本セッションのコンテンツ

川島拓海氏:それでは私から「キャッシュの課題と戦略」について話します。よろしくお願いします。(スライドを示して)私はアマゾンウェブサービスジャパンの川島拓海と申します。ふだんはソリューションアーキテクトとして、お客さまのクラウド移行や検討を支援しています。得意な技術領域は機械学習や画像認識です。

本セッションでは、Amazon Builders' Library『キャッシングの課題と戦略』を基にした紹介をします。ここに貼ってあるQRコードから記事のページに飛べるので、ぜひこのリンクから入ってもらえると幸いです。

それではさっそくですが、本日私からお話しするコンテンツを紹介します。イントロダクションの後、ローカルキャッシュと外部キャッシュの分類、キャッシュのセキュリティ、そしてその他の考慮事項について順に紹介します。

なお、これらを話していく中で、Amazonのキャッシュに関するベストプラクティスを紹介していきたいと思います。最後にまとめに代えて、キャッシュに関するAmazonのベストプラクティスを再度確認します。

イントロダクション

まずはイントロダクションです。なお、QRコードの表示はこのスライドまでとしますが、最後に再度表示します。

本セッションでは、キャッシュを導入および運用する際の考慮事項、および検討事項を伝えられればと思います。これを基に、みなさまのワークロードにおいて、そもそもキャッシュが必要なのか、どのようなキャッシュ戦略を取るのがいいのかといったことを決める際の1つの参考になれば幸いです。

主な対象となるのは、キャッシュ導入や運用の方法に迷っているエンジニアの方、およびキャッシュを利用しているものの検討に甘さを感じているエンジニアの方です。

これから話すのは一般的なキャッシュの運用について、およびAmazonが考えるキャッシュの検討すべき事項です。今回は具体的な実装方法やAWSサービスの細かい話には踏み込みません。

本セッションで取り扱うキャッシュの定義

(スライドを示して)さて、ここで本セッションで取り扱うキャッシュがどのようなものか、紹介しておきます。1つの例として、ユーザーがネットワーク経由でデータベースなどの呼び出しを行う場合を考えてみてください。この時、リソースのそもそもの処理能力から、呼び出し速度が遅い場合があります。また、呼び出し量が増えた時に、それに対応できるようにリソースを大規模にスケールアウトする必要が出て、コスト面が問題になることも考えられます。

本セッションで取り扱うキャッシュは、そのような問題を解決するためのものです。(スライドを示して)なおこの時、右の図のようにキャッシュの後側にあり、キャッシュミスの際にデータを取りに行く元のリソースを、このセッションではダウンストリームリソースと呼びます。

Webサーバーやデータベースサーバーなど、キャッシュ元となるサーバーがこれに当たるので、みなさまの中でこのダウンストリームリソースを適宜置き換えて思い浮かべてもらえると幸いです。

ローカルキャッシュと外部キャッシュの比較

(スライドを示して)キャッシュに関するAWSサービスをいくつかピックアップしたのがこちらです。今回はこの一つひとつのサービスについて深く踏み入ることはしませんが、AWSの内外を含め、キャッシュの選択肢はさまざまにあり、用途がはっきりしているものもある一方で、どのようなキャッシュを用いるのが適切かわからないことも出てくるかと思います。

なので、キャッシュ戦略の選び方の1つのヒントとして、ここではまずキャッシュを分類する観点を1つ取り上げます。それがローカルキャッシュと外部キャッシュの分類です。

ローカルキャッシュは左の図のように、既存のダウンストリームリソース、すなわちデータベースサーバーやWebサーバーなどのキャッシュ元となるサーバーの内部にキャッシュを実装するものです。一方で外部キャッシュは、右側の図のように、ダウンストリームリソースの外側に実装するものです。ここからはそれぞれについて説明した後、あらためてこれらローカルキャッシュと外部キャッシュを比較します。

ローカルキャッシュの利点と欠点

最初に紹介するのがローカルキャッシュです。これはダウンストリームリソースの内部にそのリソースの一部を用いるかたちでインメモリで実装するキャッシュを指します。

右側の図のように、ダウンストリームリソースがスケールアウトされて複数存在する場合は、それぞれのサーバーの内部にキャッシュが実装されます。なお、クライアントでキャッシュを保持する実装もローカルキャッシュと呼びますが、本セッションではそのような実装は割愛します。

このキャッシュは迅速かつ簡単に実装できるのが何よりも大きな利点で、最初に実装および評価されることが多い方法です。

しかし、ローカルキャッシュにはいくつかの欠点もあります。ここからはその欠点を見ていきます。(スライドを示して)1つ目が、サーバー間でキャッシュの一貫性が保証されないことです。これは複数あるサーバーごとに、同様の役割を持つキャッシュが保存されているためです。

例えば、最初のアクセスであるサーバーにアクセスした際は、キャッシュが最新の情報を保持しており、それが返ってきたとします。そしてこの時、直後のアクセスが別のサーバーに割り振られ、その別のサーバーのキャッシュが古いデータを保持していた場合には、最初と異なる結果が得られることになります。これがキャッシュの一貫性の問題です。

2つ目が、新しいサーバーが立ち上がった時のコールドスタートの問題です。サーバーが立ち上がった瞬間は内部にあるキャッシュも立ち上がったばかりで、キャッシュが空の状態です。この時、リクエストはすべてキャッシュミスとしてサーバー本体に投げられます。これによりサーバー本体、ダウンストリームリソースの負荷が非常に大きくなります。

そして3つ目は、ダウンストリームリソースの負荷がサーバー群のサイズに比例することです。これは、キャッシュがダウンストリームリソースの内部にあるがゆえに起こる問題です。データ自体や読み書きの量が増えると、キャッシュミス率が上がることは避けられません。この時、各ダウンストリームリソース内で同様の読み込みが行われます。そして、キャッシュへの書き込みも各サーバー内でそれぞれ行う必要があり、負荷は大きくなります。

(スライドを示して)以上に挙げたローカルキャッシュの問題のうち、キャッシュの一貫性やコールドスタートの問題は、リクエストの合体を用いることにより影響を減少できます。これはキャッシュミスしたリクエストを逐次ダウンストリームリソースに投げるのではなく、まとめて投げるものです。これによりある程度一貫性の高いレスポンスを返せるほか、コールドスタート時のダウンストリームリソースの負荷を減らせます。

一方、ダウンストリームの負荷の増加については、ローカルキャッシュでの問題の緩和が難しいです。キャッシュミスやリクエスト数をメトリクスとして出力することで、モニタリングして対処を考えられます。

一方で、これらの問題を緩和もしくは解消できるのが、ローカルキャッシュと対比して紹介する外部キャッシュです。ここからは外部キャッシュについてお話しします。

外部キャッシュの利点と欠点

外部キャッシュは、キャッシュをダウンストリームリソースとは完全に別で保持するものです。ローカルキャッシュでは、ダウンストリームリソースが増えるとサーバーごとにキャッシュを保持していました。一方、外部キャッシュではキャッシュサーバーだけで、ダウンストリームリソースとは独立してスケーリングを行います。

(スライドを示して)ローカルキャッシュであった問題を踏まえ、ここに外部キャッシュの利点を列挙しました。第1に、個々のダウンストリームリソースでキャッシュを管理する方法と異なり、キャッシュが別サーバーでまとめられているので、キャッシュの一貫性の問題が軽減されます。ただし、書き込みによるキャッシュ更新時のエラーは依然として起こり得ます。

第2に、ダウンストリームリソースとは別のサーバーとして動かすため、ダウンストリームリソースをデプロイした際のコールドスタート問題が発生しません。

第3に、キャッシュサーバーを外部に切り出したことで、ダウンストリームリソースの全体的な負荷がフリートサイズに比例しなくなります。これは、キャッシュの読み込みや書き込みは外部サーバーに対して一元化して行えるためです。

これらに加え、ストレージスペースの制約から解放(される)という側面もあります。これはどういうことかと言うと、ローカルキャッシュではダウンストリームリソースの一部を切り出してキャッシュとしていたため、ダウンストリームリソース全体のスペースに依存してキャッシュのスペースにも実質的な制約がありました。一方で、外部キャッシュではその制限から解放されるというわけです。

キャッシュのスペースに制限があると、キャッシュに入れられるデータが少ないうえにキャッシュミスの可能性が高まることも考えられるため、これは非常に重要な問題の改善です。このように、外部キャッシュはローカルキャッシュで発生する問題を緩和もしくは解消できます。

(スライドを示して)しかしながら、外部キャッシュにも特有の問題が存在します。その問題が運用コストの増加です。外部キャッシュの追加はダウンストリームリソースと異なる新しいサービスの追加と捉えられ、その特性はダウンストリームリソースと異なる場合が多いです。ゆえに、モニタリングや管理、スケーリングなどを別枠で考える必要があります。

一例として、運用においてメンテナンスウィンドウが必要か、ゼロダウンタイムアップグレードが可能かなどが挙げられます。

キャッシュの運用における4つの考慮事項

ここからは、キャッシュの運用における考慮事項にどのようなものがあるかを見ていきます。

1つ目が、キャッシュの障害が起きた時の処理です。この障害にはキャッシュサーバー群全体の障害、ノードの障害、書き込みや読み込みの個別の障害などが挙げられます。

障害が起きた際の対応策として、他のサーバーでのフェイルオーバーが考えられます。しかしこの方法では、キャッシュを提供する外部サーバー群全体の障害などには対応できません。

他の対応策として、外部キャッシュとは別にローカルキャッシュを持っておき、障害の際に切り替えるというものも挙げられます。

そして第3の対応策として、(スライドの)右側の負荷制限の実装も考えられます。キャッシュサーバー群が使えなくなった場合でも、ダウンストリームリソースは一定以上のリクエストを受け付けないようにし、障害の影響がダウンストリームリソースにまで及ばないようにします。負荷制限については、本日2番目のセッションで話す長友(長友健人氏)から詳しく紹介があります。

第2の考慮事項として、キャッシュフリートのスケーリングと伸縮性が挙げられます。ダウンストリームリソースとは独立してキャッシュをスケーリングできるのは外部キャッシュの良さですが、それゆえの運用の難しさもあります。

どのようなメトリクスを用いてどのような閾値でスケーリングするのが適切なのか、現実的なトラフィックパターンに基づいたテストによって決めるのが望ましいです。また、スケーリングにはキャッシュ固有の特性を考慮して、キャッシュサーバーの追加や削除の際のテストを許容する必要があります。

第3の考慮事項として、複数ノードからの書き込みへの対応が挙げられます。キャッシュには通常、条件付き書き込みやトランザクションなどの機能がありません。なのでキャッシュ更新のコードが正しく挙動することを確認し、キャッシュが無効な状態や一貫性のない状態にならないように注意します。

第4に、他のサービスのバージョニングとの対応も考える必要があります。キャッシュ以外のサービスにおいてデータ形式が更新される時、それに合わせてキャッシュも更新される必要があり、データの不整合によるエラーが起こってはいけません。それに加えて、新旧両方のデータバージョンが存在する場合もあります。その場合でも、両方のバージョンにキャッシュが対応してうまくハンドリングできる機構を作る必要があります。

外部キャッシュの導入においては、ここまで挙げてきたような運用の問題を考慮する必要があります。

Amazonのキャッシュに関するベストプラクティス

そしてここで、Amazonのキャッシュに関するベストプラクティスを一部取り上げます。これらは外部キャッシュ運用の考慮事項に含まれるものです。

第1に、キャッシュをダウンストリームリソースなどの他のサービスと同様に、厳密に管理・モニタリングすることが重要です。それ以外にもキャッシュが使用できない場合に、サービスが回復力を持つようにすること、他のサービスのバージョニングと対応できるようにすることも重要です。

ローカルキャッシュではダウンストリームリソースの内部にキャッシュを持つ分、これらを考慮する負担が外部キャッシュに比べて少なくなる可能性が高いです。しかしながら、ローカルキャッシュでの運用の際も、これらのベクトプラクティスをまったく考えなくていいわけではもちろんありません。

例えばローカルキャッシュでは、キャッシュとダウンストリームリソース本体のストレージリソースのバランスを適切に配分するために、外部キャッシュにはないモニタリングが必要になることもあるかと思います。

ローカルキャッシュと外部キャッシュの利点まとめ

(スライドを示して)以上を基に、ローカルキャッシュと外部キャッシュのそれぞれの利点をあらためてまとめたのがこちらのスライドです。ローカルキャッシュは導入が迅速かつ簡単であり、外部キャッシュで見てきたような運用の問題も考慮が少なくて済みます。

一方、外部キャッシュはローカルキャッシュで解決できない問題を改善します。ここにはキャッシュの一貫性の問題の軽減、コールドスタート問題の回避、ダウンストリームリソースの負荷の低減、メモリスペースの制約からの解放が挙げられます。

(次回に続く)