RoomClip 開発者ブログ

TV番組「今夜くらべてみました」でRoomClipを紹介されて得られたたくさんのこと

みなさんこんにちわ。 ルームクリップ株式会社CTOの平山です。 残暑が厳しい日々ですね。

昨日の9日、表題の通り日本テレビ「今夜くらべてみました」でルームクリップが紹介されました。 ありがたい話です。

いつだってユーザさんに触れてもらうのは大変に喜ばしいことですが、 大きな衆目を集めるシーンでの言及となると、ちょっぴり特別な興奮がありますね。

これが「エンジニアとして」、となるとなおさらです。

なんてったって巨大トラフィックが襲撃してくるかも知れないわけです。 この手の興奮は上手にコントロールして、常に冷静に対処し、万全の対策で迎え撃たなければなりません。 ご多分に漏れず今回も我々は相応の準備をもって立ち向かいました。

というつもりでしたが、、、

結果として、今回はもっと興奮しておくべきでした。

TVは、

「今夜くらべてみました」という番組は、

私の想像のはるか上空を飛び、ずいぶん時間がたちこのブログを書いている今ですら、おおきな影響を及ぼし続けております。

本ブログでは、「こんくら」メンバーの影響力を甘く見ていた一人のエンジニアの猛省と、 これから同じ轍を踏むかもしれないすべてのエンジニアに向けての転ばぬ先の杖を記していこうと思います。

中には「え、こんなの当たり前でしょ、むしろなんでやってなかったの?」ってものもあるかと思います。

わかっております。不安にならずとも皆様の手厳しいご意見は、これ以上ないくらい私の脳幹をえぐっています。

ただ、時には包み隠さないことも大事です。

わたしは後ろ暗さを抱えて危険なシステムを運用しているすべてのエンジニアの味方です。 「正しい運用しようぜ」の流れを全力で社内に引き込むための道具として、ぜひ本ブログをお使いください。

その前に…

改めまして、今回突発的に発生しましたアクセスに対応しきれず、長きに渡ってサービスに障害を起こしてしまいましたことをこの場を借りて謝罪いたします。 期待をもってアクセスしていただいたすべてのユーザの皆様、また、すべての関係各位の皆様に対し大変にご迷惑をおかけいたしました。重ね重ね申し訳ありません。

以下、専門的な話になりますが公開できる限りにおいて、障害の経緯を共有させていただきます。

概要

簡単に言ってしまうと下記のようなことが起きました。

  • TV局から連絡を受けて流入トラフィックを推計した
    • 余裕で外れた
  • 単一障害点はスケールアップで大丈夫だろうと高をくくった
    • 余裕で外れてそいつのせいで全部落ちた
  • 分散しまくればなんだって耐えうるだろうと甘く構えた
    • ネットワークリソースについて忘れてて分散できず落ちた
  • 対策範囲なんてアプリケーションサーバとDBくらいだろ、って思った
    • バックエンド色々マイクロ化したため対策ポイントが増えててんやわんやになって気分が落ちた

一つでも「あ、これは対岸の火事じゃないぞ」と思ったエンジニアは今すぐ点検しましょう。 単一障害点は本当に危険です。当たり前ですが大事なことです。 「当たり前のことができていない」というケースは「当たり前に多い」と思ってます。 心当たりあるエンジニアは、今日だけは責めないので、そっと確認しましょう。

それでは、一つ一つ見ていきましょう。

TV番組のトラフィック見積もり

一般的には視聴率と世帯数から視聴者数を概算して母数を求め、 その後に「サービス言及中に見ている人の割合」とか「その時間帯に検索する人の割合」とかを適当に見積もって積算して当たりをつけるものだと思います。

大事になるのは瞬間最大風速req/secなので、秒単位で平坦にならすのではなく、適当にピーク分布を積算して出すのがまぁ妥当かと思われます。

今回わたしが見誤ったのは、「その時間帯に検索する人の割合」でした。 番組の性質上、検索やサービス起動を促す作りになっていて(これは本当にすばらしい!)、思った以上のリクエストが発生しました。数値でいうと2倍程度見誤りました。

でも、2倍です。

皆様、「危険だな」と思ったら妥当な計算のあと、「2倍」しましょう。

ちなみに私は、放送直前に「チュートリアル徳井さんがサービス名を発話するかも」という情報を追加で得ました。(このあたりの連絡網を強化することも必須ですね!)

この時点で実はかなり迷いました。今の対策が不十分である可能性がよぎっていたのです。

・・・皆さん、虫の知らせがやってきたら迷わず「最大値の2倍」にしましょう。

単一障害点への対策

これが本当に悔やまれるポイントです。 どの本にだって書いてあることです、こういうボトルネックは障害時にも影響を波及させないように対策しておけと。 それができないなら、どんなアクセスにも耐えられるような設計にしておけと。

ところで、RoomClipはiOS、Android、ブラウザ向けにサービスを展開しており、そのバックエンドとして概ね下記のようなクラウドサービスを利用しています。

  • アプリケーションサーバ/ストレージサーバとしてAWS
    • EC2、ECSを併用
    • DBはAurora
  • 画像配信/変換サーバとしてさくらインターネット
  • 検索サーバとしてElastic Cloud

共有リソースに対するAPIアクセス、が多発するような状態と言えるでしょう。

かつてのルームクリップにおいて負荷障害発生時の犯人の9割はDBでした。 よって我々はDBに対してどんな奇行種も入ってこれない防壁で守っておりました。 実際今回のアクセスに対しても唯一と言っていいくらい割と大丈夫だったのはDBです。 皆さんもそこは大丈夫だと思います。

問題は、かねてよりバックエンドで進めていたマイクロ化にあります。 特に検索サーバ・画像配信サーバ、このあたりはサービスの隅々で使われている重要な機能なので特別に本体設計から切り離し、大事に保守メンテしていました。それはそれでいいことだと思います。

だが、そのAPIの呼び出し部分が悪かった。

一部のページにおいて、APIのレスポンスをタイムアウトせず待つ、帰ってこなければExceptionを投げエラー終了する、というコードになっていました。

運命共同体コードです。

ぞっとしますね。

本当に反省しています。

本来であればサービスメッシュやenvoyレイヤのように、API接地面の安全な設計は暗黙的に処理する予定でした。 しかし、そのレイヤについてちゃんと決めきることを少し後回しにて、とりあえず(後からどうとでもなるような形で)切り離すということを優先していました。 これはこれで限られたリソースや検証という意味ではメリットのあることだと思います。 ただ外部環境は待ってくれません。 TV番組の話は突然来ますよ。 「まぁ一旦これでいって、ある程度わかったらちゃんと固めてこうや」 これは悪くない選択肢です。 ただ「リスクを受容した」ということはもっと強烈に認識すべきでした。

皆さん、モノリシックなシステムをDDD的思想でもって妥当な範囲でバラしたく気持ちはわかります。

しかし、いつでも想定しておいてください。

来週、あなたのサービスについてチュートリアル徳井さんが言及するかも知れないことを。

想定外のネットワークリソース枯渇

さて、異常を察知して直ちにリソースの水平スケールをアップした我々ですが、そこで地団駄を踏むことになります。

インスタンス・コンテナが全く増えません。

ルームクリップのAPIサーバ、Webサーバは基本的にECS(一部EC2)という状況だったので、オートスケーリンググループをいじれば続々と援軍追加されるはずでした。 が、いくらたってもエラーで立ち上がりません。AWSリソース制限かとも思ったのですが、つい最近あげたばかりです。

いろいろ調査してわかったことは、サブネットのPrivateIP枯渇でした。事情あってサブネットの許可IPのCIDRを厳しくチューンしていたため、ここの上限にぶつかってインスタンスの立ち上げができなくなっていました。

サブネットの設定なんてそうそう変更しないので、すっかり忘れておりました。 皆さんもそらで言えますか?あなたのサブネットは第何オクテットまでマスクしていますか?

あ、ごめんなさい、そらで言える必要は全くありません。確認しに行けばいいだけです。 ネットワークに限らず「リソース枯渇」系の話は結構緊急時に人をイラつかせるものです。

例えばnlimit、inode、エフェメラルポート、帯域制限、もちろんHDD容量。そして今回忘れてならないIP。

これは激痛で、リカバリの速度がだいぶ遅れた原因の一つとなってしまいます。

対策点の増加

先に触れたマイクロ化の流れもそうですが、BFFなども積極的に導入した結果、スケール対象となるインスタンスの塊は結構増えておりました。

端的にALBの数が多いんですね。

これは本質的にはそこまで問題ではないことなのですが、少ない人数でこれらのスケールアップを管理するというのは中々ストレスがたまります。 事前準備はまぁいいんですが、障害中「やべぇ!」となったときのあっちゃこっちゃいじる千手観音っぷりは悲惨です。 いろいろな対策がありえますが、Lambdaなりでサーバレスに切り替えていくのは非常に良い選択かもしれません。

とにかくウォームアップなんていらない!というのは大正義です。

まとめ

非常に長くなってしまいましたが、簡単にまとめますと、今回の障害の大きな原因はやはり単一障害点の対策不備になります。

RDB周りは特に手厚く対策されると思いますが、(当たり前ですが)転置インデックスを扱うサーバや、DynamoやRedisといった領域についても、「手厚くするか、緊急時に被害を軽微にするような設計にする」など、最低でも波及を抑える設計にすべきでした。

また、外部APIを使うときの接地面の設計(リトライ制御やブレーカーなどを含む、一般にenvoyレイヤなどで処理される諸問題)も非常に繊細になされるべきだということを改めて実感しました。

これ以外にも気づけなかった問題は多々ありますが、本ブログではひとまず猛省しつつ「速報」という形での共有とさせていただきたいと思います。

また、これからバックエンドをマイクロ化していくプレーヤーは多数存在していると思いますが、ぜひ改めて「管理すべきドメイン」が増えていくことにより、それぞれの障害点への対策やスケーラビリティの保証などが手薄にならないよう、気をつけていただけるとよいかと思います。

色々と課題はたくさんありますが、日々精進し、これからも皆様の日常にある「創造性」を応援して参ります。 何卒末永くルームクリップをよろしくお願い申し上げます。 改めまして、この度の大規模な障害、大変申し訳ありませんでした。

そして、本ブログを読んで、 「しかたない、、わたしがなんとかしてあげよう」と思うエンジニアの方、ぜひ遊びに来てください!

フロントもサーバサイドも!生産性の高いサービス開発基盤を作りませんか?



この記事を書いた人:平山知宏

ルームクリップ株式会社のCTO。 インフラからサーバサイド全般担当。 インダストリアル系の家に住みたいと思うけど、子供もできちゃったし危ないから工具とかほっぽっとくのやめようと思っている1985年生まれ。