各レイヤーでキャッシュすることにより、アプリのパフォーマンスを向上させる

遅いアプリにさようなら!究極のパフォーマンスを実現するために、アプリを上から下までキャッシュする方法を学びましょう。

アプリケーションについて語るとき、スピードと効率ほど重要なものはありません。しかし、最新のアーキテクチャでは多くの可動部があるため、データフローに遅延が生じ、すべての処理が遅くなる可能性があります。そこでキャッシュの出番となります!キャッシュにデータを保存することで、アプリケーションはリクエストのたびにデータを処理することなく、簡単にアクセスできるようになります。

これは、トラフィックのピーク時であっても、より速いロード時間とスムーズなパフォーマンスを意味します。スピーディーでシームレスなアプリケーションを好まない人はいないでしょう。ですから、サーバーレスアーキテクチャを構築している場合でも、従来のアプリケーションを構築している場合でも、キャッシングはユーザーを満足させ、アプリケーションをよく動くマシンのように稼働させ続けるスーパースターソリューションなのです。アプリケーションを次のレベルに引き上げる準備をしましょう!

アプリのパフォーマンスを向上させるためにキャッシュできる場所は?

信じられないかもしれませんが、ユーザーインターフェイスとデータベースの間には5つのレベルのキャッシュがあります!Alex Debrie氏がブログの投稿で言及しているように、それぞれに長所と短所があります。AWS上に構築されたアプリケーションにおいて、これらのそれぞれがどのように見えるかについて説明しましょう。

クライアントサイドキャッシュ

ユーザがアプリケーションにアクセスすると、ブラウザはコンテンツのリクエストをサーバに送ります。コンテンツがクライアント側にキャッシュされている場合、ブラウザはサーバに新たなリクエストをする代わりに、ローカルにキャッシュからコンテンツを取得することができます。これは、ネットワーク・トラフィックによる遅延や待ち時間なしに、データが即座に利用可能になることを意味します。

クライアントサイドのキャッシュは、ネットワークを介して送信されるデータ量を削減します。クライアント側でデータがすでにキャッシュされている場合、サーバーは再度データを送信する必要がないため、帯域幅を節約し、サーバーの負荷を軽減することができます。

アプリケーションへのAPI呼び出しは、レスポンスに含まれるデータをキャッシュするようブラウザに指示するヘッダーを返すことができます:

Cache-Control: このヘッダは、ブラウザがコンテンツをキャッシュする期間と、それ以降のリクエストでサーバと再検証するかどうかを制御します。コンテンツがキャッシュされる最大時間を指定するmax-ageや、クライアントがコンテンツを使用する前にサーバーで再検証することを強制するno-cacheのような指標を持つことができます。
Expires: このヘッダは、コンテンツが期限切れとなり、クライアントによってキャッシュされなくなる特定の日時を指定します。
ETag: このヘッダはコンテンツの一意な識別子を提供し、クライアントはこれを使ってキャッシュされたバージョンがまだ有効かどうかを判断することができます。ETagが変更されていなければ、クライアントはサーバに新しいリクエストをすることなく、キャッシュされたバージョンを使うことができます。

Content delivery network (CDN) 

アプリケーションに画像や動画など多くのコンテンツがあり、それをユーザーに素早く見てもらいたい場合、コンテンツ・デリバリー・ネットワーク(CDN)を使うことができます。AWS上に構築されたアプリケーションは、CDNとしてAmazon CloudFrontを使用します。CloudFrontはあなたのコンテンツのコピーを世界中の様々な場所に保存し、人々がどこにいてもあなたのコンテンツに本当に速く簡単にアクセスできるようにします。

さらに、CloudFrontはデータをキャッシュするため、写真やビデオの取得がさらに速くなります。たとえコンテンツがAmazon S3でホストされているシンプルなウェブサイトであっても、CloudFrontを使えばスピーディーにアクセスできるようになります。CloudFrontを設定し、アプリでメディアキャッシュを有効にするには、わずか数行のコードが必要です。以下のSAMテンプレートの例をご覧ください。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-s3-bucket
 
  MyCloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
          - Id: MyS3Bucket
            DomainName: !GetAtt MyS3Bucket.DomainName
            S3OriginConfig:
              OriginAccessIdentity: !Ref OriginAccessIdentity
        DefaultCacheBehavior:
          TargetOriginId: MyS3Bucket
          ViewerProtocolPolicy: redirect-to-https
          ForwardedValues:
            QueryString: true
          MinTTL: 0
          DefaultTTL: 86400
          MaxTTL: 31536000
        Enabled: true

他のキャッシュと同様に、コンテンツにTTL(time to live)を設定する必要があります。これは、リフレッシュのためにリクエストがS3に戻るまでの保持時間をCDNに伝えるものです。

API キャッシュ

AWS上に構築されたほとんどのRESTful APIとWebSocketは、Amazon API Gatewayを使用しています。このサービスは、リクエストに対するレスポンスを指定された時間キャッシュに保存することで、キャッシュを可能にします。呼び出し元がAPIにリクエストを行うと、API Gatewayはまずキャッシュをチェックし、そのリクエストに対するキャッシュされたレスポンスがあるかどうかを確認します。キャッシュされたレスポンスがある場合、API Gatewayはリクエストをバックエンドのサービスに転送することなく、クライアントに直接レスポンスを返します。

このタイプのキャッシュはパフォーマンスを向上させるだけでなく、API Gatewayがデータを抽出するために計算リソースを使用しないため、コスト削減にもつながります。

デフォルトでは、API Gatewayはリクエストパス、クエリー文字列、ヘッダーをキャッシュします。しかし、キャッシュキーを自分でカスタマイズして、追加のデータを含めたり除外したりすることができます。

AWS AppSyncはマネージドGraphQLサービスであり、API Gatewayとは別に独自のキャッシュメカニズムを持っています。これは、クエリと変異からのすべての結果をキャッシュします。リクエストレベルとフィールドレベルのキャッシュを提供する AppSync は、実行を高速化し、計算を削減する素晴らしい方法を提供します。個々のリゾルバに設定可能なキャッシュ設定を追加することもでき、頻繁に変更されないデータソースからのデータをより長くキャッシュすることができます。

AppSyncのJavaScriptリゾルバでは、開発者はMomento Node.js SDKを使用して、さらに別のレイヤでキャッシュを追加できます。

アプリケーションキャッシュ

ユーザーインターフェースから新しいリクエストが来て、APIキャッシュを通過すると、サーバーサイドの実装がデータをキャッシュする次の機会になります。頻繁にアクセスされるデータ、ロードにコストがかかるデータ、あるいは性質上短命なデータは、キャッシュの絶好の機会です。

このレイヤでのキャッシュは、Momento Cacheの素晴らしい使用例です。ビジネスロジックがサードパーティのAPIを呼び出す場合、そのAPIは低速で高価であることが知られています!あらゆる機会を利用して、高価な処理を短絡させましょう。これにより、エンドユーザーにより高速なエクスペリエンスを提供できるだけでなく、アプリケーションの運用コストも削減できます。

Momentoのリモート集中型の特性を活用することで、サーバーレス・バックエンドやその他の分散アプリケーションを最適化できます。どの実行環境や負荷分散されたサーバーがリクエストを拾っても、共通のキャッシュを共有し、データへの高速かつ容易なアクセスを提供します。

データベースキャッシュ

しばしば「データをキャッシュする唯一の場所」と考えられていますが、データベースは通常、データをキャッシュする最後の機会です。データベースはアプリケーションの主力であり、データベースから仕事を奪う機会があれば、そうすべきです。

リード・アサイドライト・アサイドリード・スルーライト・スルー・キャッシングのような戦略はすべて、疲弊したデータベースにストレスを与えないための素晴らしいアプローチです。最も一般的なキャッシュの実装はリードアサイドキャッシュで、データフェッチはデータベースにアクセスする前にキャッシュに問い合わせます。データがキャッシュに見つかれば、すぐに呼び出し元に返されます。見つからない場合は、データベースからフェッチされ、キャッシュに入力された後、呼び出し元に返されます。

書き込み側では、Amazon DynamoDBやDocumentDBのようなデータベースは、データ変更の結果としてストリームを提供するため、ほぼリアルタイムのキャッシュ更新メカニズムを構築することができます。レコードにデータが書き込まれるたびに、データはストリーム出力され、キャッシュ内で更新されます。

DynamoDBには、リードスルーとライトスルーを提供するDAXというキャッシュ・オプションがあります!しかし、DAXには対処すべき問題があります。DAXはプロビジョニングされたサービスであり、コンシューマは独自のキャッシュ・クラスタを構成、拡張、維持する必要があります。DAXの設定を理解し、キャッシュクラスタの適切なサイズを知るには、専門家レベルのスキルが必要で、それでもうまくいかないかもしれません!これに対してMomento Cacheは、即座の可用性、弾力性、そして数分で運用を開始できる従量課金制を採用しています。

まとめ

多くの異なるレイヤーでキャッシュを行うことで、アプリのパフォーマンスと効率を向上させる機会が数多く得られます。クラウド時代において、少ないコンピュート数は少ないコストを意味します。つまり、エンドユーザーにより高速なエクスペリエンスを提供するだけでなく、余分な支出キャッシュ(私が何をしたか分かるだろう)を財布に残すことができるのです!

これを読んだ後、あなたは突然、どこにでもキャッシュを実装する気になったことでしょう。ただ、キャッシュする前に考えることを忘れないでほしいのです。キャッシュの無効化は難しく、データの適切な保存期間を設定することは、時として正確な科学のように感じられることがあります。

まずは1つのレイヤーから始めましょう。そのレイヤーがどのように機能するのかを理解し、ユーザーがあなたのアプリとどのようにやりとりするのかを知りましょう。そのレイヤーに慣れたら、別のレイヤーを追加しましょう。そのレイヤーに慣れたら、また別のレイヤーを追加していきましょう。

何から始めたらいいのでしょうか?データベースキャッシュを使えば間違いありません。アプリケーションにキャッシュを実装するためのMomentoのステップバイステップのチュートリアルを試してみてください!