ElastiCacheでDBの結果をキャッシュした。元のDBが更新されたらキャッシュはどうなる?
解説
正解は「古いデータを返し続ける可能性がある」です。ElastiCacheに限らず、キャッシュは基本的にデータのコピーを保存しているだけなので、元のデータベースが更新されてもキャッシュ側は自動的に同期されません。明示的にキャッシュを削除・更新する処理を入れない限り、古いデータ(これをstale data(ステールデータ)と呼びます)がユーザーに返され続けます。「自動的にキャッシュも更新される」は最もありがちな誤解です。DBとキャッシュは独立したシステムなので、片方を更新してももう片方には何も起きません。「キャッシュが即座に削除される」も同様で、自動的には何も起こりません。「エラーが発生してアプリが停止する」こともなく、アプリは正常に動作し続けます。むしろ正常に動いているように見えるのに古いデータを返しているという点が厄介です。キャッシュが古くなる問題にどう対処するかこの問題への対処法は主に2つあります。1つ目はTTL(Time To Live)を設定する方法です。キャッシュに有効期限を設定し、期限が切れたら自動的にデータが消えるようにします。次にそのデータが必要になったときにDBから最新データを取得してキャッシュし直します。たとえばTTLを300秒(5分)に設定すれば、最大でも5分前のデータが返されることになります。2つ目はキャッシュの明示的な削除(Cache Invalidation)です。DBを更新したタイミングで、アプリケーション側のコードから該当するキャッシュを削除します。こうすれば次のリクエスト時にDBから最新データを取得するようになります。TTLは短すぎても長すぎてもダメTTLの設定は「短すぎるとキャッシュの意味がない、長すぎると古いデータが残り続ける」というトレードオフがあります。たとえばユーザーのプロフィール情報なら数分〜数十分のTTLで問題ないかもしれませんが、在庫数のようなリアルタイム性が求められるデータには短いTTLが必要です。データの性質に応じて適切な値を決める必要があります。Cache-AsideパターンとはElastiCacheを使う際に最もよく使われる設計パターンがCache-Aside(キャッシュアサイド)です。流れは以下のとおりです。アプリがまずキャッシュを確認するキャッシュにデータがあればそれを返す(キャッシュヒット)キャッシュになければDBに問い合わせ、結果をキャッシュに保存してから返す(キャッシュミス)このパターンではアプリケーション側がキャッシュの読み書きを制御するため、TTLや明示的削除と組み合わせることでデータの鮮度をコントロールできます。「キャッシュを入れれば速くなる」は半分だけ正しいキャッシュを導入するとDBへのアクセスが減り、レスポンスが速くなるのは事実です。しかし、古いデータを返してしまう問題、キャッシュが一斉に切れてDBに負荷が集中するキャッシュスタンピード、データの整合性が崩れるリスクなど、キャッシュ特有の課題がセットでついてきます。キャッシュは「入れたら終わり」ではなく、データの鮮度と速度のバランスを設計し続けるものだと理解しておくことが大切です。