はじめに
Redisなどでキャッシュを導入すると、レスポンスを速くし、DBや外部APIへの負荷を下げられます。読み取りが多いシステムでは、非常に効果的な手段です。
一方で、キャッシュは古い値だけでなく、空データや一時的な失敗の結果まで保持します。例えば日付をキーにしたキャッシュへ空データが入ると、その日はずっと空の結果が返り続けることがあります。
この記事では、キャッシュで空データが返り続ける仕組みと、設計・運用で確認すべき点を整理します。
キャッシュは正しい結果だけを保存するとは限らない
キャッシュは、取得した値をキーに紐付けて再利用する仕組みです。値が正しいか、一時的な値か、空であることに意味があるかまでは判断しません。
例えば、ある日付のデータを取得する処理が次のような流れだったとします。
- 日付を含むキーでキャッシュを確認する
- キャッシュがなければDBや外部APIから取得する
- 取得した結果をキャッシュへ保存する
- 以降はキャッシュの値を返す
このとき、データ連携がまだ終わっていない、検索条件が誤っている、一時的に外部APIが空を返した、といった理由で空データを取得することがあります。その値をそのまま保存すると、後から正しいデータが利用可能になっても、TTLが切れるまで空データが返ります。
日付をキーにすると影響が長引きやすい
日次データを扱う場合、次のようなキーを使うことがあります。
sales:2026-08-07
このキーに空データを「翌日まで有効」として保存すると、2026年8月7日の間は再取得されません。午前中のデータ連携遅延で空が保存されたのに、午後に連携が完了しても画面には空のまま表示されます。
日付をキーにすること自体は問題ではありません。問題は、データが確定する時刻と、キャッシュの有効期限を同じものとして扱ってしまうことです。
日次で確定するデータなら、次の点を設計で明確にします。
- その日のデータはいつ確定するか
- 確定前に空データを返すことは正常か
- 空データをキャッシュしてよいか
- 正しいデータが入ったときに既存キャッシュを削除または更新できるか
空データには意味が異なる2種類がある
空データをすべてキャッシュしない、というルールにも注意が必要です。空には少なくとも2つの意味があります。
- 条件に一致するデータが本当に存在しない
- データを取得できず、結果として空になった
前者は、短時間ならキャッシュしてもよい場合があります。同じ存在しないIDへの問い合わせが集中するとき、DBへの負荷を防げるためです。これはネガティブキャッシュと呼ばれます。
後者を空データとしてキャッシュすると、障害や連携遅延を正常な結果として固定してしまいます。取得失敗と「0件」をレスポンスや内部の型で区別できるようにします。
TTLだけで整合性を任せない
「TTLを短くすればよい」と考えがちですが、短いTTLにもコストがあります。
- TTLが短すぎると、キャッシュの効果が薄れる
- 同じタイミングでキャッシュが切れると、DBや外部APIにアクセスが集中する
- 空データが数分だけ残ることも、画面によっては問題になる
TTLは古い値をいつまで許容するかを決める仕組みです。データが更新されたことをキャッシュへ伝える仕組みの代わりにはなりません。
更新元を把握できる場合は、データ更新時に関連するキーを削除または更新する方法を検討します。日次バッチでデータが確定するなら、バッチ完了時に当日キーを削除する運用も有効です。
キャッシュのキーには条件をすべて含める
空データの原因は、キャッシュの有効期限だけではありません。検索条件の一部がキーに入っていないと、別の条件で取得した結果を誤って返します。
例えば、テナントごとにデータが違うのに日付だけをキーにすると、あるテナントの空データが別のテナントにも返る可能性があります。
キーを設計するときは、結果を変える条件を洗い出します。
- テナントや組織
- ユーザーの権限
- 日付や対象期間
- 表示言語
- 検索条件やソート条件
- データ形式のバージョン
全てを無条件にキーへ詰め込むのではなく、そもそもユーザーごとに異なる値を共有キャッシュすべきかも確認します。
調査できる状態を作る
キャッシュが絡む不具合は、DBを見るだけでは原因が分からないことがあります。DBには正しいデータがあるのに、APIが空を返すためです。
少なくとも次の情報を確認できるようにします。
- どのキャッシュキーを使ったか
- キャッシュヒットかミスか
- 保存された値と保存時刻
- TTLの残り時間
- キャッシュミス時に呼び出したデータソースと結果
機密情報をログへ出さない配慮は必要です。しかし、キーの構造、件数、キャッシュのヒット状況が見えなければ、調査のたびにRedisを直接確認することになります。
キャッシュ導入時の確認項目
キャッシュを追加するときは、性能だけでなく次の項目を確認します。
- 空データと取得失敗を区別できるか
- 空データを保存する場合、その理由とTTLは明確か
- データ更新時にキャッシュを削除または更新できるか
- キーに必要な検索条件が含まれているか
- キャッシュ障害時にデータソースへフォールバックできるか
- ヒット率、キー、TTLを調査できるか
この確認がないと、性能改善のために入れたキャッシュが、データの正しさを疑うべき新しい原因になります。
おわりに
キャッシュは性能改善に役立ちますが、取得時点の結果を保存するだけです。空データや一時的な失敗も、設計しなければ正しい値と同じように残ります。
特に日付単位のキャッシュでは、データの確定時刻、空データを保存する意味、更新時の無効化をセットで考える必要があります。キャッシュを速さのためだけの仕組みにせず、データの鮮度と調査しやすさまで含めて設計することが大切です。