ここまでの連載で、AWSバックボーンネットワークの裏側、EC2イベントへの対応やDesign for Failureについてお話してきました。
私の担当回では、AWSという巨大な分散システムを支える技術要素のうち、非常に重要なアーキテクチャ設計、プログラミング技術のいくつかについて見ていきたいと思います。これらは、AWSの内部を支える技術でもありますが、皆さんのアプリケーションをダウンタイムゼロのシステムに近づけるための基礎技術、クラウド・ネイティブなアプリケーションを構築する基礎的なテクニックのヒントにもなると思います。
具体的には、下記の4つをご紹介します。
- 非同期処理(Asynchronous process)
- リトライ(Retry with Exponential Backoff and jitter)
- 結果整合性(Eventual Consistency)
- 冪(べき)等性(Idempotency)
本記事では、非同期処理について解説します。
24時間365日計画停止もダウンタイムもないシステムを作るために
何かプログラムを作成しようと思ったとき、まずは、「そのプログラムで実現したいこと(要件)」を機能として実装し、とにかく「動くもの」を作りますよね。Webサービスであれば、1台のサーバー上に1つのデータベース、1つのWebサイトをもったシステムをモックアップとして作成します。
このモックアップが、どんな負荷にも耐え、物理的な故障が起きても自動で復旧することができれば幸せですが、サーバーやネットワークはダウンすることがあり、現実的に本番サービスとしてリリースする前には、システムを安定稼働させるために、さまざまな制約や単一障害点(Single Point of Failure)がないかなどを考慮しなければなりません。
インフラ的な視点から、Webサービスを構成するコンポーネントごとの冗長性を持たせるために、負荷分散装置を設ける、Webサーバーを複数立てる、データベースのレプリカを作成するなどの対策を講じることは可能です。しかし、それだけでダウンタイムゼロのシステムが実現できるわけではありません。ダウンタイムゼロのシステムを作成するには、アプリケーションプログラム側で、これらのインフラを適切にハンドリングできるような設計にしておく必要があります。
例えば、可用性を向上させようとして、図1の「Production#1」のように、単純にApp+DBの組をそのまま複数持たせてみると、それぞれのアプリケーションは自身に対応するデータベースにのみデータを書き込むことになるため、当然ながら、データベース間のデータはバラバラで同期されません。
そこで、「Production#2」のように、データベースのレプリケーションを加味して構築してみます。これはマスターデータベースがダウンしても、他データベースが処理を引き継げる(フェールオーバー)ので、一見、完璧なようにも見えます。しかし、厳密に言えば、フェールオーバー時にわずかなダウンタイムが発生し、サーバー間の通信がダウンする可能性があります。さて、こうしたタイミングではアプリケーションはどう振舞えばいいのでしょう。