Cache-tags
Cache-tags = gegevensafhankelijkheden
Cache-tags beschrijven afhankelijkheden van gegevens die door Drupal worden beheerd
Waarom?
Cache-tags bieden een declaratieve manier om bij te houden welke cache-items afhankelijk zijn van bepaalde gegevens die door Drupal worden beheerd.
Dit is belangrijk voor een CMS/Framework zoals Drupal, omdat dezelfde inhoud op verschillende manieren kan worden hergebruikt. Met andere woorden: het is onmogelijk om van tevoren te weten waar inhoud zal worden gebruikt. Overal waar inhoud wordt gebruikt, kan het worden gecachet. Dat betekent dat dezelfde inhoud op tientallen plaatsen in de cache kan belanden. Wat ons brengt bij het bekende citaat. In de informatica zijn er maar twee moeilijke problemen: cache-invalidatie en naamgeving. – ofwel: hoe ga je alle cache-items ongeldig maken waar de inhoud in voorkomt?
Opmerking: Drupal 7 bood 3 manieren om cache-items ongeldig te maken: een specifieke CID ongeldig maken, ongeldig maken met een CID-prefix of alles ongeldig maken in een cache-bin. Geen van deze drie methoden stelde ons in staat om cache-items ongeldig te maken die een gewijzigde entiteit bevatten, omdat dit simpelweg niet te achterhalen was!
Wat?
Een cache-tag is een string.
Cache-tags worden doorgegeven in sets (de volgorde maakt niet uit) van strings, dus ze worden weergegeven in string[]. Het zijn sets, omdat één cache-item afhankelijk kan zijn van meerdere cache-tags.
Syntaxis
Volgens conventie hebben ze de vorm ding:identifier – en wanneer er geen concept van meerdere instanties van het ding is, hebben ze de vorm ding. De enige regel is dat ze geen spaties mogen bevatten.
Er is geen strikte syntaxis.
Voorbeelden:
- node:5 – de cache-tag voor Node 5 (wordt ongeldig telkens wanneer die node wijzigt)
- user:3 – de cache-tag voor gebruiker 3 (wordt ongeldig telkens wanneer die gebruiker wijzigt)
- node_list – cache-tag voor een lijst van Nodes (wordt ongeldig telkens wanneer er een Node wordt aangemaakt, bijgewerkt of verwijderd, m.a.w. telkens wanneer een nodelijst moet veranderen). Dit geldt voor elk entiteitstype in de vorm: {entity_type}_list.
- config:system.performance – cache-tag voor de configuratie system.performance
- library_info – cache-tag voor asset libraries
Algemene cache-tags
Door Drupal beheerde gegevens vallen in 3 categorieën:
- entiteiten – hebben cache-tags in de vorm <entity type ID>:<entity ID>, plus <entity type ID>_list en <entity type ID>_list:<bundle> voor het ongeldig maken van entiteitslijsten. Configuratie-entiteiten gebruiken de cache-tag van het onderliggende configuratie-object.
- configuratie – hebben cache-tags in de vorm config:<configuration name>
- custom – bijvoorbeeld library_info
Drupal voorziet automatisch in cache-tags voor entiteiten en configuratie – zie de Entity basisklasse en de ConfigBase basisklasse. (Alle specifieke entiteitstypes en configuratieobjecten erven daarvan.)
Hoewel veel objecttypes voorspelbare cache-tags hebben (<entity type ID>:<entity ID>), zou third-party code hier niet blind op mogen vertrouwen. In plaats daarvan moet je de cache-tags voor een object ophalen met de methode ::getCacheTags(), bijvoorbeeld $node->getCacheTags(), $user->getCacheTags(), $view->getCacheTags() enz.
Daarnaast kan het nodig zijn caches ongeldig te maken op basis van lijsten die afhankelijk zijn van een entiteit (bijvoorbeeld om een listing bij te werken als er een nieuwe entiteit verschijnt): dit kan met EntityTypeInterface::getListCacheTags(), naast de eigen cache-tags van het object. Vanaf Drupal 8.9 (change record) hebben entiteiten met bundles ook automatisch meer specifieke cache-tags met hun bundle.
Het is ook mogelijk om custom, specifiekere cache-tags te definiëren, gebaseerd op objectwaarden, bv. een term reference veld voor lijsten die alle nodes met een bepaalde term tonen. Ongeldig maken voor zulke tags kan in hook_node_presave()/hook_node_delete:
function yourmodule_node_presave(NodeInterface $node) {
$tags = [];
if ($node->hasField('field_category')) {
foreach ($node->get('field_category') as $item) {
$tags[] = 'mysite:node:category:' . $item->target_id;
}
}
if ($tags) {
Cache::invalidateTags($tags);
}
}
Deze tags kunnen in code en in Views gebruikt worden met behulp van de module Views Custom Cache Tag.
Hoe
Instellen
Elke cache-backend moet CacheBackendInterface implementeren, dus wanneer je een item opslaat met ::set(), specificeer je de derde en vierde argumenten, bijvoorbeeld:
$cache_backend->set( $cid, $data, Cache::PERMANENT, ['node:5', 'user:7'] );
Dit slaat een cache-item met ID $cid permanent op, maar maakt het ongeldig zodra cache-tags node:5 of user:7 ongeldig worden verklaard.
Ongeldig maken
Cache-items kunnen ongeldig gemaakt worden via hun cache-tags met cache_tags.invalidator:invalidateTags() (of Cache::invalidateTags() als service injection niet kan). Dit accepteert een set cache-tags (string[]).
Opmerking: dit maakt items ongeldig in alle cache-bins, niet enkel in één, omdat dezelfde data meerdere caches kan beïnvloeden.
Debugging
Als iets gecachet is met tags ['foo', 'bar'], dan zal de cache-tabel (bv. database backend) een kolom hebben:
bar foo
- Cache-tags zijn gescheiden door spaties
- Cache-tags worden alfabetisch gesorteerd
Dat maakt het makkelijker om caches te analyseren en debuggen.
Headers (debugging)
Tot slot: je kan altijd in de HTTP-response kijken naar de header X-Drupal-Cache-Tags om te zien van welke cache-tags een response afhankelijk is!
(Daarom zijn spaties verboden: de header gebruikt spaties als scheiding.)
Opmerking: als je deze headers niet ziet, configureer je Drupal voor ontwikkeling.
Integratie met reverse proxies
In plaats van caches in Drupal op te slaan en via cache-tags ongeldig te maken, kan je ook caches opslaan in reverse proxies (Varnish, CDN’s …) en die ongeldig maken via dezelfde cache-tags. Drupal kan die tags meegeven in response headers.
Drupal 8 kan net zoals X-Drupal-Cache-Tags ook een Surrogate-Keys header sturen (spatiegescheiden waarden, zoals sommige CDN’s verwachten) of een Cache-Tag header (komma-gescheiden waarden, zoals andere CDN’s verwachten). Dit werkt zowel met eigen reverse proxies als met commerciële CDN’s.
Aanbevolen is dat zowel je webserver als reverse proxy response headers tot 16 KB ondersteunen.
- HTTP is tekst-gebaseerd. Cache-tags dus ook. Reverse proxies kunnen dit intern opslaan in andere structuren. 16 KB limiet werd gekozen om praktisch compatibel te zijn en breed ondersteund (Apache, CDN’s zoals Fastly).
- Gemiddeld zijn het zo’n ~1000 cache-tags per response, voldoende voor 99% van de gevallen.
- Meer dan 1000 tags duidt waarschijnlijk op een te complexe response die beter opgesplitst wordt. Drupal laat het technisch toe, maar het vereist mogelijk extra configuratie.
Lees de documentatie over het gebruik van Varnish met cache-tags.
CDN’s met ondersteuning voor cache-tag invalidatie:
CloudFlare
Fastly
KeyCDN
Akamai
Interne page cache
Het uitgebreide gebruik van cache-tags in Drupal 8 maakt het mogelijk dat Drupal 8 standaard geleverd wordt met de interne page cache ingeschakeld. Dit is in feite een ingebouwde reverse proxy.