com4dc’s blog

Javaプログラマーのはずだけど運用してます

2019/08/23 AWS障害で観測した現象と現場での対応

2019/08/23の週末金曜日、「今日は読書会に出て脆弱性指摘されたIssueの修正PRだけ作って帰ろ」と思っていたところ、AWSで大規模な障害が発生に遭遇。

障害から復旧までの経緯や原因については各種ニュースサイト等で報道されている通り。

www.itmedia.co.jp

今回の障害によって各種サービスやアプリケーションに多大な影響があったことを調べていた方がいたため、そちらのリンクを記載させていただく。

piyolog.hatenadiary.jp

この記事では、実際に自分が対応した上記障害が起因と思われるトラブルに対応した内容について雑に記載しておく。

AWSが公式にアナウンスしていたサービス以外にもいくつか影響が出ているのは確認したので、単純に公式アナウンスだけを見て問題なしと考えるのは危うい(マネージドサービスだけど裏ではEC2使ってるとかそういうのは多そう)

会社のブログに書けばええやんという話もあるんだけど、色々察してほしい。公式アナウンス出てなかったけど、このサービス落ちてたので対応しました系のことはとても書きづらいのである。なので個人のとこで書く。

EC2が立ち上がらない

これは公式アナウンスにも出ていた。

t2やm3といった旧世代のインスタンスタイプを利用している場合、ap-northeast-1a (実際のAZ IDは失念した) で起動しようとしている場合、影響が出ていた。 AutoScalingで立ち上げようとしたインスタンスのStatus Checksが 0/2 でPassせずに正常に立ち上がらない。

さらにTerminateしようとしているインスタンスも 「Waiting」のまま停止しない現象を確認。

f:id:com4dc:20190824142402j:plain

どうしようもできず、とりあえず復旧を待つことに。日中帯の障害だったため、障害発生時には必要な台数がある程度立ち上がっており、想定以上のアクセス数、SQSのQueueに入っているアイテム数によってScaleしようとしているサーバーのいくつかに影響が出ていた。ただ、システムそのものは停止しているわけではなく処理能力が若干足りないながらも正常に動作しているのを確認している。

対応

本当に停止するとやばいアプリケーションに関しては、起動設定等の変更で起動インスタンスタイプを変更する等の対応が必要だったが、今回は以下の理由から対応を見送った。

  • 障害発生時点で必要な台数のインスタンスが全て正常に立ち上がりきっていて、処理も継続できていた(後述のALB障害?によるクライアント側のエラーは出ているがEC2上では見えてない)
  • EC2起因と思われる障害状態が見つけられなかった(主に障害状態に対して別の原因によって全て説明がつくため)

ただし、後述するRedisノードの障害によって5xxエラーが頻発した結果、ElasticBeanstalkで動作している全てのEC2のヘルスが一気に悪化した時には戦慄が走った(Redisノードの復旧と共に沈静化した)

ALBの障害?

公式なアナウンスがないものの一つ。ALBのログが一部ロストしているのと、メトリクスが一部取れていないのを確認している。ALBが2つのIPを持っているのを確認しているが、どうやら片方が反応していなかったっぽい(恐らく障害に該当するAZ)

f:id:com4dc:20190824153426p:plain

一時的にメトリクスが取れてない。コンソールの問題かと思ったけど、障害解消後の今に至っても取得できない。

対応について

ALBに関しては手の出しようがないので、静観するしかなかった。リクエストがそもそも到達しないやSocket Timeout等で普段あまり見ないタイプのアプリケーションログが出ていた。

ElastiCacheのRedisノードが停止

こちらも特に公式のアナウンスは出ていない、ものの内部的にはEC2を使っているのは間違いない。インスタンスタイプの指定から見るに。

さらにt2インスタンスという旧世代インスタンスで構築されていたため、障害に該当するものと思われる。

f:id:com4dc:20190824143518j:plain

復旧直後からメトリクスが出現。障害時間中はメトリクスが一切出ていなかった。 さらにRedisにつなごうとしたアプリケーションでは以下のようなログが多発していたのを確認している。

org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:281)
        ....

対応

過去の経験上、いくつかの対応方法を検討

  1. 復旧するまで祈って待つ
  2. Reboot
  3. 新しいRedisノードを作成してアプリケーションの向き先を振り分け

1. 復旧するまで祈って待つ

一番消極的な方法。ただし有効な場合もある模様。 実際、優先度の問題で後回しにした環境があとからみたらいつの間にか復旧しているというのがあった。

2. Reboot

すでに正常に動作してないんだから再起動すればええやろ、というノリ。ただし条件付き。 インスタンスタイプに問題がなく、AZのみの場合は有効とのこと。インスタンスタイプによってはEC2の枯渇等によってRebootがいつまで経っても終わらない現象を確認している。

3. 新しいRedisクラスタを作成してアプリケーションの向き先を振り分け

ただし、この方法はSingle AZでRedisクラスタ内にノードが一つしかない状態での話。なんでそんな構成なんだ!と言われても現実そんな環境で運用してしまっているのだから仕方がない。理想論は後回しにして今は目の前の障害をいかに解決するかが最優先事項。

積極的な解決方法。 Parameter Group, Engine Version, Security Group等々の各種パラメータを全て同じにした上で、インスタンスタイプに問題があるならばインスタンスタイプを変更、AZにも問題がありそうならばAZも変更して、新しいクラスタを立ち上げ、ノードをレプリカなしで1台だけ立ち上げる。

アプリケーションのRedisノードの向き先を変更して対処完了。ただし、この手法はCloudFormation等でリソースを管理している場合は、一時的に管理外のリソースを作成しそちらに振り分けてしまうことから後日何らかの方法でそれらのギャップを埋めておくことが必要。

旧Redisノードが残っていて、再度Redisノード内のデータがクリアされてしまっても問題ないというのであれば旧Redisノードは残しておいたほうが良い。

AmazonESのESインスタンスが停止

特定のアカウントに限り発生していた障害らしい。全体的な障害との因果関係は不明。ただ ap-northeast-1 だから関係ありそう。

f:id:com4dc:20190824150845j:plain

こちらもESインスタンスのメトリクスが正常に取得できず、すごく表示がアレなことになっていた。まあ、コンソールはガタガタなのでESが悪いのかコンソールが悪いのかはっきりしないところはあるが・・・。

f:id:com4dc:20190824151423p:plain

メトリクスがほぼ取れてない。それと赤い。

f:id:com4dc:20190824151538p:plain

ESへ接続しようとするアプリケーションからは以下のエラーが大量に出力されていた。

503 Service Unavailable: Back-end server is at capacity

対応

自然復旧を待つほかなさそうということで静観。2019/08/23 21:30頃に回復していた。

まとめ

AZ全体の障害なんてめったに経験できないので、普段運用しているシステムの弱点を洗い出せた現場が多かったのではないかと思う。 マネージドサービスとはいえ、AWS内部ではサービスの組み合わせで新たなサービスを作っているようなので、こういった広範囲に及ぶサービスの障害によって思わぬところで影響が出ていることが多そう。

今回の障害を糧に洗い出した弱点を潰す(もしくは受け入れつつ)強固なサービスの改善が行われることを願うのみ。

個人的には以下(個人の意見なので所属会社云々〜〜)

  • こういった障害が発生した時に組織的に対応できるか、それとも個人スキルに依存した各個撃破で対応するかによって、復旧速度やメンバーへの負荷が変わると思う。良いチェックシートになったのでは。
  • 作り出したものの弱点は「これ」と明らかに言える現象が発生したので、確実に開発へフィードバックする。もしフィードバックが受け入れらず改善されないならば、その開発組織はそれまで。