Magento Block HTML & Full Page Caching
This document describes briefly how Magento uses caching, in particular for the view layer.
Other documents will relate to this content when describing Hyvä specific caching features.
Background
Magento uses several layers of caching:
-
Low level caching of configuration, layout XM, table data etc.
This usually happens in a Redis like system or the file system. -
FPC (Full Page Caching)
In production this usually is done by a reverse proxy like Varnish, but it is also possible to use Redis or the file system on development systems. -
ESI caching
The acronym stands for Edge Side Includes. It is only available if a Varnish compatible full page cache is used. -
Browser caching
The visitors' browser stores content in the local HTTP cache, browser storage and cookies.
This includes JavaScript files and templates, Customer Section Data, the Session ID and the selected store view.
These interacting levels of caching often lead to interesting and hard to reproduce bugs.
Cache Invalidation
When some event changes data, the relevant caches should automatically remove any references to the old version of the data.
Cache records can be deleted either by Cache ID (also called Cache Key), or - more commonly - by Cache Tags.
"Cache Tags" are used to group together multiple cache records. A cache record is associated with zero or more cache tags.
For example, every cache record containing data from a product with the ID 123 is associated with the cache tag p_123
.
When product 123 is edited, Magento dispatches the command to delete any cache record on any level associated with that cache tag.
Because of the distributed nature of the cache backends used for the different levels of caching, this command needs to be processed differently depending on the cache backend:
-
The low level cache is the simplest case.
Cache tags are stored in some kind of (backend dependent) index, pointing to the associated records.
During removal, any cache records related to the given tags are deleted in the same PHP process where the cache clean command is sent. -
The Full Page cache handling depends on which backend is used.
For the built-in FPC backend (i.e. Redis or the file system), the records are associated with cache tags by setting theX-Magento-Tags
HTTP response header to a comma separated list of cache tags. The records are cleaned in-process, just like low level records.
For Varnish like FPC backends, the cache tags a record is associated with are specified via aX-Magento-Tags
HTTP header. The value is a comma separated list of cache tags.
During removal, a HTTP PURGE request is sent by Magento, with anX-Magento-Tags-Pattern
HTTP header. The header value is a regular expression matching the desiredX-Magento-Tags
header values. Varnish then evicts any cache records with cache tags matching the pattern. -
ESI cache records are handled via HTTP headers just like Varnish above, since they are stored in the same way.
-
The handling browser caching depends on the type of storage.
Cookies are deleted server side by setting the value tonull
and/or setting an expiry date in the past.
Local storage is forced to refresh by updating the value of the cookieprivate_content_version
.
JavaScript and Translation files are forced to refresh by changing the value of a virtual directory in the request path to the files.
Note that besides the in addition to the cache tags based cleaning system described above, most cache records on all cache layers also have an expiry time, after which the storage will automatically discard them.
Associating cache tags with cache records
Note
This section will focus on the frontend development related cache records and ignore low level caching, for example, the config cache.
- HTML Block cache records
- FPC records
- ESI records
Block HTML Cache
Usually the blocks rendering a template are responsible for providing the relevant cache tags.
This is done through the method Magento\Framework\View\Element\AbstractBlock::getCacheTags
.
The method returns an array of strings, each one being a cache tag. It is sometimes overridden in subclasses to provide additional cache tags.
It is also possible to set the cache tags on a block by calling setCacheTags($tagsArray)
before the block is rendered.
This system works quite well. It was made a bit more complicated when Magento decided to discourage creating custom block classes, and instead use the standard template block, because it isn’t possible to override the method without using inheritance.
According to Magento, view models should be used instead to provide data to render. There is no standard Magento API for view models to add cache tags on the block that is being rendered, but usually it is possible to somehow set the cache tags for a block using setCacheTags($tags)
, either in the parent template or through a custom view model method.
This is one of the reasons why the Magento core only makes very limited use of the Block HTML cache. Instead, the core favors using the FPC cache.
Full Page Cache & ESI Cache
The cache tags that are to be included in a X-Magento-Tags
HTTP response header are the responsibility of blocks.
However, the getCacheTags
method which is used for the block HTML cache is not used for the FPC. Instead, the block classes need to implement the interface Magento\Framework\DataObject\IdentityInterface
.
This interface has one method, getIdentities()
, which returns an array of strings (each one a cache tag).
All “identities” of the blocks rendered on a page are combined in the X-Magento-Tags
response header.
Because the IdentityInterface
needs to be implemented by the block, there is no way to add tags to a response using a standard Template
block instance.
This is maybe an oversight of the Magento core team when starting to discourage the use of custom blocks in favor of PHP view models.
There is no API for view models to add cache tags to a response.
The next document will describe Hyvä’s solution to this issue.
Note
For completeness, besides grouping of cache records by cache tags for eviction, the FPC also allows further segmenting of cached versions of URLs.
This full page cache segmentation is out of scope of this document. More information can be found in this blog post.