集中型キャッシュがサーバーレス・アプリケーションを進化させる

集中型キャッシュをソリューションに組み込むことで、パフォーマンスを高め、サービス制限を回避し、時間とコストを節約します。

サーバーレス・アプリケーションは、いくつかの点で知られています。需要に合わせて拡張でき、0にすることもできます。一時的なネットワーク停止の際にもフォールトトレラントです。ほとんどの場合、コンテナや従来のソフトウェア・デプロイメントと比較すると、実行コストはほとんどかかりません。

そしてスピードでも知られています。サーバーレスアプリケーションは高速です。

必ずしもインフラが優れているからというわけではなく、より一貫性があり、予測可能で、スケーラブルなランタイムを自然に導く運用上の制約があるからです。サーバーレス・サービスの価格モデルはシンプルです。使った分だけ支払う。ソフトウェアがイベントにより速く反応すればするほど、月末の請求額は安くなります。

開発者がサーバーレス・アプリケーションをチューニングして猛スピードを実現する方法はたくさんあります。実際、私はHTTPコネクションの再利用から、API Gatewayをダウンストリームのサービスに直接接続する方法、Lambda実行環境のローカルに変数をキャッシュする方法まで、サーバーレスアプリを最適化する9つの方法を共有しています。しかし、重要な最適化が私のリストから抜けています:セントラル・キャッシュを実装することです。

アプリケーションで使用するキャッシュの種類によって、パフォーマンス、動作、機能は大きく異なります。Alex Debrie氏は、キャッシュの種類を理解するための投稿で、主な違いを見事に説明しています。

サーバーレス・アプリケーションにはサーバーレス・キャッシングが必要です。キャッシュを除いてアプリケーション全体が需要に応じて弾力的にスケールすると、スロットリングやデータ整合性の問題に直面します。しかし、キャッシュがアプリケーションと同じ容量でスケールする場合、このような経験は他にはありません。真にサーバーレスなキャッシュであるMomentoを使えば、集中型キャッシュへの扉を素早く簡単に開くことができ、アプリケーション全体でデータへの高速アクセスが可能になります。

ローカル・キャッシュだけでは不十分な理由

サーバーレス・サービスは、エンジニアリングの驚くべき偉業です。消費者からトラフィックベースのスケーリングの複雑さを完全に抽象化し、瞬時に応答する可用性の高いアプリケーションを提供します。

しかし、データを適切にキャッシュする方法を理解するためには、AWS Lambdaのようなサービスが需要を満たすためにどのように機能しているのか、ちょっと覗いてみる必要があります。

Lambda関数が呼び出されると、実行環境が作成されます。この環境は、コネクションを初期化してコードを実行するコンテナです。コードの実行が終わると、環境は次の呼び出しに備えて一定期間存続します。それ以降の呼び出しでは、初期化のステップはスキップされ、メイン関数ハンドラの外部に保存されたデータが再利用されます。

AWSのLambdaのベストプラクティスを考えてみよう:

実行環境の再利用を活用して、関数のパフォーマンスを向上させましょう。SDKクライアントとデータベース接続を関数ハンドラの外で初期化し、静的アセットを/tmpディレクトリにローカルにキャッシュします。関数の同じインスタンスによって処理される後続の呼び出しは、これらのリソースを再利用できます。これにより、関数の実行時間を短縮してコストを削減できます。

ラムダの実行環境は、一度に1つのリクエストにしか対応できません。実行環境があなたのコードを実行している間に別のリクエストが来たら、別の実行環境が初期化されて要求に応えることになります。

上の例では、合計5つの呼び出しがあり、3つの実行環境に分かれています。呼び出しが実行されている間にリクエストが来ると、”free “の実行環境がなければ、新しい実行環境が作られます。

リクエストが来て実行環境が利用可能になると、新しい実行環境を初期化する代わりに、その実行環境が使われます。環境が再利用されるとき、後続の呼び出しはローカルにキャッシュされたデータにアクセスできます。このローカルにキャッシュされたデータは、実行環境にスコープされ、実行環境がシャットダウンすると、永遠になくなります。

上記の3つの実行環境では、ローカルにキャッシュされたデータが3セットあります。もし全ての実行環境が同じルックアップ、例えばS3オブジェクトのルックアップを実行していたら、それぞれの実行環境の最初の呼び出しでキャッシュミスが発生することになります。これはコストを増加させるだけでなく、ローカルキャッシュの性質上、デバッグ時に混乱を引き起こす可能性があります。もしデータが一元化されたリモートの場所にキャッシュされていれば、複数の刹那的なローカル・ストアの代わりに、1つの場所で見ることができます。

ストアのアイテムのメタデータとサムネイルをロードするLambda関数を想像してみてください。新商品が登場し、大々的に宣伝されます。何千人もの人がその商品を予約販売のためにカートに入れます。商品がオンラインになると、トラフィックの波が関数を襲い、関数は水平方向にスケールし、何千もの新しい実行環境を初期化します。それぞれの新しい実行環境は、ローカルにキャッシュできるようにデータをロードしなければなりません。

時間が経つにつれて、このようなキャッシュミスが蓄積されていきます。SDKを何度も何度も呼び出し、同じデータを繰り返しロードし、ルックアップのコストが発生します。S3オブジェクトでは、それは本当に速く高価になるのです。

その後の各実行環境への呼び出しはキャッシュヒットとなり、余分なルックアップ呼び出しをすることなく値を返します。つまり、実行環境をローカル・キャッシュとして使うことで、パフォーマンスとコストの削減が可能になるわけだが、もっといい方法があるはずです。

集中型キャッシュによる救済

サーバーレス・アプリケーションには、SDKクライアントの初期化やデータベース接続管理など、ローカル・キャッシュの用途は確かにあります。しかし、ダウンストリーム・サービスの呼び出し回数を減らそうとする場合、集中型キャッシュが最良の選択肢となります。

リモートの集中キャッシュを使えば、実行環境だけでなくバックエンド全体でデータを共有することができます!しかし、できるからといって、そうすべきとは限りません。中央キャッシュは強力な武器だが、意図的な思慮なしに使えば悪夢になりかねないのです。

とはいえ、もしあなたが計画を練り、責任を持ってアプリケーションにキャッシュを実装しているなら、いくつかのエキサイティングな扉が開かれます。

実行コンテキスト間でデータを共有する場合、リード・アサイド・キャッシュにデータをキャッシュすることができます。リード・アサイド・キャッシュとは、永続データストアからデータをフェッチする前に、セントラル・キャッシュを検索することです。キャッシュ・ヒットがあれば、その値を返します。失敗した場合は、DynamoDBのようなデータストアからデータをロードします。

複数のソースからデータをロードし、断片を結合し、最終的にDynamoDBに最終結果を保存する前に、追加の変換と検証を実行するStep Functionワークフローを考えてみましょう。

統合されるデータはかなり大きく、ステップ・ファンクションのステート・データ・サイズ制限256KBをすぐに超えてしまう。このワークフローは、EventBridgeを使用して他のマイクロサービスからもデータを収集しますが、EventBridgeの最大メッセージサイズ制限は256KBです。

これらの制限により、イベントのペイロードを介してデータを送り返したり、ステップ関数の実行コンテキストにデータとして保持したりすることは不可能になります。その代わりに、セントラルキャッシュを使用してデータを一時的に保存し、イベント内でキャッシュキーを受け渡します。‍

Momentoでは、アイテムサイズの上限を1MBに設定しており、その結果、ステートマシンのデータ容量が4倍になります!アイテムサイズが1MBを超える場合は、Discordまたはお問い合わせフォームからMomentoチームに連絡して、この制限をさらに増やすことができます。

従来は、アイテムをS3に保存し、各Lambda関数でオンデマンドでデータをロードすることでこれを回避していました。マイクロサービス間でデータへのアクセスを提供する場合、同じアプローチが適用されるが、アクセスは事前に指定されたURL経由で付与されます。

Momentoはリモートキャッシングシステムなので、S3経由でデータをロードする際の高いレイテンシーを心配する必要はありません。その代わりに、すべてのマイクロサービスが高速なレスポンスタイムでアクセスできる中心的な場所があります。

結論

サーバーレスアプリケーションのステートレスな性質により、キャッシングは再び難しい問題になっています。最新のキャッシュ・ソリューションのほとんどは、サーバーレス・アプリケーションにうまく適合しません。

DAXElastiCacheのようなAWSサービスはキャッシュ機能を提供するが、クラスタ管理、フェイルオーバー設定、プロビジョニング・リソースの価格設定などのオーバーヘッドも伴います。

サーバーレス・アプリケーションにはサーバーレス・キャッシュが必要です。Momentoのリモート、中央集中、サーバーレスという性質は、自動スケーリング、大容量アイテムサイズのストレージ、低コストの代替手段を提供します。

サーバーレスアプリケーションにキャッシュを責任を持って実装することで、あなたは多くのAWSサービスのサイズ制限を回避する方法を構築しました。また、コストを大幅に削減し、サービス間通信を少し簡単にする方法を発見しました。

キャッシングは、サーバーレス・アプリケーションを構築する際のすべてのペインポイントを解決するわけではありません。しかし、サーバーレス・サービスの制限を回避するための回避策を実装することなく、迅速にソリューションを構築できるようになります。

今すぐMomentoを試してみてください。無料で始められます。まだ質問があったり、戦略について話したい場合は、Twitterで連絡するか、Momento Discordに参加してください!

サーバーレスコンテンツについては、Twitter(@AllenHeltonDev)でフォローしてください。また、私の「今週のサーバーレス・ピック」ニュースレターに参加すれば、展望をメールで受け取ることができます。