この記事について
サービス運用中にRedisのキャッシュ互換性で困った経験について書きます。
何が起きたのか
運用中のサービスで、APIのドメインを変更した際に、Redisのキャッシュ取得時にエラーが発生しました。
例えばUserというドメインがあり、以前のデータ構造は以下の通りです。
{
"id": 1,
"name": "Alice",
"age": 20
}
キャッシュのキーは一意のidを使用していました。ここに新たにgenderというフィールドを追加し、その変更を行なったAPIをデプロイしようとしKubernetesクラスター上で旧APIのPodと新APIのPodが混在する状況が発生した際に、旧APIのPodがidをキーとして新APIのキャッシュデータを取得しようとすると、存在しないgenderフィールドが原因でエラーが発生し、逆に新APIのPodが旧APIのキャッシュデータを取得しようとすると、存在するはずのgenderフィールドが無いためエラーが頻発しました。
このような状況ではキャッシュ取得がうまくいかず、サービス全体のパフォーマンスが低下してしまいます。そこで、この問題をどのように解決したかについて説明します。
どうやって解決したか
この問題を解決するために、新バージョンのドメインに予め追加しておいたgenderフィールドと共にversionフィールドを追加しました。
{
"id": 1,
"name": "Alice",
"age": 20,
"gender": "Woman",
"version": 20241201
}
さらに、キャッシュキーにもバージョン情報を追加しました。新バージョンのAPIではidとversionがなければ、キャッシュがヒットしなくなります。
user-1-20241201
なぜversionを追加したか
versionフィールドを追加することで、新旧APIのキャッシュを区別できるようにしました。旧APIで作成・取得されるキャッシュにはversionフィールドが無いため、新APIでは取得されません。逆に、新APIで作成・取得されるキャッシュにはversionフィールドがあるため、旧APIでは取得されません。
versionの値はどうするか
versionの値は、APIのドメインを変更した日付を採用しました。APIのコミットハッシュを使用することも考えましたが、デプロイのたびに変わるためキャッシュの効果が薄れてしまいます。そのため、ドメインに変更があった場合にバージョンの日付を変更する運用を採用しました。
まとめ
このように、APIのドメインを変更した際にRedisのキャッシュ互換性を保つために、versionフィールドを追加し、キャッシュキーにもバージョン情報を追加することで、新旧APIのキャッシュを区別できるようになりました。