過負荷になったシステムはなぜ回復しないのか

赤い光の軌跡がサーバーラックに繰り返し戻り、リトライストームを表すイラスト

アクセスのピークを過ぎても、APIのタイムアウトが減らないことがある。新規リクエストが減った後も、失敗したリクエストの再試行が、詰まったDBに仕事を送り続けるからだ。

リトライが過負荷を維持する

短時間のアクセス急増でDBの応答が遅れ、APIがタイムアウトし始める。呼び出し元が再試行するとDBに仕事が増える。タイムアウトした元の処理がDB側でまだ走っていれば、元の処理と再試行が重なる。追加の仕事で応答がさらに遅れ、次のタイムアウトと再試行を招く。

再試行が集中して負荷を増幅する現象をリトライストームと呼ぶ。この例では、アクセス急増が引き金で、リトライストームが障害を維持する仕組みだ。引き金が消えた後も、この循環で過負荷が続く状態を準安定障害(metastable failure)という。

元の処理と再試行が重なるのを抑えるには、リクエスト全体のデッドラインを下流まで伝える。各層では残り時間を使い、期限が切れた処理は開始しない。実行中に呼び出し元が待つのをやめた場合も、キャンセルを下流に伝え、対応している処理を打ち切る。

負荷制御の手法はどこに効くか

手法どこに効くか
負荷分散余力のあるレプリカに仕事を振り分ける。全レプリカが同じDBを使うなら、振り分け先を変えてもDBに届く仕事の総量は減らない。
バックプレッシャー下流の処理能力に合わせて上流を減速させる。例えば、同時実行枠が空くまでワーカーが次のジョブを取り出さない。
ロードシェディング処理に入る前に一部のリクエストを断る。例えば、同時実行数が上限に達したら、低優先度の処理を早めに拒否する。
トークンバケット一定の速度でトークンを補充し、処理を許可するたびに消費する。補充速度で継続的な許可レートを、バケット容量で短時間のバーストを制御する。再試行専用にも使える。
指数バックオフ+ジッター指数バックオフで再試行までの待ち時間を段階的に伸ばす。ジッターは、再試行が同じ時刻に集中しないように、待ち時間をランダムにばらつかせること。例えば、待ち時間の上限が1秒なら、各クライアントが0〜1秒の範囲から待ち時間を選ぶ。再試行の回数や総量にも上限を設ける。
サーキットブレーカー失敗が続く依存先への呼び出しを一時的に遮断し、時間を置いて少数の試行を通し、回復を確かめる。

DB呼び出しの同時実行数に上限を設け、実行枠が埋まったら短時間だけキューで待たせる。キューイングは一時的な負荷の山を吸収できる。流入が処理能力を上回り続けると待ち時間が伸び、タイムアウトや再試行が増えるため、キューの件数と待ち時間にも上限を設ける。キューが満杯なら早めに断り、待機中に期限が切れたリクエストはDBに送らない。

APIゲートウェイとサービスクライアントがそれぞれ最大3回試行する構成では、元のリクエスト1件から下流への呼び出しが最大9回発生する。リトライを担当する層を決めておくと、試行回数が層ごとに掛け合わさるのを防げる。

回復するまで流入を絞る

平常時にさばける負荷と、障害中に回復できる負荷は違う。GoogleのSRE本には、平常時は毎秒1万件を処理できるサービスでも、正常なサーバーが1割まで減ると、復旧のために毎秒1,000件程度まで流入を下げる必要があるという例がある。

直前のデプロイや設定変更が引き金なら、負荷を絞るのと並行して切り戻す。流入を絞っても回復しなければ、DBなど詰まっている箇所の処理能力を回復させる。

DBが詰まった例なら、まず再試行や低優先度の処理を絞り、DBに届く仕事を減らす。新規リクエスト数と再試行数を別々に数えると、どこから仕事が増えているかが見える。成功処理数とレイテンシが持ち直し、キューの滞留が減り始めたら、再び詰まらないかを見ながら流入を段階的に戻す。指標が再び悪化したら、流入を直前の水準まで絞り直す。

負荷試験では、何件まで処理できるかに加えて、一度過負荷に入ったあと、どこまで流入を落とせば復旧するかも確かめる。

参考資料

データ指向アプリケーションデザイン 第2版
Metastable Failures in the Wild
Google SRE — Addressing Cascading Failures
AWS Well-Architected Framework — Control and limit retry calls

おすすめの書籍

書籍 · アフィリエイトリンク
データ指向アプリケーションデザイン 第2版 ―信頼性、拡張性、保守性の高い分散システム設計の原理
この記事のきっかけになった本です。過負荷への対処を、分散システムの信頼性や拡張性の設計とあわせて学べます。
Amazonで書籍を見る

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です