ハロウィーンはもうすぐそこです。不気味なエンジニアリング・ゴースト・ストーリーに備えましょう。
数年前、私はある大企業でソフトウェア・エンジニアとしてビデオ・ストリーミング・サービスを構築していました。最初の顧客は大手プロスポーツリーグで、私たちのサービスを使って週に一度、何百万人もの視聴者に試合のライブストリームを放送する予定だでした!
私たちがこのプロジェクトに参加したとき、私たちのサービスはまだ存在していませんでした。しかし、リーグの放送スケジュールは確かに存在していました。 🙂 開始日は確実で、サービスは私たちに送られるすべてのトラフィックを処理できなければなりませんでした。
ここから怖い話が始まるのか?いや!私たちには素晴らしいエンジニアリング・チームと、自分たちが信じるアーキテクチャ設計がありました。スケジュールはタイトだったが、発売日を守れると確信していた。私たちは頭を下げて仕事に取りかかりました。
初回放送の数週間前、私たちはかなり調子が良かったのです。いくつかの仕上げを除いて、サービスは構築されていました。チームは、サービスが試合時のトラフィックに耐えられるかどうかを確認するための負荷テストの追い込みに入っており、すべてがいつもどおりでした。
しかし…
顧客から初めて現実的なサンプルデータセットを入手し、それを負荷テストに組み込んだのです。しかしスムーズにはいきませんでした。予算と保存するデータ量の見積もりに基づいて、DynamoDBの最大読み取り/書き込み容量を設定しました。しかし、負荷テスト中に、その容量を大幅に超え、DynamoDBのスロットルにぶつかっていることがわかりました。サービスは失敗しました。大変です。
Be afraid. Be very afraid.
あーあ。初回放送まであと数週間だが、大きな問題が発生しました。私たちのアーキテクチャ設計では、放送を見ている視聴者一人一人がストリームのどこにいるかを追跡するために保存する必要があるデータがありました。このデータはDynamoDBに保存することに決めていました。放送局から送られてくるトラフィックを調査した結果、各視聴者のペイロードのサイズが、私たちの見積もりの10倍まで大きくなる可能性があることがわかりました。そのため、DynamoDBで10倍のIOPsと10倍のコストが必要になりました!
私たちのワークロードは非常に書き込みが多く、観測されたデータの10倍増に基づくいくつかの計算では、Dynamoに保存すると予算を大幅にオーバーすることが明らかになりました。これらのデータはエフェメラルだったので、DynamoDBからキャッシュ・サーバーに移動できると判断しました。私たちは選択肢について素早く調査し、マネージドRedisソリューションを進めることにしました。
マネージドRedisサービスには、キャッシュクラスタ内の個々のノードのプロビジョニングと運用を明示的に担当しなくて済むという利点があります。しかし、キャッシュ・クラスタに必要なノードの数とその規模を決定する責任は明示的にあります。
次のステップは、Redisクラスターにかかる負荷をシミュレートするコードを書き、それを何度も何度も実行することでした。さまざまなサイズのノードをテストしました。異なるクラスタサイズをテストしました。異なるレプリケーション構成をテストしました。テストを繰り返しました。何度も。
キャッシングクラスターのサイズを決めるために合成負荷テストを書くことは、エンジニアリング計画では想定していなかった作業でした。キャッシュノードのサイズ(とタイプ)を変えて実験したり、テスト実行中に過負荷にならないように監視したり……これらの作業はお金と時間がかかり、私たちが構築しようとしているサービスの実際のビジネスロジックにはほとんど付随するものでした。どれも私たち独自のものではありませんでした。しかし、それでも貴重なエンジニアリング・リソースを割かなければなりませんでした。
1週間後、私たちはクラスタのサイジングとコンフィギュレーションに釘付けになりました。さらに1週間後、コードの一部をDynamoからRedisクラスタに移行する作業が完了しました。
そしてサービスは再開されました。
It’s alive! It’s aliiive!
やったよ!最初の放送はスムーズに行われました。どんな大きなソフトウェア・プロジェクトでもそうであるように、現実世界での動作を観察した後、私たちはいくつかの教訓を学び、改善すべき点を見つけました。その後、いくつかの改良を施し、気がつけばシーズンが始まっていました。勝利です!
しばらくの間は・・・・
シーズンが始まって約1カ月後、私たちはAWSの請求書を受け取りました。私たちを驚かせたと言っても過言でありませんでした。請求書は…巨大でした!一体何が起こったのでしょう?
家の中からだ!
私たちのアーキテクチャー上、DynamoDBからの請求が最も大きくなることはわかっていました。しかし、私たちはDDBの容量制限に基づいてそのコストを合理的に見積もっていました。では、なぜAWSの請求額が高かったのでしょうか?
その原因はRedisクラスタにあったことが判明しました。今にして思えば予測できたことですが、私たちは納期に間に合わせるために確実に稼動させることで精一杯で、計算する時間がありませんでした。
試合中のピーク時のトラフィックの要求を満たすために、放送を行うすべての地域に90ノードのクラスタを作成することを余儀なくされました。さらに、各ノードには投入するすべてのデータを保存するのに十分なRAMが必要で、非常に大きなインスタンス・タイプが必要でした。
この場所には幽霊が出るのか?
必要な量のRAMを提供する非常に大きなインスタンス・タイプは、たまたまvCPUの数も多かったのです。Redisはシングルスレッド・アプリケーションであるため、クラスタ内の各ノードで1つのvCPUしか利用できず、残りのvCPUはほぼ100%アイドル状態になります。
つまり、16VCPUの大きなインスタンスに大金を払い、その1つ1つが使用可能なCPUの約6%以上を使わないことが保証されていたのです。信じられないかもしれないが、これは最悪の事態ですらなかったのです。
スポーツ中継中に発生するピークトラフィックは、それ以外の時間帯のトラフィックを凌駕していました。そのため、試合中は十分に活用できていない馬力にお金を払わなければならなかっただけでなく、毎週スポーツイベントを放送している3時間以外の時間帯は実質的に利用率が0%であるにもかかわらず、1日24時間、週7日、Redisクラスタにお金を払っていたのです。
そしてシーズンが終わり、6ヶ月間スポーツ中継がなくなりました。そのため、これらのクラスタは24時間365日の稼働率が約0%になりました。
わかった。問題は解決しました。あとはそれを解決して、クラウド料金を抑えるだけです!
ゾンビの大群…エンジニア!
Redisクラスタの使用量を修正するのは、言うは易く行うは難しでした。マネージドRedisサービスには、クラスタをスケールアップしたりスケールダウンしたりする簡単で安全な方法がありませんでした。また、Redisクライアントはクライアント側でキーのシャーディングを処理するため、いつでも利用可能なサーバーのリストを把握しておく必要があります。つまり、クラスタの増減は移行中のキャッシュ・ヒット率に影響を与えるリスクが高く、非常に慎重に管理する必要がありました。
これらは解決可能な問題でした。十分な数のエンジニアを投入すれば、何でも可能なのです。スケーリングイベント中に2つの異なるクラスタに書き込みを行い、移行中のキャッシュミスのために新しいクラスタから古いクラスタに読み込みをフェイルオーバーするように、すべてのコードを更新することができました。そして、ピーク時のトラフィックに必要な巨大なRedisクラスタと並行して、2つ目の小さなRedisクラスタを追加することでスケールダウンできます。新しいクラスタをオンラインにする間、新しいコードの挙動を入念に監視し、古いクラスタの撤収をいつ始めても安全か判断します。そして、古いクラスタの撤収をいつ始めても安全かどうかを判断することもできます。
スポーツ中継の準備のために規模を拡大する必要があるときと、イベント終了後にコスト削減のために規模を縮小する必要があるときです。
しかし、それは膨大な作業になります。エンジニアに支払う金額と、オーバープロビジョニングされたRedisクラスタに支払う金額を比較する必要がありました。
このクラスター・スケーリングの無意味さには、私たちにとって独自のビジネス価値はなく、私たちのビジネスに独自の機能を提供し、私たちのユーザーに実際に顧客と接する価値を提供するために働けるエンジニアの数は限られていました。
私たちがどこに降り立ったか、想像できるでしょうか?そう。私たちは、エンジニアが実際にビジネスを前進させ、新しい顧客を獲得できるようなプロジェクトなど、もっと価値のある顧客プロジェクトがたくさんあったのに、この問題を解決しようとするためにかかるエンジニアリング・コストを正当化できるようなポイントには到達できませんでした。
だから私たちはお金を払い続けました。使っていないものに。
ある時点で、もし私たちのビジネスが苦境に立たされていたら、支出を減らして予算を均衡させるために、エンジニアのリソースをこの問題の解決に割かざるを得なかったかもしれません。しかし、これは私たちが困っているというサインだったでしょう。
あなたのチームがクラウドサービスにお金を使うことについて、あなたがどう感じているかは知らないが、私はクラウドサービスが、あなたが実際に使っているものに対して正当な金額を支払い、眠っているリソースに大金を支払わないような正当な請求書を得ることを非常に複雑にし、あなたが絶望的な状況に陥った場合にのみ、そのための時間を作ることができるようになることを、とても恐ろしいことだと考えています。
クラウドサービスプロバイダーにとっては素晴らしいビジネスモデルです。顧客にとっては素晴らしいビジネスモデルではありません。
こうである必要はないのです。
Momento Cache: All treat, no tricks!
あなたが今読んだ恐ろしい物語は、私たちがMomentoのサーバーレス・キャッシング製品を構築するためのインスピレーションの大部分でした。サーバーレス・クラウド・サービスの最も優れた点の1つは、使用した分だけ支払うという公平な価格設定モデルです。なぜキャッシングでそれ以下の価格に落ち着く必要があるのでしょうか?
Momentoでは、キャッシュとの間で送受信するバイト数に厳密に基づいた、極めてシンプルな価格ポリシーを採用しています。私たちは、これらのバイトがすべて3時間以内に転送されたり、1週間や1ヶ月の間に均等に分散されたとしても、より多くの料金を支払う必要はないと考えています。私たちが懸念しているのは、必要なときにキャッシュの読み書きができればいいということです。それだけです。単純明快です。
もちろん、サーバーレスはそれだけにとどまりません。バックエンドの厄介なことはすべて私たちが管理します。トラフィックが増加してキャッシュの容量が必要になっても、それは私たちの責任です。トラフィックが減少した場合、トラフィックの少ないウィンドウにトラフィックの多いウィンドウと同じ金額を支払う必要はありません。また、より多くのRAMが必要になったからといって、キャッシング・クラスターの多数のノードのアイドル状態のCPUコア15個分の料金を支払う必要はありません。
クラウド・サービスに騙されて、使っていないキャッシュ容量にお金を払うのはやめましょう!キャッシュは5分以内に無料で作成できます。5分以上かかる場合は、ハロウィーン・キャンディーをお送りしますので、お知らせください。
まずはスタートガイドをご覧ください。また、料金のページでは、お支払いいただいた料金に見合ったサービスをご提供しています。
Happy Halloween! 👻