キャッシュタグ
Cache tags = データの依存関係
Cache tagsは、Drupalによって管理されるデータへの依存関係を記述します
なぜ?
キャッシュタグは、どのキャッシュアイテムがDrupalによって管理される特定のデータに依存するかを追跡するための宣言的な方法を提供します。
これは、DrupalのようなCMS/フレームワークにとって重要です。同じコンテンツがさまざまな方法で再利用される可能性があるためです。言い換えれば:コンテンツがどこで使用されるかを事前に知ることは不可能です。コンテンツが使用される場所ではどこでも、キャッシュされる可能性があります。つまり、同じコンテンツが数十の場所でキャッシュされる可能性があります。そして、これが有名な引用につながります。コンピューター科学には、キャッシュの無効化と名前の割り当てという2つの難しい問題しかありません。つまり、コンテンツが使用されているすべてのキャッシュアイテムをどのように無効化するのか、ということです。
注記:Drupal 7では、キャッシュアイテムを無効化する3つの方法が提供されていました:特定のCIDを無効化する、CIDプレフィックスを無効化する、またはキャッシュバケット内のすべてを無効化する。これらの3つの方法のいずれも、変更されたエンティティを含むキャッシュアイテムを無効化することはできません。それを知る方法がなかったからです!
どのようなものか?
キャッシュタグは文字列です。
キャッシュタグは文字列のセット(順序は関係ありません)として渡されるため、string[]として出力されます。セットであるのは、1つのキャッシュアイテムが多くのキャッシュタグに依存する可能性があるためです。
構文
慣例により、それらはthing:identifierの形式を持ち、物の複数のインスタンスの概念がない場合はthingの形式になります。唯一のルールは、スペースを含めることができないことです。
厳密な構文はありません。
例:
- node:5 - ノード5のキャッシュタグ(変更されるたびに無効化されます)
- user:3 - ユーザー3のキャッシュタグ(変更されるたびに無効になります)
- node_list - ノードのキャッシュタグリスト(任意のノードが更新、削除、または作成されるたびに無効化されます。つまり、ノードリストの変更が必要になる場合)。任意のエンティティタイプに次の形式で適用されます:{entity_type}_list。
- config:system.performance - system.performance設定のキャッシュタグ
- library_info - アセットライブラリのキャッシュタグ
一般的なキャッシュタグ
Drupalによって管理されるデータは、3つのカテゴリに分けられます:
- エンティティ - キャッシュタグの形式は<エンティティタイプID>:<エンティティID>であり、エンティティリストを無効化するための<エンティティタイプID>_listおよび<エンティティタイプID>_list:<バンドル>もあります。設定エンティティタイプは、基本設定エンティティのキャッシュタグを使用します。
- 設定 - キャッシュタグの形式はconfig:<設定名>
- カスタム「custom」(たとえば、library_info)
Drupalはエンティティと設定のキャッシュタグを自動的に提供します - Entity基本クラスとConfigBase基本クラスを参照してください。(すべての具体的なエンティティタイプと設定エンティティはそれらを継承します。)
多くのエンティティタイプが予測可能な<エンティティタイプID>:<エンティティID>形式のキャッシュタグに従っていますが、サードパーティのコードはこれに依存すべきではありません。代わりに、::getCacheTags()メソッドを使用して単一エンティティの無効化用キャッシュタグを取得する必要があります。たとえば、$node->getCacheTags()、$user->getCacheTags()、$view->getCacheTags()などです。
さらに、対象のエンティティのデータに依存するリストベースのキャッシュを無効化する必要がある場合があります(たとえば、新しいエンティティが作成されたときにリストのレンダリングされたHTMLを更新するなど)。これはEntityTypeInterface::getListCacheTags()を使用して行うことができます。その後、そのメソッドによって返されたタグを、エンティティ自体のタグと一緒に無効化します。Drupal 8.9以降(変更レコード)、バンドルを持つエンティティには、バンドルを含むより具体的なキャッシュタグも自動的に設定され、リストのより的を絞った無効化が可能になります。
エンティティが持つ値に基づいて、カスタムのより具体的なキャッシュタグを定義することも可能です。たとえば、特定のタームを持つエンティティを表示するリストのためのターム参照フィールドなどです。そのようなタグの無効化は、カスタムのエンティティプリセーブ/削除フックに配置できます:
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);
}
}
これらのタグは、提供されているViews Custom Cache Tagモジュールを使用して、コード内およびビューで使用できます。
注記。現在、エンティティまたは別のオブジェクトから個々のバンドルおよびより具体的なキャッシュタグを取得するAPIはありません。これは、特定のリスト/クエリに対してどのリストキャッシュタグが関連するかを決定するのがオブジェクトではなく、クエリ自体に依存するためです。Drupalコアの将来のバージョンでは、バンドルごとのキャッシュタグの組み込みサポートが改善され、たとえばエンティティクエリビルダーやビューに統合される可能性があります。
方法
設定
すべてのキャッシュバックエンドはCacheBackendInterfaceを実装する必要があります。したがって、::set()メソッドを使用してキャッシュアイテムを設定するときは、3番目と4番目の引数を指定します。例:
$cache_backend->set(
$cid, $data, Cache::PERMANENT, ['node:5', 'user:7']
);
これにより、$cidのキャッシュアイテムが永続的に保存されます(つまり、無期限に保存されます)が、node:5またはuser:7キャッシュタグによる無効化の対象になります。
無効化
タグ付きキャッシュアイテムは、cache_tags.invalidator:invalidateTags()を使用してタグを介して無効化されます(または、cache_tags.invalidatorサービスを注入できない場合は:Cache::invalidateTags())。これはキャッシュタグのセット(string[])を受け取ります。
注記:これは、指定されたタグが付けられたアイテムをすべてのキャッシュバケットで無効にします。これは、キャッシュタグを個々のバケットで無効化することは意味をなさないためです。キャッシュタグが無効化される変更されたデータは、他のキャッシュバケット内のキャッシュアイテムに依存する可能性があるためです。
デバッグ
上記はすべて、キャッシュされるものをデバッグする際の有用な情報です。ただし、もう1つあります:何かがキャッシュタグ['foo', 'bar']でキャッシュされているとします。対応するキャッシュアイテムには、次の値のタグ列があります(一時的にデータベースキャッシュを想定):
bar foo
つまり:
- キャッシュタグはスペースで区切られます
- キャッシュタグはアルファベット順にソートされます
これにより、キャッシュの分析とデバッグが容易になるはずです!
ヘッダー(デバッグ)
最後に:特定のレスポンスがどのキャッシュタグに依存しているか(つまり、何によって無効になるか)を確認するのは簡単です:X-Drupal-Cache-Tagsヘッダーを見るだけで十分です!
(スペースが禁止されているのはそのためです:X-Drupal-Cache-Tagsヘッダーは、他の多くのHTTPヘッダーと同様に、値を区切るためにスペースを使用するからです。)
注記。これらのヘッダーが表示されない場合は、開発用にDrupalインスタンスを設定する必要があります。
リバースプロキシとの統合
Drupalでレスポンスをキャッシュし、キャッシュタグで無効化する代わりに、リバースプロキシ(Varnish、CDN ...)でレスポンスをキャッシュし、それらのレスポンスに関連付けられたキャッシュタグを使用して、プロキシがキャッシュしたレスポンスを無効化することもできます。これらのリバースプロキシが各レスポンスに関連付けられているキャッシュタグを認識できるようにするには、キャッシュタグをヘッダーと一緒に送信できます。
Drupal 8がデバッグ用にX-Drupal-Cache-Tagsヘッダーを送信できるのと同じように、一部のCDNが期待するスペース区切りの値を含むSurrogate-Keysヘッダーや、他のCDNが期待するカンマ区切りの値を含むCache-Tagヘッダーも送信できます。また、商用CDNサービスではなく、自分で実行するリバースプロキシサーバーでも構いません。
一般的に、Webサーバーとリバースプロキシサーバーの両方が、最大16 KBの値を持つレスポンスヘッダーをサポートすることをお勧めします。
1. HTTPはテキストベースです。したがって、キャッシュタグもテキストベースです。リバースプロキシは、キャッシュタグを別のデータ構造内で自由に表現できます。16 KBのレスポンスヘッダー値の制限は、A)99%のケースで機能することを確認するため、B)実際に達成可能であるためという2つの要因に基づいて選択されました。一般的なWebサーバー(Apache)と一般的なCDN(Fastly)は、16 KBのレスポンスヘッダー値をサポートしています。これは約1000個のキャッシュタグを意味し、99%のケースに十分です。
2. キャッシュタグの数は、サイトと特定のレスポンスによって大きく異なります。多くの他のものに依存するレスポンスの場合、キャッシュタグは多数になります。レスポンス内に1000を超えるキャッシュタグが存在することはまれです。
3. ただし、もちろん、このガイドライン(レスポンスあたり約1000タグで十分)は、A)より多くの実際のアプリケーションがこの機能を使用するのを見て、B)システムがこの機能を特別に使用/構築しているのを見るにつれて、時間の経過とともに変化する可能性があり、また変化するでしょう。
最後に、1000個を超えるキャッシュタグは、より深い問題を示している可能性があります:レスポンスが複雑すぎて分割すべきだということです。Drupalでこの数を超えることを妨げるものは何もありませんが、手動設定が必要になる場合があります。これは、そのような非常に複雑なユースケースでは許容されます。おそらく、1000個のキャッシュタグよりはるかに少ない数でも当てはまる可能性があります。
キャッシュタグでVarnishを使用するに関するドキュメントをお読みください。
タグベースの無効化/パージをサポートすることが知られているCDN:
CloudFlare
Fastly
KeyCDN
Akamai
内部ページキャッシュ
Drupal 8でのキャッシュタグの包括的な使用により、Drupal 8にはデフォルトで有効な内部ページキャッシュが付属しています。これは組み込みのリバースプロキシに他なりません。