Drupal 10: Cache API

Drupal 10: Cache API

Cache is a crucial component of any website, serving users faster and efficiently managing resource utilization. There are two types of traffic that any website can receive: Authenticated users and anonymous users. For anonymous users, pages remain unchanged, allowing them to load without variation. However, pages for authenticated users are dynamic and unique per user.

Drupal cache has undergone significant advancements compared to Drupal 6 and 7. It has come a long way, enabling dynamic caching for authenticated users, region-based caching, language-based caching, and placeholders for dynamic content.

At the Drupal level, caching is managed by two core modules:

  1. Internal Page Cache: This module, enabled by default, caches pages for anonymous users and serves as a fallback when an external page cache is unavailable.
  2. Internal Dynamic Page Cache: This module caches pages, including those with dynamic content, for all users. When pages are initially requested by users (whether anonymous or authenticated), they are stored and can be reused. However, personalized parts are excluded and replaced with placeholders. This module requires no additional configurations as it utilizes metadata (Cache Context) of all components on a page to determine if caching is possible.

By default, Drupal stores cache in the database. This is the default cache mechanism provided by Drupal out of the box.

One question that arises is how the cache system knows when content has changed and needs to be updated with the latest changes. Drupal handles this automatically for core systems:

  • If any entities change, Drupal signals it via Cache Tags.
  • If content is updated based on conditions, Drupal signals it via Cache Context.
  • If Drupal needs to update any content after a certain amount of time, it signals it via Cache Max-age.

While Drupal manages these aspects out of the box for core systems, when writing custom code, it's essential to ensure that the content passed via your code is updated and invalidated as necessary.

Let's consider a small example to illustrate this concept.

If you're creating a custom block or a controller and passing data to a render array through it, you also need to specify when this content needs to be revalidated. How do you do that? You can achieve this by populating the "#cache" key in render arrays.

For instance, suppose you create a custom block that displays the current user's name and your site's name. Your block would return the following render array:

$render_array = [
      '#markup' => t('Hi, %name welcome back to @site', [
        '%name' => $current_user-getUserName();
        '@site' => $config->get('name');
      ]),
    ];        

The above block is only cacheable per user since it displays the user's name. Here, we need to add Cache Context (condition), so our above render array will be modified as follows:

 $render_array = [
      '#markup' => t('Hi, %name welcome back to @site', [
        '%name' => $current_user-getUserName();
        '@site' => $config->get('name');
      ]),
      "#cache" => [
        'contexts' => ['user'],
      ],
    ];        

Now, consider what will happen if you change the name of your site. In the above render array, we need to add a dependency for site configuration. As soon as it changes, the cache should be invalidated, ensuring that the block displays the latest updated site name.

$renderer->addCacheableDependecy($render_array, $config);        

Similarly, the same principle applies to the user name. If a user changes their name, it should also reflect the updated user name. Therefore, we need to add a dependency on the current user.

$renderer->addCacheableDependecy($render_array, $current_user);        

So, to invalidate the cache using a render array, you could add a cache key. Additionally, you could further add context, tags, or a maximum age, or all three. All these mechanisms will work simultaneously.

For example, if you set a max-age of 1 hour and a cache tag as 'node:5', then in practice, Drupal will check the status of 'node:5'. If it hasn't been updated, Drupal will then check if the content has crossed the maximum age (time to live) of 1 hour. If either condition is true, it will invalidate the cache and fetch new or updated content.

Cache tag bubbling:

  • Drupal keeps track of which entities have cache tags.
  • As cached elements are encapsulated inside other elements, the containing item inherits the cache tags of its content.
  • Cache tags bubble up to parent/ancestor cache items.
  • Page records cache tags from every embedded element.
  • This allows Drupal to "Surgically" clear cache on pages/content/etc featuring specific cache tags.

Markup should generally be passed to the theme layer via render arrays. Cacheability details are added to the render array. We set: cache tags, cache context, and cache max-age.

Examples of cache tags:

  • 'node: article': Clear item if the article content type has been changed (e.g., if a new field is inserted in the content type).
  • 'node: 1': Clear item if the node with ID 1 has been changed.
  • 'node_list': Clear item if any node is updated.

Let’s see some more examples of setting cache information:

pubic function build(){
    return [
      '#markup' => some_fucntion_returns_markup(),
      '#cache' => [
        'tags' => ['node_list'], // Invalidate this block when any node updates
        'context' => ['user']. // New cache item per individual user
        'max-age' => \Drupal\Core\Cache\Cache::PERMANENT,
        // More Example......
        // 'tags' => ['node:1', 'term:2'], // invalidate this block if node 1 or term 2 updates
        // 'max-age' => 60, // Cache expires after 60 seconds
        // 'max-age' => 0 // Cache for 0 seconds, i.e never cached
      ],
    ]
  }        

Where is the Cache Saved?

By default, cache is saved in the database, and core cache modules are enabled by default. Other options to store cache include:

  • CDN
  • Varnish
  • Memcache
  • Opcache
  • Queries
  • Database

Once your site is set up, there are many layers of caching. The database stores Drupal's cache and cache for database queries. Opcache or APC cache the actual PHP code.

  • Opcache: Caches the binary code of PHP files, skipping the first step of turning PHP files into binary code when interpreted by the server.
  • Memcache: Caches PHP objects from your website in your server's RAM.
  • Varnish: Caches whole pages, making page loading very fast, especially for anonymous traffic.

For Varnish:

  • Install the 'purge' and 'purge_varnish' modules and perform some configurations.
  • Configure Varnish on the same server as your site, usually on port 80.

Content Delivery Network (CDN) can also cache whole pages:

  • Ensures fast load times regardless of geographic locations.
  • Acts as a shield against DDOS attacks.

In summary, serving requests from cache appears as follows:

I hope this article provides a brief overview of caching and how it operates in Drupal. Much of the content is derived from the following YouTube video, which you can also reference for further understanding:

YouTube Video: Caching in Drupal

Additionally, caching is extensively covered on Drupalize.me.

要查看或添加评论,请登录

Pankaj Raundal的更多文章

社区洞察

其他会员也浏览了