アクセスのピークを過ぎても、APIのタイムアウトが減らないことがある。新規リクエストが減った後も、失敗したリクエストの再試行が、詰まったDBに仕事を送り続けるからだ。
リトライが過負荷を維持する
短時間のアクセス急増でDBの応答が遅れ、APIがタイムアウトし始める。呼び出し元が再試行するとDBに仕事が増える。タイムアウトした元の処理がDB側でまだ走っていれば、元の処理と再試行が重なる。追加の仕事で応答がさらに遅れ、次のタイムアウトと再試行を招く。
再試行が集中して負荷を増幅する現象をリトライストームと呼ぶ。この例では、アクセス急増が引き金で、リトライストームが障害を維持する仕組みだ。引き金が消えた後も、この循環で過負荷が続く状態を準安定障害(metastable failure)という。
負荷制御の手法はどこに効くか
| 手法 | どこに効くか |
|---|---|
| 負荷分散 | 余力のあるレプリカに仕事を振り分ける。全レプリカが同じDBを使うなら、振り分け先を変えてもDBに届く仕事の総量は減らない。 |
| バックプレッシャー | 下流の処理能力に合わせて上流を減速させる。例えば、同時実行枠が空くまでワーカーが次のジョブを取り出さない。 |
| ロードシェディング | 処理に入る前に一部のリクエストを断る。例えば、同時実行数が上限に達したら、低優先度の処理を早めに拒否する。 |
| トークンバケット | 一定の速度でトークンを補充し、処理を許可するたびに消費する。補充速度で継続的な許可レートを、バケット容量で短時間のバーストを制御する。再試行専用にも使える。 |
| 指数バックオフ+ジッター | 再試行するたびに待ち時間を伸ばし、ランダムなばらつきを入れて再試行が集中するのを防ぐ。再試行の回数や総量には上限も設ける。 |
| サーキットブレーカー | 失敗が続く依存先への呼び出しを一時的に遮断し、時間を置いて少数の試行を通し、回復を確かめる。 |
APIゲートウェイとサービスクライアントがそれぞれ最大3回試行する構成では、元のリクエスト1件から下流への呼び出しが最大9回発生する。リトライを担当する層を決めておくと、試行回数が層ごとに掛け合わさるのを防げる。
回復するまで流入を絞る
平常時にさばける負荷と、障害中に回復できる負荷は違う。GoogleのSRE本には、平常時は毎秒1万件を処理できるサービスでも、正常なサーバーが1割まで減ると、復旧のために毎秒1,000件程度まで流入を下げる必要があるという例がある。
DBが詰まった例なら、まず再試行や低優先度の処理を絞り、DBに届く仕事を減らす。新規リクエスト数と再試行数を別々に数えると、どこから仕事が増えているかが見える。成功処理数とレイテンシが持ち直し、キューの滞留が減り始めたら、再び詰まらないかを見ながら流入を段階的に戻す。
参考資料
データ指向アプリケーションデザイン 第2版
Metastable Failures in the Wild
Google SRE — Addressing Cascading Failures
AWS Well-Architected Framework — Control and limit retry calls
おすすめの書籍

コメントを残す