ETagをどう生成するか
ETagとは何か
ETagはHTTPレスポンスヘッダのひとつで、RFC 2616の14.19(日本語訳)で規定されています。If-None-Matchリクエストヘッダを使った条件付きGETでの転送量軽減や、If-Matchを使った条件付きPUTでの競合検出などに使われる値です。
強いETag、弱いETag
ETag(エンティティタグ)には強弱があります。簡単にいえば、HTML内のアクセスカウンタが1上がっただけで変わるのが強いETag、変わらないのが弱いETagです。弱いETagは、リソースの意味が変わらなければ変わりません。
同13.3.4では「HTTP/1.1 オリジンサーバにとってより望まれる動作とは強いエンティティタグと Last-Modified 値の両方を送る事である」とされています。なるべく強いETagを使いましょう、ということです。
Rails2.0の生成手法
「http://blogs.ricollab.jp/webtech/2008/02/etag/」によれば、Rails2.0ではレスポンスボディのMD5をETagとしているようです。強いETagですね。単純な手法でありながら、HTTP1.1の望む挙動になっているので、開発者としては惹かれるところです。
Rails式の問題点
この手法に対し「ETagを使ってSpringとHibernateの転送量と負荷を削減する」では、2つの問題点が指摘されています。
1点目について補足します。条件付きGETリクエストに応じてModelやViewの処理をおこない、せっかくレスポンスボディを作っても、ETagがIf-None-Matchの値と同じであれば、レスポンスボディを空にしなければなりません(「304 Not Modified」ではレスポンスボディを送ってはいけない)。処理が無駄になってしまうわけです。
なお2点目は、強いETagであれば当然の挙動なので、特に問題ないでしょう。
より洗練された手法
「ETagを使ってSpringとHibernateの転送量と負荷を削減する」の「ETagインターセプタ」の項では、Modelに変更があればViewカウンタをインクリメントし、それをETagとして使う手法が紹介されています。ただし、強いETagであることを遵守しようとすると、ビューテンプレートなどの変更についてもトラックしなければならないのではないかと思います。
他の案として、Modelの更新処理がおこなわれた際に、影響のあるリソースのHTMLを生成してキャッシュし、そのETagを紐づけておく手法も考えられます。あるいはバッチ処理で充分かもしれません。ニコニコ動画では、トップページを10分おきにバッチ更新し、HTMLをmemcachedにキャッシュしているそうです(『WEB+DB PRESS Vol.42』、59ページ)。