エピローグ — キャッシュ設計チェックリスト
マナミから未来のエンジニアへ
1年前、深夜のアラートから始まったキャッシュの旅。マナミは最後に、自分が学んだことをチェックリストとしてまとめた。
キャッシュ設計チェックリスト
基本設計
- キャッシュなしでも動作するか?(キャッシュは最適化であり依存先ではない)
- 読み書きパターンを分析したか?(Cache-Aside / Write-Through / Write-Behind)
- TTL を設定したか?(無期限キャッシュは事故の元)
- キャッシュキーは一意で、更新時に変化するか?
HTTP キャッシュ
- 静的アセットに
immutable+ 長いmax-age+ ハッシュ付きファイル名 - HTML に
no-cache+ ETag - API に適切な
s-maxage+stale-while-revalidate - 個人データに
private, no-store -
Varyヘッダーを正しく設定
Redis
-
maxmemoryとmaxmemory-policyを設定 - 本番で
KEYS *を禁止(SCANを使う) - 接続プールを設定
- 監視メトリクスを収集(ヒット率、メモリ、レイテンシ)
セキュリティ
- 認証付きレスポンスは CDN にキャッシュしない
- Redis はプライベートネットワーク + パスワード
- Cache Poisoning 対策(キャッシュキーの明示)
- Cache Deception 対策(パス正規化)
障害対策
- キャッシュサーバーダウン時のフォールバック
- Cache Stampede 対策(ロック or SWR)
- サーキットブレーカーの設定
- アラート閾値の設定
Rails キャッシュクイックリファレンス
# config/environments/production.rb
config.cache_store = :redis_cache_store, {
url: ENV["REDIS_URL"],
expires_in: 1.hour,
namespace: "freshmarket",
error_handler: -> (method:, returning:, exception:) {
Rails.logger.error("Redis error: #{exception}")
Sentry.capture_exception(exception)
}
}
# Cache-Aside パターン
Rails.cache.fetch("product:#{id}", expires_in: 1.hour) do
Product.find(id)
end
# フラグメントキャッシュ(View)
<% cache @product do %>
<%= render "product_card", product: @product %>
<% end %>
# ロシアンドールキャッシュ
<% cache ["products", @products.maximum(:updated_at)] do %>
<% @products.each do |product| %>
<% cache product do %>
<%= render "product_card", product: product %>
<% end %>
<% end %>
<% end %>
# HTTP キャッシュ(Controller)
class ProductsController < ApplicationController
def show
@product = Product.find(params[:id])
if stale?(etag: @product, last_modified: @product.updated_at)
expires_in 1.hour, public: true,
stale_while_revalidate: 5.minutes
render :show
end
end
end
# キャッシュ無効化(Model コールバック)
class Product < ApplicationRecord
after_commit :invalidate_cache
private
def invalidate_cache
Rails.cache.delete("product:#{id}")
Rails.cache.delete_matched("products:*")
end
endCache-Control 早見表
| シナリオ | 設定 |
|---|---|
| 静的アセット(ハッシュ付き) | public, max-age=31536000, immutable |
| HTML ページ | no-cache + ETag |
| 公開 API | public, s-maxage=60, stale-while-revalidate=300 |
| ユーザー固有 API | private, no-cache |
| 認証・決済 | no-store |
キャッシュ戦略の全体像
Loading chart...
最後に
INFO
キャッシュの本質: 同じ計算を二度しない。それだけのことだが、正しく実装するには、HTTP、CDN、アプリケーション、Redis、DB、セキュリティ、分散システムの知識が必要になる。一つずつ、層を重ねていけばいい。
マナミの FreshMarket は今日も快適に動いている。深夜2時のアラートはもう鳴らない。