Caching in TYPO3–Part 3

The Caches of TYPO3

|Benni Mack
Feature Image for Article Caching in TYPO3–Part 3

In the previous chapters of this series on TYPO3 and Caching, we've learned about the various cache mechanisms and types of caching when generating output with TYPO3. But there is more to it. As mentioned, TYPO3 does more than just cache—or partially cache—the website output. There are several caches—let's have a closer look at what caches there are, and what they do.

1. TYPO3’s Caching Framework

Back in 2011 during development of the TYPO3 v4 series, TYPO3 Core was migrated towards the so-called Caching Framework. The Caching Framework (“cf”) consists of multiple “caches”—each of which fulfils a specific purpose, and consists of a storage backend (which is where these cache entries are kept), and a frontend (determining what type of data can be put into this specific cache).

The cache backend is where cache entries are kept, and the cache frontend determines what kind of data can be put into it.

One of the main strengths of the caching framework is the possibility to use different cache backends on a per-installation basis. An example: The database backend, which keeps the cache entries in a database table, is useful if your server is also running the RDBMS on the same machine or in your container orchestration, whereas a server with a distributed database server on the network might slow things down when the database is also used as a cache. There is not a single truth to how to set up caches, but understanding the benefits or downsides to each backend type is key.

Need help tuning your website caching? Get in touch and we’ll get you sorted

Let’s connect

2. Caching basics revisited—comparing apples and oranges

To understand the basics of the caching framework and a single cache, let's take the analogy of lots of apples that are placed in a basket.

  • Cache identifier: A specific apple you can hold in your hand only exists once—so we can name this specific apple Henry. Cache tags: But there are different kinds of apples: for instance red apples, old apples or juicy apples. We can put labels on these apples to mark these characteristics.
  • Lifetime: Finally, we can put an expiration date on each, by which time they are just not relevant for us anymore (= we can’t eat them).

The “basket” is our cache, where we put all the apples. As we put them in, we give each an identifier, and—if applicable— one or more tags.

So, we have a basket full of different apples, and if we want to take one out, we'll ask only a few questions, but these are all you need for cache retrieval:

  1. “Give me the apple named Henry.”
  2. “Remove the apple named Henry.”
  3. “Empty the basket.”
  4. “Remove all juicy apples.”
  5. “Clean up—remove the expired apples from the basket.”

Along with putting apples in the basket, that's all that's needed for a cache.
So, that's one cache. If you have one basket for apples, but another one for oranges (assuming you'd never mix apples and oranges), then that's a different cache. Both of them belong to the cache group “fruits”, but there could be another group “vegetables” or something else like “cereals”. You might want to put cereals in a bowl or box instead of a basket—that's when one would carefully choose which cache backend makes most sense for your TYPO3 installation. Organizing the caches in a group allows you to empty multiple baskets at once.

3. Cache Backends

TYPO3 Core ships with most caches to be either in the file system, or the database—because that's what all TYPO3 installations have in common. But the best basket, or Cache Backend, to use depends on the server environment and how it’s set up. TYPO3 Core comes with the following Cache Backends ready to configure:

TYPO3 Database & PDO-based Database Cache Backends

This approach keeps all identifiers and the content inside a RDBMS. The TYPO3 Database Cache Backend automatically creates the database table schema for you (using the database schema comparator), and prefixes the tables with “cache_” (or “cf_cache_” until TYPO3 v9). The PDO-based Database Cache Backend can be used to put the cache in a separate database system.

Pros:

  • A good choice for caching in a regular hosting environment, when there are no specific requirements.

Ideal for debugging cached data while developing for TYPO3 Core when caching is involved (it’s my first choice).

Cons:

  • As all regular content and information is also stored in the same database, creating database backups of your TYPO3 installation might get unnecessarily large. 
  • If there is a multi-head system or a clustered RDBMS in use, a database cache might be useful as it usually is proven stable, but also increases latency.

When running into performance issues on a high-traffic site, moving the caches out of the database is usually our very first measure, as it separates concerns and frees up resources on the RDBMS.

File Backend & File Backend with Tagging Support

A simple file backend works like this: The file name is the “identifier”, and the contents of the file is the actual information to be cached. If tagging functionality is needed, a more sophisticated logic with a separate tagging control file is needed. This decreases the performance, but when running with a local SSD on the server, a file backend is often a very good choice to improve performance quickly—and also to debug cached content.

The files are usually put under var/cache/ (or in non-composer mode under typo3temp/var/cache) within TYPO3’s folder structure.

Null-Cache Backend and PHP-memory Cache Backend

These two special cache backends are not necessarily something extension developers should use, but are worth mentioning nonetheless. For the “NullCacheBackend” and the “TransientMemoryBackend” a.k.a. “Runtime Cache”, let’s take the analogy of the apple basket again. The TransientMemoryBackend just gets emptied at the end of the day, and you  start completely fresh the next day, whereas the Null Cache Backend has a hole at the bottom, so nothing is kept in a cache. 

The TransientMemory backend is used heavily in TYPO3 Core, where multiple PHP calls to the same logic is provided, and the Caching Framework is used to keep this information during one PHP request, so the single request performs better to e.g. calculate permissions of a backend user.

The Null Cache Backend, in contrast, is perfect for actually seeing how much a cache benefits, and allows you to run TYPO3 completely without any caching functionality—with just a few lines of configuration.

Memory Caches—APC/APCu, WINcache, Redis, and Memcached

In computer processing, the fastest way to access buffer / memory is the actual RAM—memory—as opposed to a hard drive / SSD / flash drive, or via the network. File and database are—ultimately—optimized caches writing data to disk, in order to allow maximum performance when putting data into, or fetching it from, the cache.

Most of the memory caches need to have PHP extensions / adapters compiled into the PHP runner, but can be added afterwards via common package managers for Linux distributions.

APC/APCu and WINcache—sharing memory between requests

PHP’s own efforts to share a certain amount of RAM between concurrent requests—APC (or APCu for “userland” cached content)—have been advancing and should be available on most PHP7+ installations. So this is a very good fit, as it is all handled by PHP internally. But it has its downsides: The APC cache provided by PHP is usually limited to a few megabytes, and has its upper limits at the gigabyte level. As the shared memory is not shared between web requests and command-line requests (as they are different PHP runners), it is technically not possible to flush the caches built by the web requests via CLI. There are workarounds to it, but the burden of doing that is more complicated than choosing an alternative in my opinion. WINcache is an alternative for Windows-based systems, which is an additional PHP module to be compiled into PHP, and has similar benefits to APCu.

memcached and Redis—key-value pair storage

A few other memory-database systems—so called “key-value stores” have evolved. They store all data primarily in memory to allow fast reading and writing from the cache. They run as separate services / daemons on the server, but are not limited to the same operating system—similar to how a MySQL database can be kept on the same server, or on a separate machine. Two of the most common systems are called “memcached” and “Redis”. Their optimized database system is perfect for memory-based caching. The amount of data to be kept in memory can be configured, and multiple baskets can be addressed as well. So the only limit really here is the RAM the service runs on.

Make your website faster with memory caches

For any medium- or large-sized TYPO3 installation, we strongly recommend using one of the two key-value stores (we at b13 prefer Redis), as we’ve seen a 30% performance increase when switching from database-based caching to Redis.

Every Cache Backend has different options that can be applied—a FileBased Cache Backend can be used to define the location of the folder where all files should be stored, and Redis cache backend needs the credentials to the service in order to work.

TYPO3 can be extended to create custom cache backends via a PHP class that implements the Cache Backend Interface.

A note on TYPO3 and PSRs: The PHP Standards Recommendation Group (PHP-FIG) published two Standards Recommendations for PHP Frameworks related to caching: PSR-6 (Cache) and PSR-16 (Simple Cache). TYPO3’s Cache Framework and its features were in place years before these standards, and although we like using standards, we’ve been reluctant to incorporate them as they either do too much (PSR-6 works on a per-object basis for cache entries) or not enough (PSR-16 does not have cache tags).

Not sure where to start? We can analyze your project, find bottlenecks, and speed up your website.

Let’s connect

4. What caches exist in TYPO3 by default?

TYPO3 has a couple of caches built-in and in use for different purposes and we’ll have a look at each of them. Some caches have been removed or renamed over the previous TYPO3 versions, but for simplicity’s sake, we’re using the cache names that are used in TYPO3 v10.

Frontend-related caches

You’ve probably seen the “Clear Frontend Caches” button in TYPO3. This flushes all entries in the following caches:

pages (Default: Database)

We’ve already looked at the cached page content and page variants in detail. The “pages” cache holds all the information for rendering a page.

pagesection (Default: Database)

The pagesection contains the TypoScript configuration from sys_template records necessary to generate a page or parts of a page. A curated form of all TypoScript / Rendering Instructions for a single page without taking the TypoScript conditions into account.

rootline (Default: Database)

TYPO3’s “Pagetree” renders the “pid” (parent page) and the “uid”—a flat table-based approach—into hierarchical tree information. The rootline cache (mainly accessed in the “RootlineUtility” API) caches information about all ancestor pages of a page. This is used for validating whether a page is allowed to be accessed, or whether it has a proper connection to the root page of a site—or even whether the current website visitor has permission to see this page (= having access to all visitors). The rootline cache also contains modifications to the rootline via MountPoints as separate entries.

A nice side-effect: When browsing through the TYPO3 Backend, this cache is also populated and used, so when a regular visitor checks out a page which the editor clicked on, the rootline has already been built.

hash / cache_hash (Default: Database)

Previously called “cache_hash”—I’d say “misc” would be the best fit for describing what TYPO3 currently puts in this cache. Let’s just call it “everything that does not really fit in the other categories”. In a regular TYPO3 installation you’ll find:

  • Cached HTML for a menu generated in the TYPO3 frontend via “HMENU” or its MenuDataProcessor decorator. (See our “menus” extension to find out why we believe HMENU is a bad design concept in conjunction with the “hash” cache).
  • TypoScript: Keeps the raw TypoScript for a page (initially as a long string) with all inclusions of all external files.
  • PageTSconfig: The “page-relevant TSconfig properties” information is also stored in a non-evaluated form (similar to the “pagesection” cache) in there.
  • UserTSconfig: Similar to PageTSconfig but related to Backend Users.
  • Single Content Parts (“.cache” stdWrap properties).
  • Marker-based templates (remember the ### in TYPO3?).

System-related caches

These caches are put in the “system” group, as they only change if the code or the configuration has been changed. Flushing the system group (“Clear all caches” empties all caches of the system group as well) should only be done on production sites after installing an extension or carrying out a deployment.

Most of the caches are configured to be put on file system level by default. This is perfect for most use cases, except when TYPO3’s data is put on a NFS (Network File Share) system, where heavy access to the file system might slow down the system drastically.

assets (Simple File Backend)

Any type of icon used in TYPO3 Backend, and used for the Icon API, is stored in the “assets” cache. In addition, TYPO3’s RequireJS configuration in TYPO3 Backend is also kept in the assets cache.

l10n (Simple File Backend)

TYPO3’s multi-language capabilities are not only bound to the actual content, but also to the system labels—both for the website (like validation messages in a form) and all of TYPO3’s Backend interface. All labels are stored in various XLIFF files—which need to be parsed (it’s XML). This work does not need to be done over and over again, so it’s put in a cache.

fluid_template (custom FluidTemplateCache)

Fluid’s templating engine generates PHP code out of templates—The fluid_template cache is TYPO3’s backend to store the PHP code, so template parsing is only done once.

extbase (SimpleFileBackend)

Extbase—TYPO3’s primary MVC framework for plugins—works exclusively with PHP objects and analyzes PHP classes for framework-specific functionality like PHPdoc annotations or dependency injections, or for its ORM capabilities. As PHP classes don’t change, except during development or after a deployment, this PHP-related information is cached.

core (SimpleFileBackend)

While booting up, TYPO3 compiles a list of all extensions, and the places where extensions modify core functionality—either through “ext_localconf.php” files, custom TCA configuration, PSR-15 Middlewares or additional backend routes. This information is all stored in the Core Cache. Be aware that this cache cannot be configured to be stored in e.g. the database—as this is a classic chicken egg situation: One cannot cache something if we don’t yet know which basket to cache it in. So Core Cache is always in the file system for now.

Since TYPO3 v10 we also have a “di” (Dependency Injection) cache, which can only be flushed via the Install Tool / Maintenance Area. This contains information about available services and PHP classes. As you can imagine, this only changes if you run a deployment, or activate an extension, so this will not change, and only seldomly needs to be flushed—mostly relevant for PHP developers. This cache also cannot be “reconfigured” during runtime, as this cache is static and already built / finished at runtime.

Other available caches

imagesizes

When using images on a website, the actual imagesize is found out by API and/or asking the file system for the width and height of an image to be rendered. TYPO3’s FAL API keeps track of this metadata already—also for processed images, but when displaying resized images or dynamically generating images through TYPO3’s GIFBUILDER capability, this information is cached to avoid unneeded file system checks.

This cache is put in the “lowlevel” group, which does not need to be flushed at all, as the size of a dynamically generated image does not change.

runtime

This cache only lives in PHP’s memory for the current request. Once the response has been sent to the browser, the PHP request is finished, and all memory is freed up. Sometimes referred to as a “first-level cache”, where information is stored in memory instead of fetching the same information multiple times from the database. 

For the sake of completeness, the following Core-maintained extensions also create additional caches when they are installed.

  • Admin Panel—adminpanel_requestcache
  • Workspaces—workspaces_cache

5. How to configure the caches?

Now you know everything—time to play around with it:

Site owners—the main thing that is of interest for you is to re-configure an existing cache. This can be done in your system configuration in typo3conf/LocalConfiguration.php or typo3conf/AdditionalConfiguration.php.

Modifying the pages cache to be put in a file system looks like this in your AdditionalConfiguration.

1
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['pages']['backend'] = \TYPO3\CMS\Core\Cache\Backend\FileBackend::class;

Changing all page-related caches to use Redis looks likes this—this is actually how we do it in some of our projects:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$redisHost = '127.0.0.1';
$redisPort = 6379;
$cachesForRedis = [
    'pages' => 86400*30,
    'pagesection' => 86400*30,
    'hash' => 86400*30,
    'rootline' => 86400*30,
];
$redisDatabaseNumber = 0;
foreach ($cachesForRedis as $cacheName => $lifetime) {
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheName]['backend'] = \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class;
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheName]['options'] = [
        'database' => $redisDatabaseNumber++,
        'hostname' => $redisHost,
        'port' => $redisPort,
        'defaultLifetime' => $lifetime
    ];
}

Extension owners’ main question is how to create a new cache for your extension. Put this in the Configuration/Services.yaml file of your extension:

Put this in the Configuration/Services.yaml file of your extension:

1
2
3
4
5
6
7
8
9
10
services:
_defaults:
autowire: true
autoconfigure: true
public: false

cache.mycache:
class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache']
arguments: ['mycache']

As you see, a lot of things get cached in different places—we’re not going to put oranges and apples in the same basket. Watch out for the next part in our caching series about where you can find caches that matter to you outside of TYPO3.

If you want some advice on how to choose the best cache configurations for your setup, reach out to us. We at b13 love fast websites and feel TYPO3 is the right fit to keep your website running at top speed.

Do you need expert help to speed up your website? Get in touch to talk about your needs

Let’s connect