キャッシュ入門
- ウェブキャッシュとは、ウェブサーバーとクライアントの間に存在するウェブリソースのコピーです。
- キャッシングはパフォーマンス最適化の一形態と考えることができ、サーバーへのリクエストを開始する際、優れたキャッシング戦略はサーバーに送信されるリクエストの数を減らし、サーバーのストレスを軽減し、帯域幅を削減し、ローカルにキャッシュされたファイルを再利用し、ユーザーエクスペリエンスを向上させるのに役立ちます。
キャッシュの場所による分類
サービス・ワーカー
メモリキャッシュ
ディスクキャッシュ
上から下への優先クエリは、すべてのキャッシュの場所が見つからない場合は、再ネットワークリクエストを開始します。フロントエンドは主にブラウザと密接にリンクされているため、ブラウザのキャッシュ階層の主な研究
サービス・ワーカー
Service Workerはブラウザの背後で実行される独立したスレッドで、キャッシュ機能を実装するために使用できます。Service Workerを使用する場合、トランスポートプロトコルはHTTPSでなければなりません。また、Service Workerはリクエストの傍受を伴うため、セキュリティのためにHTTPSプロトコルを使用する必要があります。Service Workerのキャッシュは、どのファイルをキャッシュするか、どのようにキャッシュにマッチさせるか、どのように読み取るかを自由に制御できるという点で、ブラウザに組み込まれている他のキャッシュ機構とは異なります。どのファイルがキャッシュされるか、キャッシュがどのようにマッチングされるか、キャッシュがどのように読み込まれるか、キャッシュが永続的であるかを制御することができます。
上記のキャッシングポリシーや、キャッシング/読み込み/無効化の動作は、すべてブラウザが内部で判断&実行するもので、ブラウザに伝えるにはレスポンスヘッダに特定のフィールドを設定するだけで、自分ではできません。例えば、銀行に行ってお金を預ける/引き出す場合、銀行員に「いくら預けたい/引き出したい」と伝えるだけで、銀行員は一連の記録や手続きを経て、お金を金庫に入れたり、金庫からお金を取り出して渡してくれたりします。
しかし、サービス・ワーカーの出現により、より柔軟で直接的な操作方法が生まれました。お金を預けたり引き出したりすることを例にとると、銀行員をバイパスして金庫室まで行き、自分でお金を入れたり出したりすることが可能になりました。つまり、どのお金を入れるか、何を出すか、どれを取り出すかを自分で選ぶことができるのです。もちろん、現実には銀行はそのようなサービスをオープンにしていません。
Service Workerが操作できるキャッシュは、ブラウザ内のメモリキャッシュやディスクキャッシュとは異なります。この別の「キャッシュ」は、ChromeのF12、アプリケーション -> キャッシュストレージで見つけることができます。別の場所にあることに加え、このキャッシュは永続的です。つまり、TABやブラウザを閉じても、次に開いたときにはキャッシュが残っています。 cache.delete(resource)
このキャッシュがクリアされる可能性があるシナリオは2つあります:APIを手動で呼び出した場合、またはキャッシュが容量を超え、ブラウザによって完全に空にされた場合です。
サービスワーカーがキャッシュをヒットできなかった場合、通常は fetch() メソッドを使ってリソースの取得を続けます。その時点で、ブラウザは次のキャッシュハントのためにメモリキャッシュまたはディスクキャッシュに移動します。注意: サービスワーカーの fetch() メソッドによってフェッチされたリソースは、それがサービスワーカーのキャッシュにヒットしなかったとしても、また実際にネットワークリクエストであったとしても、ServiceWorker からのものとしてマークされます。
メモリキャッシュ
メモリキャッシュとは、主に現在のページに取り込まれているスタイル、スクリプト、イメージなど、ページ上でダウンロードされたリソースをメモリ上にキャッシュしたものです。メモリ内データの読み込みはディスク上よりも断然速く、メモリ内キャッシュは読み込み効率は良いですが、短命であり、処理が終わると解放されます。 タブ・ページが閉じられると、メモリ内キャッシュは解放されます。
** インメモリーキャッシュはとても効率的なので、すべてのデータをメモリーに保存することは可能ではないですか?** これは不可能です。コンピュータに搭載されるメモリはハードディスクの容量よりもはるかに小さくなければなりませんし、オペレーティングシステムはメモリの使用量に注意する必要がありますから、どうしても多くのメモリを使わせることはできません。
ページがアクセスされ、再びリフレッシュされると、多くのデータがメモリキャッシュからもたらされていることがわかります。
メモリキャッシュの重要な部分は、プリローダーディレクティブによってダウンロードされるリソースです。preloader ディレクティブは、ネットワークから次のリソースを要求する間に js/css ファイルを解析することで、ページを最適化する最も一般的な方法の一つとして知られています。
また、リソースのマッチングは URL だけでなく、Content-Type や CORS などの他の機能についても行われます。
ディスクキャッシュ
ディスクキャッシュは、ハードドライブに保存されているキャッシュとしても知られており、読み取り速度は遅くなりますが、すべてをディスクに保存することができ、メモリキャッシュよりも容量とストレージの適時性で勝っています。
ディスクキャッシュは、基本的にすべてのブラウザのキャッシュの中で最も広い範囲をカバーしています。どのリソースをキャッシュする必要があるのか、どのリソースをリクエストせずに直接使用できるのか、どのリソースが期限切れで再リクエストが必要なのかを、HTTP Herderのフィールドに基づいて判断します。また、クロスサイトの場合でも、同じアドレスのリソースがハードドライブにキャッシュされると、そのデータを再度リクエストすることはありません。キャッシュの大部分は Disk Cache によるもので、HTTP のプロトコルヘッダのキャッシュフィールドについては以下で詳しく説明します。
** ブラウザはどのファイルをメモリに放り込みますか?どれがハードドライブに投げ込まれますか?** これについてはウェブ上でも意見が分かれていますが、以下のものがより信頼できます:
大きなファイルの場合、メモリに保存されない可能性が高く、その逆が望ましい;
現在のシステムメモリ使用量が多い場合、ファイルは優先的にハードディスクに保存されます。
キャッシュポリシーによる分類
強制キャッシュ
強力なキャッシュとは、ブラウザがリクエストを開始したときに、キャッシュされたファイルがあるかどうかを調べ、もしあれば、サーバにリソースをリクエストすることなく、キャッシュされたファイルを直接使用することを意味します。この方法は帯域幅の消費を大幅に節約し、サーバへの負担を減らし、最もパフォーマンスを向上させるキャッシュ戦略の1つです;強力なキャッシュは、リクエストヘッダにExpiresとCache-controlを設定することで実現されます。
有効期限
キャッシュの有効期限を示します。
レスポンスメッセージヘッダーにこのフィールドを設定すると、ブラウザは有効期限が過ぎるまでリクエストを開始しないようになります。Expires: Thu, 10 Oct :11 GMT
- 絶対時刻であるため、ユーザがクライアント側でローカル時刻を修正する可能性があり、ブラウザがキャッシュ無効と判断してリソースを再要求する可能性があります。また、確信犯的な修正を考慮しなくても、時差や誤差などの要因でクライアントとサーバーの時刻が不一致になり、キャッシュが無効になることもあります。
- 書き方が複雑すぎる時刻の文字列に空白が複数あったり、文字が欠けていたりすると、不正な属性となり、設定が無効になる可能性があります。
キャッシュ制御
Expires の欠点が知られた後、HTTP/1.1 では Cache-control フィールドが追加されました。
両者の違いは、前者が絶対時間であるのに対し、後者は相対時間であることです。以下のようになります:
Cache-control: max-age=9522000
以下は、Cache-control フィールドの一般的な値のリストです:
- max-age: 上の例でわかるように、最大有効時間。
- must-revalidate: max-age を超えた場合、ブラウザはサーバーにリクエストを送り、リソースがまだ有効であることを確認する必要があります。
- no-cache: 文字通りの意味は「キャッシュしない」ですが、実際にはクライアントはコンテンツをキャッシュする必要があります。
- no-store: "キャッシュしない "という本当の意味。強制や比較を含め、すべてのコンテンツはキャッシュされません。
- public: すべてのコンテンツをキャッシュできます。
- private: すべてのコンテンツはクライアントによってのみキャッシュされ、プロキシはキャッシュされません。デフォルト。
Cache-Control は Expires よりも優先されます。HTTP/1.0 や HTTP/1.1 との互換性のために、実際のプロジェクトでは両方のフィールドが設定されます。
- ネゴシエーションキャッシュ
強制キャッシュが無効になった場合、キャッシュされたコンテンツを無効にするかどうかをサーバーが決定するコントラスト・キャッシングを使用する必要があります。
このプロセスでは、まずブラウザがキャッシュデータベースを要求し、キャッシュ識別子を返します。その後、ブラウザはこの識別子を使用してサーバーと通信します。キャッシュが無効でない場合、HTTPステータスコード304が返され、継続的な使用が示されるため、クライアントはキャッシュの使用を継続します。無効である場合、新しいデータとキャッシュルールが返され、ブラウザはデータに応答し、キャッシュデータベースにルールを書き込みます。
ネゴシエーション・キャッシュには2つのフィールドがあります:
最終更新日時と変更日時
サーバーは、リソースが最後に変更された日時を、例えば Last-Modified フィールドでクライアントに通知します:
Last-Modified: Mon, 10 Nov :11 GMT
ブラウザはこのフィールドの値とリクエストの内容をキャッシュデータベースに保存します。
次に同じリソースがリクエストされたとき、キャッシュが "期限切れかどうかわからない "かどうかを調べ、リクエストヘッダのIf-Modified-sinceフィールドを、リクエストでキャッシュに預けられたLast-Modifiedフィールドの値に設定します;
サーバーは If-Modified-since フィールドと Last-Modified フィールドを比較し、同じ場合はリソースが更新されていないことを意味し、304 を返し、クライアントはキャッシュを使用します。
欠陥:
リソースが秒以下の速度で更新される場合、キャッシュは使用できません。
ファイルがサーバーによって動的に生成される場合、ファイルが変更されていなくても、更新時間は常に生成された時間になります。
Eタグと非一致の場合
- 上記の問題を解決するために、EタグとIf-None-Matchフィールドが表示されます。
- E-tagはファイルの識別子を格納し、サーバはファイルのE-tagフィールドを格納します。その後、リソースが古いかどうかの判定は、ファイルのE-tagフィールドが変更されたかどうかを判定することを除き、If-Modified-Sinceと同様の判定処理を行い、If-Modified-Sinceをif-none-matchに変更します。サーバは同様にサーバは比較します。変更されていなければ 304 を返し、更新されていれば 200 と新しいキャッシュ識別子を返します;
- EタグはLast-Modifiedよりも優先順位が高い
キャッシュの概要
ブラウザがリソースを要求するとき:
- Service-Workerのfetch()イベントレスポンスの呼び出し
- menory-cacheを見る
- ここで細分化されたdisk-cacheをチェックしてください:
強力なキャッシュ:ExpiresとCache-controlの2つのフィールドに基づいて判断し、有効期限が無効でない場合は、強力なキャッシュを使用し、サーバーに要求しない、ステータスコードは200です。
ネゴシエーションキャッシュ:Last-Modified、If-Modified-SinceとE-tag、If-None-matchの2つのフィールドセットに基づいて判断し、強制キャッシュの有効期限が切れた後、ネゴシエーションキャッシュを使用します。 - ネットワークリクエストを送信し、応答を待ちます。
- レスポンスをディスクキャッシュに保存します。
- レスポンス内容への参照をメモリーキャッシュに格納
- レスポンスの内容をService-Workerのキャッシュストレージに保存します。)
ブラウザの動作
- アドレスバーにURLを入力し、Enter: disk-cacheで一致するものを探し、あればそれを使用し、なければウェブリクエストを送信します。
- 通常のリフレッシュ:タブが閉じられていないため、メモリキャッシュが利用可能で、最初にマッチングされ、次にディスクキャッシュがマッチングされます。
- 強制更新:ブラウザはキャッシュを使用せず、最新のリソースと200を直接返します;