そーだいなるらくがき帳

そーだいが自由気侭に更新します。

障害から学ぶクラウドの正しい歩き方について考える

 AWSで大きな障害が発生したこの機会に、自分がクラウドと正しく付き合っていくために必要なことを考える。

piyolog.hatenadiary.jp

 ちなみに稼働率 99.99% くらいを目指していくために必要な事を考える。

必要な稼働率を見極める

 今回は 99.99% くらいを目指すと言ったが、実際に自分たちにとってどのくらいの稼働率を目指すか?ということはとてもとても大切だ。

 幸い、今回自分は影響がなかったが、本当に完璧か?と言われるとそうではない。 まず弊社の場合、マルチリージョンではないので東京リージョンが落ちたら落ちる。 これを許容できない場合に99.99%を目指せるか?というと正直厳しい。

 しかしサイトの規模はそんなに大きくないのでデータサイズも現実的に転送出来る範囲で、コンポーネントも少なく、TerraformやAnsibleによって再構築しやすい状態は整っている。 そのため東京リージョンがある日、消滅しても再構築はしやすい。 その再構築の時間を許容できる範囲かどうかで本当の稼働率が決まるが東京リージョンが消滅した時は、みんなもっと大変だろうから2~3時間くらいサービス停止をしても許されるだろうと思っていて例外として考えている。

 逆にある日突然、ヒューマンエラーでサービスが全損してもバックアップからそれくらいあれば復旧できる見込みでいる。

 このように弊社の場合は明確な目標の稼働率を定めてはないのだけど現実的な範囲で再構築は可能と考えており、そのためのサービス停止はビジネスとしても許容している。 この場合、バックアップは別リージョンのS3、または別サービスなど、メインの場所とは別の場所に取っておくことが大切だ。

 しかし、世の中には必ず社会インフラのような1秒たりとも止まっては困るサービスはある。 その場合は稼働率を1桁増やす毎に指数関数的にコストは増えることは間違いない。 マルチリージョンは必須だし、場合によってはマルチクラウドが必要になるかも知れない。 実際にDBだけに置いても稼働率 99.999% から実現していく難易度が跳ね上がっていく。 サービスとなるとコンポーネント毎に当然冗長化は必要なので掛け算でコストが掛かる。

 逆説的いうと、先程の弊社の例のように「止まっても良い」とすることでコストは大幅に下げることが出来る。 サイトの規模によるが、小さなWebサイトでアクセスも少ないのであればRDSもEC2もMultiAZにしないと言う選択肢ももちろんある。サービス障害レベルの問題が発生したらダンプから他のクラウドに作り直してDNSを切り替えても良いし、今回のようなクラウドサービスの障害時に1番低コストなのは「クラウドサービスが直るのを待つこと」だ。

 もちろん、これは機会損失とトレードオフなのだけど必ずしも完璧を目指すことがビジネスとして正しいわけではない。 そういうバランス感覚をエンジニアとして知っておくことが肝要だ。


以上のように稼働率を考えた結果、 99.99% を目指すにはどうするかを考えていく。

インターネット

 意外に知られてないがインターネットは壊れる。 悪意のあるBGPの設定が流れたりしたら簡単に壊れる。 最近でもCloudFlareが激おこぷんぷん丸になった例もある。

blog.cloudflare.com

 大体年に1回くらいはこの話を聞くので他人事ではないのだが、ここを担保するというのはとてもとてもコストが掛かる。 弊社は先の例のとおり、諦めて「勝手に治るの待つ」スタンスでいるので今回の稼働率計算の対象外とする。

DNS

 DNSも近年あまり気にされないと思うが壊れる時は壊れるし、自分たちだけで担保するのはインターネット同様に難しい。 8.8.8.8に障害などがあると多くに影響する。 ここも弊社は諦めているし、Route53のSLAは100%なのでAWSを全面的に信じるスタンスとしている。 そもそもRoute53が完全に死んだら弊社が使用しているSaaS系も、アクセスする前にサービスが死んでいるので今回の稼働率計算の対象外とする。

ネットワーク

 ここではAWS内のネットワークを指す。 これも前述同様、アンコントローラブルなところが多く、MultiクラウドやMultiリージョンを検討する必要がある。そもそも東京リージョンが死んだらDNSと同様に他のサービスが死んでいるので今回の稼働率計算の対象外とする。

CDN

 弊社はCloudFrontを使っているのだけど、実はここが単一障害点である。 現状はCloudFrontが死ぬとサービス停止を伴う。 一応、CloudFrontを介さないように切り替えることは出来るようにはしているが、それにはdeployを伴うし、サイトのパフォーマンスの劣化は間違いない。 特に画像周りは再配置が必要になる。

 ここは稼働率をあげようとすると別サービスのCDNをバックアッププランとして用意する必要があるのだけど、コストがかかるので「素早く移行出来るようにする」のが現実的な路線になっているが、弊社は結構ヘビィにCloudFrontを使い込んでいるので実質移行は難しい。 そのためここもRoute53と同様にAWSと心中する覚悟をしており、今回の稼働率計算の対象外とする。

アプリケーションサーバ

 ようやく自分たちの手で稼働率を担保できそうなレイヤーになった。 アプリケーションサーバはALBのようなロードバランサーとオートスケールを使うことで比較的容易に可用性を担保出来る。

 今回の件を見て感じたのはEC2、1台でもオートスケールと同じ用にAMIのスナップショットやAnsibleなどを使って、別AZに迅速に置けるようにしておくことが重要だ。 また迅速に対応するための選択肢としてコンテナは非常に相性がよく、ステートレスな状態でコンテナを運用する大きなメリットの一つと言えるだろう。

 増やせる事と同様に、減らす・移すことが迅速に出来ることも大事だ。 今回の場合、特定のAZを使わないという判断が素早くできたかどうかは大切なポイントだ。 その判断のためには正しくサービスを仕組みと体制の両輪が回っている状態で監視出来ている必要があり、それが適切で迅速な判断につながる。

 しかしながらEC2が全滅した場合、EC2だけ別リージョンに持っていくことは簡単ではない。 まずDBにつなげるためにルーティングが必要だし、ALBやSSL証明書も合わせて別リージョンに作り直す必要がある。 DNSの切り替えも必要だし、よほど準備している場合を除き、全てのAZが完全に死んだようなケースでは対応が難しいのではなかろうか。

 ちなみに弊社はサービス自体に影響は出なかったが、deploy系の責務とbot処理が1つのEC2インスタンスに集約しており、そのインスタンスが死んだため、簡単にdeployできる状態ではなかった。  幸い手元の環境でもdeployは可能なのでクリティカルではなかったが、botは完全に死んでおり、社内のチャットは閑散としていた。

RDBMS

 データストアの冗長化はとても難しい。 今回の件もRDSが障害の対象だったため、お手上げだった会社も多いのではないだろうか。

 まずMultiAZでも駄目でRDS自体の障害の場合、他の選択肢が限られる。EC2にRDBMSをインストール、パラメータチューニング、レプリケーションの構築、リストア、全て行えるエンジニアが自分の会社に居るだろうか? 幸い弊社には曽根さんっていう素晴らしいDBAが居るので可能だが、それは非常に稀なケースで多くの場合、厳しい戦いを強いられる。

 またデータサイズが大きくなれば大きくなるほどデータ転送なども含めたリストアに必要な時間が膨れていく。 シャーディングをしており、数十台以上のDBインスタンスがあるような場合、RDSそのものに問題が発生した場合は多くは諦めるしかないし、RDBMSが停止した場合の多くはサービスが停止してしまうのではないだろうか。

 現実的にRDSを利用しながら稼働率を上げたいのであれば、リアルタイムの参照を諦めたり、更新情報をログに残してリトライ、リランによってデータを作り治せる状態(つまり非同期処理)にしてアプリケーションとしては200を返すような仕組みを作るしか無い。 しかしこの場合、実現のためにSQSとLambdaの組み合わせが利用されると思うが、今度はSQSが単一障害点となる可能性が出てくる。

 つまりRDBMSの場合、ヒューマンエラーの問題やインスタンスガチャの問題、アプリケーション負荷による増設などは対応しやすく、コントローラブルなところではアプリケーションサーバ同様に稼働率 99.99% は実現可能であるものの、AWSの障害の程度によっては諦めるしかない場合がある。

NoSQL

 ElasticCacheが障害の場合、データ自体の移行は多くの場合は不要なのでEC2の上に再構築などが可能である。 セッションなどはRDBMSをスケールアップするなどしてそっちに切り替えることも可能。

 しかしDynamoDBやKinesisなどを使っている場合は代替は難しいだろう。 弊社では積極的にデータストア層のコンポーネントを増やさない理由としてはこれがある。 しかしながらサービスの内容によってはNoSQLを必要とするケースは多々あるし、実際にみんながどのようにリスク管理しているのが知りたいところでる。

 ということでNoSQLもRDS同様にガッツリ使っている場合はAWS自体の障害には弱い。

SaaS

 例えば弊社はメールはSendGridを使っているし、監視ではMackerelを使っている。 特にメールはサービス提供のためには必須の機能であるものの、現状は具体的なバックアッププランを用意してない。 メールが厄介なところは即時にEC2にメールサーバを建てても、AWSによって25番ポートが制限されていることだ。

aws.amazon.com

 そのため、SESなどを利用する必要があり、事前に接続変更の準備やアプリケーション側の対応の準備をしておく必要がある。

 このように他にも多くのサービスが課金やクレカ利用だったり、電話やメールのような通知周りでSaaSを利用していることだろうと思う。 そのSaaSがどのようなプラットフォームを使っているか把握しておくこと、そして代替案を考えておくことは稼働率を上げるために必要だ。

 しかし課金の仕組みなどは簡易に切り替えることはとても難しいので結局のところ、諦めて直るのを待つしか無いのではないだろうか。

まとめ

 ここまで書いて来た結果、結局のところ、サービスを構築する上でコントローラブルな場所は意外と少ないことがわかった。 逆にヒューマンエラーやアプリケーション、パフォーマンス起因の障害には強く、簡易にセキュリティを担保し、スケーラビリティがある。 だからクラウドを使うことはビジネスインパクトがあるのだ。

 そこがトレードオフに近い関係であることを受け入れ、アンコントローラブルな部分を把握した上で、 クラウドが壊れたらハイボールでも飲みながら直るのを待つ」 というのがクラウドの正しい歩き方なのではなかろうか。