5

特定のリソースのETagをどこに保存する必要がありますか?

アプローチA:オンザフライで計算

リソースを取得し、リクエストごとにその場でETagを計算します。

$resource = $repository->findByPK($id); // query

// Compute ETag
$etag = md5($resource->getUpdatedAt());

$response = new Response();
$response->setETag($etag);
$response->setLastModified($resource->getUpdatedAt());

if($response->isNotModified($this->getRequest())) {
    return $response; // 304
}

アプローチB:データベースレベルでの保存

ステートメントを少し遅くしながらCPU時間を少し節約します(トリガーを使用してETagを更新しますINSERT):UPDATE

$resource = $repository->findByPK($id); // query

$response = new Response();
$response->setETag($resource->getETag());
$response->setLastModified($resource->getUpdatedAt());

if ($response->isNotModified($this->getRequest())) {
    return $response;
}

アプローチC:ETagをキャッシュする

これはアプローチBに似ていますが、ETagは一部のキャッシュミドルウェアに保存されます。

4

3 に答える 3

4

ETag自体に入るアイテムを利用できるようにするためのコストに依存すると思います.

つまり、ユーザーは特定のリソースに対する要求を送信します。これにより、データベースでの取得操作 (またはその他の操作) がトリガーされます。

取得がファイルのフェッチなどの単純なものである場合、ファイルの統計情報の照会は高速であり、どこにも何も保存する必要はありません。ファイル パスの MD5 とその更新時間で十分です。

検索がデータベースへのクエリを意味する場合は、パフォーマンスを損なうことなくクエリを分解できるかどうかに依存します (たとえば、ユーザーが ID で記事を要求します。記事テーブルからのみ関連データを取得する場合があります。したがって、キャッシュの「ヒット」は主キーに対する単一の SELECT を必要としますが、キャッシュの「ミス」は、データベースに対して再度クエリを実行する必要があることを意味し、最初のクエリを無駄にするかどうかはモデルによって異なります)。

クエリ (または一連のクエリ) が十分に分解可能 (および結果のコードが保守可能) である場合は、動的 ETag を再度使用します。

そうでない場合、ほとんどは、クエリのコストと、保存された ETag ソリューションの全体的なメンテナンス コストに依存します。クエリのコストが高く (または出力がかさばり)、INSERT/UPDATE が少ない場合 (その場合のみ)、ETag を使用してセカンダリ列 (またはテーブル) を格納すると有利です。

キャッシングミドルウェアについては、わかりません。すべてを追跡するフレームワークがあれば、「がんばれ」と言うかもしれません。ミドルウェアは、上記の点を考慮して実装する必要があります。ミドルウェアが実装にとらわれない場合 (前代未聞ではないカット アンド ペーストの平手打ちでない限り、可能性は低い)、リソースへの更新を「スクリーニング」するリスクがあるか、またはおそらく更新時にキャッシュをクリアする API を呼び出す際の過度のぎこちなさ。ETag サポートによって提供される負荷の改善に対して、両方の要因を評価する必要があります。

この場合、「銀の弾丸」は存在しないと思います。

編集: あなたのケースでは、ケース A と B の間にほとんど、またはまったく違いはありません。 getUpdatedAt() を実装できるようにするには、更新時間をモデルに保存する必要があります。

この特定のケースでは、動的で明示的な ETag の計算 (ケース A) の方が簡単で保守しやすいと思います。いずれの場合も取得コストが発生し、明示的な計算コストは​​ MD5 計算のコストです。これは非常に高速で、完全に CPU バウンドです。私の意見では、保守性と単純さの利点は圧倒的です。

半関連のメモとして、場合によっては (データベースへの更新が頻繁に行われず、クエリが頻繁に行われる場合)、データベース全体Last-Modifiedにグローバルな時間を実装することが有利であり、ほとんど透過的である可能性があります。データベースが変更されていない場合、クエリが何であれ、データベースへのクエリがさまざまなリソースを返す方法はありません。このような状況では、グローバル フラグを簡単かつ迅速に取得できる場所 (データベースである必要はありません) に格納するだけで済みます。例えばLast-Modified

function dbModified() {
    touch('.last-update'); // creates the file, or updates its modification time
}

任意のUPDATE/DELETEコードで。次に、リソースはヘッダーを追加します

function sendModified() {
    $tsstring = gmdate('D, d M Y H:i:s ', filemtime('.last-update')) . 'GMT';
    Header("Last-Modified: " . $tsstring);
}

そのリソースの変更時間をブラウザに通知します。

If-Modified-Since次に、永続化レイヤーにアクセスする (または少なくともすべての永続的なリソース アクセスを保存する) ことなく、リソースに対する要求を304 で跳ね返すことができます。記録レベルでの更新時間は必要ありません (しなければなりません):

function ifNotModified() {
    // Check out timezone settings. The GMT helps but it's not always the ticket
    $ims = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
        ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
        : -1; // This ensures the test will FAIL

   if (filemtime('.last-update') <= $ims) {
       // The database was never updated after the resource retrieval.
       // There's no way the resource may have changed.
       exit(Header('HTTP/1.1 304 Not Modified'));
   }
}

リソース供給ルートのできるだけ早い段階で ifNotModified() 呼び出しを配置し​​、リソース出力コードのできるだけ早い段階で sendModified を配置し、リソースに関する限りデータベースが大幅に変更される場合はどこでも dbModified() を配置します (つまり、リソースのコンテンツに影響を与えない限り、アクセス統計をデータベースに記録するときは避けることができますし、おそらく避けるべきです)。

于 2012-08-21T07:09:08.730 に答える
2

私の意見では、ビジネスロジックがETagの永続化についてでない限り、ETagの永続化は悪い考えです。ETags に基づいてユーザーを追跡するアプリケーションを作成するときのように、これはビジネス機能です:)。

実行時間の節約の可能性は小さいか、まったくありません。このソリューションの悪い面は確かであり、アプリケーションが成長するにつれて大きくなります。

仕様によると、同じバージョンのリソースは、取得したエンドポイントに応じて異なる E-Tag を与えるものとします。

http://en.wikipedia.org/wiki/HTTP_ETagから:

「ETag の比較は、1 つの URL に関してのみ意味があります。異なる URL から取得したリソースの ETag は、等しい場合とそうでない場合があるため、それらの比較から意味を推測することはできません。」

このことから、ETag だけでなくそのエンドポイントも保持し、所有しているエンドポイントと同じ数の ETag を保存する必要があると結論付けることができます。クレイジーに聞こえますか?

HTTP 仕様を無視して、エンドポイントに関するメタデータなしで Entity に 1 つの Etag を提供したい場合でも。理想的には混合すべきではない少なくとも 2 つのレイヤー (キャッシングとビジネス ロジック) をまだバインドしています。エンティティを持つことの背後にあるアイデア (データを失うものとは対照的に) は、ビジネスロジックを分離して結合せず、ネットワーク、ビューレイヤーデータ、または... キャッシュに関するものでそれらを汚染しないことです。

于 2014-01-24T16:19:33.943 に答える
0

IHMO、これは、リソースが更新される頻度とリソースが読み取られる頻度によって異なります。

各ETagが変更の間に1回または2回読み取られる場合は、その場で計算するだけです。
リソースが更新されるよりもはるかに多く読み取られる場合は、リソースをキャッシュして、リソースが変更されるたびにETagを計算することをお勧めします(したがって、古いキャッシュされたETagを気にする必要はありません)。

ETagが読み取られるのとほぼ同じ頻度で変更された場合でも、特にリソースがデータベースに保存されているように見えるため、ETagをキャッシュします。

于 2012-08-21T08:36:53.077 に答える