はじめに
Cache-as-a-Serviceとして市場に新しく参入したMomentoから、彼らのテクノロジーを評価し、記事にするよう依頼されました。私はAmazon Web Service (AWS) Data Heroとしてオープンマインドで参加しています。私はAWS ElastiCache for Redisをキャッシュプロバイダーとして愛用しています。Momentoが登場したことで、私は彼らをチェックアウトし、彼らがどれほど速く、安く、そして優れているか?この記事を書くにあたって、Momentoチームと素晴らしいコネクションを築き、#CacheTheWorldというミッションに参加したことを除けば、私は何の報酬も受け取っていません(まあ、タンブラーを十分な報酬とみなさない限りは)。このブログでは、MongoDBでMomento Cacheをセットアップした最初の感想を共有しようと思います。
最初から、キャッシュをセットアップするのに必要な儀式がはるかに少なくて済むと主張できます。私が望むことのひとつは、RedisやMemcachedと同じAPIを持つことで、企業がコードを変更することなく、あるいは最小限の変更で移行できるようにすることです。
しかし、研究によれば、ウェブサイトでの2秒の待ち時間は、顧客を他の場所に移動させる可能性があります。このような研究によって、マーケティング・マネージャーは夜も眠れなくなり、その結果、開発チームはさらなる技術革新を推し進めることになります。ソフトウェア部分を最適化した後、彼らはデータベースを顧客に近づけることに頼ります。データベースの強化が終われば、次はキャッシュが最大の時間節約になるでしょう。ウェブサイトが複雑化するにつれ、ブラウザーエンジンは動画、グラフィック、プラグイン、広告トラッキングツールで溢れかえり、懸命に働いています。
主要なクラウド・プロバイダーは他にも多くのことを抱えているため、Momentoはレイテンシーを可能な限り削減しながらキャッシングを行うことだけに特化しています。クラウドベースのプロバイダーでありながら、すべてのハイパースケールクラウドとそれぞれのエッジロケーションに存在感を示しているため、キャッシングの背後にあるレイテンシを最小限に抑えることができます。これは、オンプレミスのサービスを持っているが、クラウドに移行できない企業や、リスクを避け、クラウドにとらわれない、あるいはマルチクラウドという考えを持つ企業にとっては画期的なことです。
典型的なクライアントとサーバーのセットアップ
もし私が、個人ブログやニッチ向けのウェブサイトなど、継続的な変更がほとんどないウェブサイトを構築するのであれば、AWSですべてを運用するでしょう。もし私が、ウェブサイトが低レイテンシーで無限のアップタイムを必要とする一方で、単一プロバイダーのリスクを抱えることに汗をかくクライアントにアドバイスするのであれば、1つのクラウドプロバイダーにフェイル・フェイル・オーバー(誤字ではありません!)をさせながら、複数のベンダーに痛みを分散させることを勧めるでしょう。
MACHアーキテクチャー(マイクロサービス、API、クラウドネイティブ、ヘッドレス)は、最近のほとんどの近代化されたウェブサイトで典型的なものです。マイクロサービスは、1つ、いや2つのことを行う小さなプログラムです。APIとは、私たちがやりとりするURI/URLエンドポイントです。クラウドネイティブとは、クラウド、オンプレム、ハイブリッドのどこででも動作することを意味します。コマンドラインインターフェイス(CLI)経由でHeadlessとして実行するか、APIの前にUIベースのフロントエンドを構築するかはオプションであり、クライアントは独自に開発するか、オープンソースのツールを使うか、サードパーティの統合ツールを使うことになります。
さて、このレベルの詳細で武装して、仮想のウェブサイトと、それを運用するツールを考えてみましょう。
やってみる
私は、Amplify、DocumentDB(MongoDBと互換性がある)、Lambda、API Gatewayを使って、Amazon Web Services(AWS)でホストされたウェブサイトを運営しています。ウェブサイトのリクエストは、まずAPI Gatewayのエンドポイントを経由し、次にLambdaに渡されます。そしてLambdaはDocumentDBに問い合わせ、データが戻ってくるのを待ち、戻ってきたらAPI Gatewayを通してパッケージ化されたレスポンス(JSON)をHTTPレスポンスとしてAmplifyウェブアプリに渡します。どうすればリスク回避とクラウドにとらわれないことができるかを考えてみましょう。
技術リーダーとして、私はシステムが大きな停止を起こすことなく、可能な限り最適化された状態で稼働していることを保証したいと考えています。クラウドでは、アクティブ-アクティブのセットアップを作成することができるが、それは非常に高価であり、DynamoDB以外のAWSデータベースは、リージョン障害が発生した場合にクラウドのリージョンから別のリージョンにシームレスに移行する機能を持っていません。技術チームが介入し、アプリを別のリージョンを指して再び稼働させるために手動で設定を変更する必要があります。このプロセスには時間がかかり、ビジネスの復旧時間の目標を達成できないリスクがあります。
Database
前述の通り、私たちはDocumentDBをトランザクションストアとして使用しています。DocumentDBは、フェイルオーバー、レイテンシー、そして極めて高い耐久性という点で独自性を発揮することができますが、サードパーティプロバイダーに委託することでリスクを軽減したいというビジネスニーズがあります。DocumentDB APIはMongoDBの現行バージョンと100%互換性があるので、私たちはデータベースをMongoDB Atlasという専門のクラウドデータプロバイダーに移行することができます。Atlasは、複数のリージョンで、複数のクラウドプロバイダーにフェイルオーバーできる素晴らしい機能を持っています。Google Cloudがダウンしても、MongoDBはデータベースをAWSやAzureにフェイルオーバーできます。私たちはMongoDBをトランザクションデータストアとして使うことができ、フェイルオーバーが約束通りに機能し、リスクはMongoDBのチームに引き継がれることを知っているので、夜も安心して眠ることができるのです。
今回は、特定のクラウドに縛られないクラウドベースのデータベース・プロバイダーを使ってみました。次に、やはり特定のクラウド・プロバイダーに縛られないキャッシュ・サービス、Momentoと結果を比較してみましょう。
100MB/secのインターネット接続の後ろにあるラップトップから、MongoDBから複雑なデータセットを取得するためにMomentoを使用することで、どのくらい時間が節約できるかを確認しましょう。まず、Githubの認証情報を使って無料のMongoDB Atlasアカウントにサインアップします。https://cloud.mongodb.comからセットアップを開始します。クレジットカードは必要ありません。MongoDBは、クエリに使用できる一連のコレクション(データベース)を提供しています。私は、集計作業が必要で、検索に時間がかかるデータを探していました。
私は、アトラスのサブスクリプションに含まれているsample_analyticsコレクションからデータを戻し、groupキーワードを使ってトランザクションテーブルから情報を取り出し、個人が特定の銘柄を購入したトランザクションを探すことにしました。
['sample_analytics']['transactions'].aggregate([
{
'$unwind': {
'path': '$transactions'
}
}, {
'$match': {
'$and': [
{
'transactions.transaction_code': 'buy',
'transactions.symbol': 'adbe'
}
]
}
}, {
'$group': {
'_id': '$_id',
'transaction_item': {
'$push': '$transactions'
}
}
}
])
ところで、MongoDBのプログラムがなぜ動かないのか不思議に思っている人は、AtlasのウェブUIの「セキュリティ」>「ネットワークアクセス」で、あなたのいるIPからデータベースへのアクセスを許可する必要があるかもしれない。私は、なぜデータが戻ってこないのかと何度も悩まされました。
MongoDB UI と pymongo ライブラリを使った Python プログラムで動作したら、Momento のセットアップに進みます。Momentoのセットアップはとても簡単です。4~5行のコマンドを必要とする新しい何かを実行させるサービスを私は知らないので、同意できない場合は私に知らせてください。ユーザ名としてあなたのEメールを使い、’Getting Started’ページに従って、あなたのマシンにMomento CLIをインストールすることができます。あなたのMomentoアカウントは、文字通り数秒で起動し、実行することができます。
次に、PythonをMomentoと連携させます。GitHubのリポジトリからプログラムを引っ張ってきて、キーバリューの作成と読み取りのテストを行います。Momentoがセットアップ中にメールで送ってきた認証トークンを使う必要があります。その気になれば、Momentoを単純なデータベースとして使うこともできるが、キャッシュ・エントリーの有効期限が切れるたびにシードする必要があります。
Pythonプログラムを使用してMomentoをテストした後、2つのアクセス・パターンを1つにまとめる時が来ました。キャッシュされたデータがより高速であると仮定して、データを取得するアプローチを決定する必要があります。データベースがその場でデータを集約しようとして CPU サイクルを消費しているのに対して、キャッシュサービスはキーを検索して単純な値を返すだけなので、そうならざるを得ません。
監査役が会社の従業員の最近の取引を見ることができるサービスがあるとします。会社によっては、インサイダー取引の疑いを避けるために、従業員による株式取引が監視されています。データは更新されるが、それほど頻繁に更新されるわけではないので、データが古くなることはないと考えられます。
Running Python
SKIP_CACHEフラグをTrueにして作成したプログラムを使うと、MongoDBから同じレコードを10回取り出すのに約5秒かかります。
私の遅いインターネット・スピードで計算すると、5秒で10回。CSS、JavaScript、ブラウザエンジンの速度、インターネットの速度、デスクトップパソコンの速度、そしてもちろんサーバーのネットワーク遅延と帯域幅…心配しなければならないボトルネックが山ほどあります。しかし、私たちはもっと早くデータを取得することができます。
New code sequence
キャッシング・サービスを使ってデータを取得する一連の流れを把握する必要があります:
1.ユーザーがウェブサイトにログイン
2.ユーザーがティッカーシンボルを検索
3.プログラムはまずMomentoを見て、ティッカーがキャッシュに保存されているかどうかを確認する。キャッシュ名は”-“パターンを使うか、実際の例で言うと、adbe-buy, amzn-sell, msft-sell, goog-buy。これがMomentoのキャッシュキーになる。
4.このキーが Momento にない場合は、MongoDB Atlas から取得します。MongoDB Atlasからデータを取り出したら、Momentoに保存する。
5.キャッシュキーが検出したデータが Momento に保存されていれば、結果をユーザーに返す。
最初の1回で、キーはMomentoに保存されます。そして、さらに9回にわたってそれを取り出します。所要時間は3秒強です。
2 回目では、Momento のみから 100% のデータが取得され、3 秒未満にかかることが確認されました。最大 3 秒まで平均すると、リクエストごとに 0.3 秒になります。毎回データベースからデータを取得する場合と比較して、処理時間が 40% 削減されます。
GitHub repository
このロジックは、GitHub リポジトリ (async-main.py) の Python プログラムに記述しました。試してみて、私の数値が少しずれていると感じたら、また報告してください。
結論
クラウド ハイパースケール製品も素晴らしく堅牢ですが、管理すべき構成とセキュリティの問題が常にあります。どのようなネットワーク トラフィックが予想されるかを把握し、予想されるトラフィックの急増に合わせてキャッシュ サービスを調整する必要があります。どちらにしても予期せぬことが起こったらどうなるでしょうか?トラフィックが少ない期間にキャッシュ サービスを拡張しすぎると、損失が発生したり、Web サイトのデータの読み込みに時間がかかりすぎて顧客を失ったりする可能性があります。
Momento は、キャッシュ サービスの管理や拡張の必要性を軽減し、技術的負債など、より重要なことに集中しやすくすることを目的としています。クラウドにいない人もいるかもしれません。したがって、Momento は、オンプレミスのデータベースを停止させる必要性を最小限に抑え、トランザクション ログが爆発してディスク領域が飽和するのを防ぐ優れた代替手段となり得ます。DBA は皆、この問題に頻繁に対処しすぎていることを私は知っています。
現在のソリューションにコストや遅延に関する懸念があり、キャッシュが役立つと感じている場合は、Momento を試してください。チームには助けてくれる素晴らしい人たちがいます!
Python Notes
Python は多くのデータ指向ショップで使用されているほぼ普遍的な言語であるため、私は Python を使用しています。このブログを書き始めたときは Python 3.9 を使用していましたが、最後の仕上げとして Python 3.11 を使用することにしました。わかりにくいことなく、エラーが何であるかをすぐに教えてくれます。たとえば、プログラムを開始するとき、リクエストを検証するためにコマンドに認証トークン変数を追加する必要があります。
$ python async-main.py
上記は以下を戻します。
...
File "/Users/rob.koch/Library/Python/3.11/lib/python/site-packages/momento/_momento_endpoint_resolver.py", line 26, in resolve
return _getEndpointFromToken(auth_token)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/rob.koch/Library/Python/3.11/lib/python/site-packages/momento/_momento_endpoint_resolver.py", line 37, in _getEndpointFromToken
raise errors.InvalidArgumentError("Invalid Auth token.") from None
momento.errors.InvalidArgumentError: Invalid Auth token.
このコマンドを実行しただけで、問題が何であるかがすぐにわかり、次のように認証トークン変数を渡してコマンドを実行する必要がありました。
$ DEBUG=true \
MOMENTO_AUTH_TOKEN=* \
python3 async-main.py