Slide 1

Slide 1 text

Cache Stampede 対策として セマフォを使う najeira @ Gunosy Cache Night

Slide 2

Slide 2 text

Cache Stampede キャッシュの有効期限切れによって オリジン(データベースなど)へ アクセスが殺到する問題 Stampede = 殺到

Slide 3

Slide 3 text

典型的な使い方 # キャッシュからデータを取得する data = get_cache(key) if not data: # キャッシュがなければデータベースから取得する data = get_data_from_database(...) # 新しいデータをキャッシュに保存する set_cache(key, data, ttl=60) # ユーザーにレスポンスを返す send_response(data)

Slide 4

Slide 4 text

アクセスが少ないと

Slide 5

Slide 5 text

アクセスが多いと

Slide 6

Slide 6 text

呼び方? 他にも ● Cache miss storm ● Dog-piling と呼ばれたりするらしい Thundering Herdと呼ばれることも?

Slide 7

Slide 7 text

対策 ● ロック ● 別プロセスで定期更新 ● 確率的な期限切れ 今日はロック(セマフォ)について

Slide 8

Slide 8 text

有名OSSは? ● Rails ActiveSupport::Cache::Store race_condition_ttl ● nginx proxy_cache_lock ● Varnish Grace mode いずれもロック系の対策

Slide 9

Slide 9 text

考え方 新しいキャッシュの作成は 「ひとりだけ」が実行すればよい 他のプロセスは、 それを待つか、 古いキャッシュを使う

Slide 10

Slide 10 text

ひとりだけ更新

Slide 11

Slide 11 text

セマフォ 並列環境での複数の実行単位が共有す る資源にアクセスするのを制御するもの。 ある資源が何個使用可能かを示す記録 で、使用や解放の際に記録を安全に書き 換え、資源が使用可能になるまで待つ操 作が結びついている。 by https://ja.wikipedia.org/wiki/セマフォ

Slide 12

Slide 12 text

セマフォ Webサーバは複数台に分散、 同一のサーバでも複数プロセス OSの(プログラミング言語上の) セマフォを使うことはできない。

Slide 13

Slide 13 text

セマフォ キャッシュが共有資源なので、 キャッシュのシステム上に セマフォを実現すればよい

Slide 14

Slide 14 text

Memcached Add add: データが存在しない場合のみ 保存する。

Slide 15

Slide 15 text

コードで見ると data = memcache.get(key_for_data) if not data: memcache.add(key_for_semaphore, 1, ttl=60) data = get_data_from_database(...) #データベースから取得 memcache.set(key_for_data, data, ttl=120) # キャッシュを保存 else: #セマフォの獲得を試みる ret = memcache.add(key_for_semaphore, 1, ttl=60) if ret: # セマフォを獲得した場合は新しいキャッシュを作る data = get_data_from_database(...) memcache.set(key_for_data, data, ttl=120) return data

Slide 16

Slide 16 text

ポイント セマフォ用のキーは データ用のキーより 短い有効期限にしておく セマフォ < データ

Slide 17

Slide 17 text

ポイント addできるのはひとり ⇒オリジンへのアクセスはひとり セマフォ用のキーに有効期限がある ⇒セマフォの解放が非同期で自動 ⇒解放されると次のアクセスが新しい キャッシュを作る