MY Scribbling

AWS HERO Masanori Yamaguchi の雑なメモ

The Amazon Builder’s Library "Reliability, constant work, and a good cup of coffee" を読んでみた

The Amazon Builders' Library をご存知でしょうか? re:Invent 2021 においても、新しくリリースされたサービスではありませんが、キーノートで触れられています。

aws.amazon.com

今回は 「Reliability, constant work, and a good cup of coffee」 という記事について取り上げてみたいと思いますが、この記事には、アーキテクチャ図は一切ありません。読み物として書かれています。

Builder’s Library で Architecture タグがついているのに、アーキテクチャ図がないということにとても興味が湧き、読み進めてみたのですが、とても面白かったので感じたことを記録として残しておきます。

aws.amazon.com

ざっくり書くと、エドワードホッパーの「ナイトホークス」という絵画をきっかけに、コーヒーポットがいかにニーズに沿ってシンプルでコスト低でかつ信頼性あるツールなのかというところから、AWSでは信頼性の高いシステムどのように実装しているのか、その設計について解説している話です。

re:Inventをはじめ、日本のカンファレンス、イベントなどの休憩時間に設置されるエンジニアとは馴染み深いコーヒーポット、YAPC::Asiaでは無限コーヒーなど呼ばれていたことを思い出します。やはりエンジニアにコーヒーは必要なのかという点もこの記事を読み始めたきかっけでした。

以下、本題。

Computers: They do exactly as you tell them

システムの信頼性を落とす要因は「不確実性」

信頼性の高いシステムを運用している場合、不確実性が最大の課題。不確実性は障害などによって引き起こされ、結果そしてシステムは高負荷や不安定な状態となり、処理停滞などを発生させる。

コーヒーショップの場合、対応が遅いことによる処理停滞は顧客の待ち行列となるが、システムの場合は物事はシンプルではない。処理停滞はクライアントやバックエンドへの再リクエストによってスパイラル的に影響を拡大する可能性がある。

再リクエスト、過負荷への対応は別の記事がある。(これらの記事も後日で読もうと思う)

Timeouts, retries, and backoff with jitter
https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/

Using load shedding to avoid overload
https://aws.amazon.com/builders-library/using-load-shedding-to-avoid-overload/

「This is why many of our most reliable systems use very simple, very dumb, very reliable constant work patterns.」

信頼できるシステムはシンプルに一定の処理を提供する。re:Invent 2021のキーノートでWernerが話していたPrimitiveに繋がるのかもしれない。複雑な処理もPrimitiveの組み合わせで実現されるとうことWernerの言葉を思い出す。

信頼性の高いシンプルなシステムは3つの要素で構成される

  • 負荷によってスケールアップや処理遅延しないこと
  • どのような状態でも同じ動作をすること(モードがないと表現されていた)
  • もっとも必要な時にパフォーマンスを向上させること

キャッシュは応答時間を改善するが、キャッシュはキャッシュが存在している時と、存在していない時モードがあると説明されていた。キャッシュが存在していなかったり無効化された場合、システムに対する負荷は存在している時と一定にならないということ。

キャッシュだけを当てにするとキャッシュが効かない状態ではソースとなるシステムに負荷がかかり予期せぬ障害が発生可能性があるかもしれない、これがモードによる影響であることが説明されている。

なお、キャッシュに関する考えはこちらを参照することも記事内で触れられている。

Caching challenges and strategies
https://aws.amazon.com/builders-library/caching-challenges-and-strategies/

Amazon Route 53 health checks and healthiness

ヘルスチェックはとても重要な機能であるということが Route 53 のヘルスチェックをテーマに「モード」「一定の処理を繰り返しおこなうこと」について解説されている。

Route53がヘルチェックのノイズ影響をどのように対応しているか、ヘルスチェッカーによるチェックとその結果をアグリゲーターが条件付けして判定している。ヘルスチェッカーとアグリゲーターはまさに一定の処理を行う「Constant work」に徹している。

ヘルスチェッカーとアグリゲーターはセル設計が採用されていて、新しいヘルスチェック対象が追加されても影響がないように設計されている。各セルで処理できるヘルスチェック数の制限と現在の数を確認していて、制限が近づいたら新しいセルが追加される。

また、アグリゲーターは常に最大サイズのヘルスチェック結果を受け取るようになっている。最大サイズの至らない場合は、ダミーで埋めて常に最大サイズがヘルスチェッカーから送られ、それによって負荷が一定になるように作られている。

ヘルスチェックの対象がAZ障害などで一度に大量のヘルスチェック失敗を返してもヘルスチェックーとアグリゲーターが行う処理は変わらないということが大事な点だと思う。

続いて、ヘルスチェックに失敗した場合の、DNSレコード変更について触れられている。

何万のヘルスチェックが同時に失敗した場合、何万以上のDNSレコード変更が一気に行われる可能性があるが、どのように対応しているのかという点が興味深い。

アグリゲーターは、固定サイズのヘルスチェックステータスを数秒感覚でDNSサーバに送っている。DNSサーバは受信してメモリに保存する。アグリゲーターよりも多いDNSサーバがプッシュを受けれるようにしている。

DNSサーバはクエリに対して、その名前に紐づく全てのレコードを検索して、メモリ内のヘルスチェックステータスと相互参照する。ヘルスチェックのステータスが正常どうかにかかわらず、毎回のヘルスチェックステータスを参照しているので動作が変わらないということがポイント。

モードとは何か、モードが存在しないということの重要性を丁寧に説明されている章だった。

Amazon S3 as a configuration loop

Network Load BalancerはEC2ネットワークに組み込まれているAWS Hyperplaneノード上で実行されている。Network Load Balancerの設定は、Amazon S3上に保存されている構成ファイルによって扱われ、AWS Hyperplaneノード が Amazon S3から設定ファイルをフェッチする。設定変更がされていない場合でも数秒ごとにフェッチして、AWS Hypervisorノードは設定が前回と同じであってもロードする。

これにより、モードは1つで常に最大数の構成変更のロード処理を実行している。設定変更されたロードバランサーの台数による影響は受けない。

構成ファイルも「ダミー」により、最大サイズになっている。

無駄を感じるかもしれないが、とてもにシンプルで複雑な構成を実現するよりも、エンジニアリングコストが最低限に抑えられている。(初期の実装もメンテナンスも) ロードバランサーの機能拡張による影響も受けにくいし、設定変更処理がボトルネックになる可能性が排除されているものだと感じた。

Constant work and self-healing

前述された2つの例は、何かしらの処理失敗があったとしても自己回復を備えている。Constant work Constant work には自己回復が伴う傾向があるということ。

1回目の処理でネットワーク問題などで設定情報が破損した場合、2回目の処理で正常化される。Consitent workはモードを持たないので、常にゼロベースの処理が実行されるため、回復性を備えている。

対照的にワークフローの場合、ワークフローの処理順序、一部の処理でエラーが発生した際の回復処理などをあらかじめ組み込んで置く必要がある。

回復処理がまた動かない時に結果として人が介在しなければいけないし、それはConstant work で継続的なエラーが発生している場合も同じなのだけど、準備にかけるリソースが全く異なるということも伝えているのだと感じた。

Design and manageability

big-O と Constant work の関係性、つまり入力サイズに関係なく、一定数の処理を行うということ。Route 53 、Network Load Balancer においても、ユーザの設定変更量に変わらず、一定数の処理が実行されていることが説明されている。

ただ、懸念する点は、無駄が生じるということ。(コーヒーポットに数百人分のコーヒを入れた結果、飲む人が数人の場合、残りは排水溝行きになると表現されている)

この懸念は構成変更、ヘルスチェックのようなプロパゲーションシステムでは現実にならない。1つのヘルスチェックを伝播することと、多くのヘルスチェックを伝播することによる消費エネルギーのコストはほぼ変わらないため。ピーク時に100台のWebサーバが必要とするシステムに対し、常時100台のWebサーバを用意することは同義ではない。これはサーバ1台あたりのコストと伝播するヘルスチェックとのコスト比較になる。

コスト削減、さらにSutainableであることを考えると、スケーリングを第一に考えてしまうが、スケールアップによる影響が細微な場合は、シンプルな設計を用いた方がコスト低になるということも念頭に置いてアーキテクチャを設計することが必要。

The value of a simple design

シンプルな設計とは、パーツの少なさではない。わかりやすく、使いやすく、オペレーションしやすい設計を指す。(一輪車は自転車よりもパーツが少ないが乗りにくいと例えられている)

そのデザインが、その立ち上げに全く関係ないチームにとっても意味をなすものであれば、それは良いデザインである可能性が高いということも触れられている。

現にAWSでも"ループの中で毎回フルコンフィグレーションを適用する“というコンフィグレーションシステムは意外と多くConstant workは何度も再利用されていると説明されている。

さいごに

今まで考えたことがなかった内容が多く、アーキテクチャを考える上で読んでおいて良かったと思える記事でした。

Builder’s Library は必要になった時に参照することにも使えますが、時間がある時などに読んでみても良いヒントを得られるのでおすすめです。

日本語化されている記事もありますので、AWSがその中で培ってきたアーキテクチャをみなさんもぜひ活用してみてはいかがでしょうか。

aws.amazon.com