本番サービスイン後、不思議な条件で起きるエラーが出てきませんか?調べても調べてもわからない...時間が過ぎるばかりですが、突然ハッと思いつきます。
💡あっ!タイムアウトだ!
見聞きする限り、ほぼ確実にこのパターンが発生しています。信頼性を上げ、不毛な障害対応を減らし、ユーザーに届ける価値を下げたくないなら、タイムアウトの設定を必修科目にしましょう
堅牢なアプリやサービスか診断するときには、タイムアウトとリトライについて確認すると良いでしょう。
タイムアウトを設定するメリット
- ユーザー体験の向上(の可能性)
- 終わりが見えずただ待つのは辛い...無駄に待っている可能性があります
- 無駄なリソースの節約
- 結局エラーになるなら早めに切断したいところ。節電です
- 障害の予防
- 特に重いときにリクエストが積み重なると厳しいですね。カスケード障害を防ぎましょう
タイムアウトを設定するコツ
前段ほど長くし、後段ほど短くする
同期処理の場合です。
単純化した例:
ブラウザ -> API -> DB 60秒 -> 50秒 -> 40秒 (仮) *リトライは考慮しないとする
もし上記とは逆に、前段のタイムアウトを短く、後段を長くしてしまうと、前段で打ち切ったのに後段では無駄に処理が続いてしまいます。安全に終わらせるためにも後段を先に打ち切りましょう。もちろん冪等性が大事です。
どことどこの話か理解する
いざタイムアウトを設定するとします。接続元のほうがコネクションを切るのか、接続先のほうがコネクションを切るのか、ドキュメントやコードを読み込まないとよくわからないこともあれば、読んでもわからないので検証しかないことも。特にネットワーク系の設定にありがちです。
その設定で何がタイムアウトするのか理解する
特に複数の設定があるソフトウェアの場合、何が起きるかわかりづらいです。極端な値を設定して試してみるのが案外早く、おすすめです。
タイムアウトするとどうなるのか理解する。
特に更新系処理は更新されるのか、されないのか、中途半端に終わるのか。確認しましょう。ほかにはLambdaのタイムアウトなら後処理がされない、通常のログが出ない、次回に半コールドスタートが起きる、といった事象が発生します。
デフォルトが長すぎることが多いので短くする
ライブラリ等の作成者は汎用的に考えて長めに確保しがちなのですが、実環境としてはそこまで不要なことも。リリース後最初のうちは詰まったらリトライで済むことが多いので短めに。
リリース前に考慮しておく
タイムアウト自体が障害になるというより、障害の要因の一つとして隠れていることが多いです。後で困らないよう一つ一つ考えておきましょう。文書化できていると理想です。
単位重要
ドキュメントを読んでいてよくわからなくなる点の一つが、単位です。秒なのかミリ秒なのか。単位の重要性について2つほど参考リンクを挙げます。
いろんなところに潜むタイムアウト
AWSサービスレベル
例えば、
- ELB
- API Gateway
- Lambda
- NAT Gateway
Lambdaで無意味に待つとお金がもったいないですね 💸
スタックレベル
- kernelパラメータ
- ミドルウェア
- アプリサーバ
特に古いミドルウェアの設定が理解しづらい傾向です。
AWS SDK: かなり長め
boto3なら、connection 60秒、socket 60秒
JavaScriptは、connection 永遠、socket 120秒
特にAWSリソース内からのAWS SDKでの通信は短めに設定しておきましょう。AWSリソースからAWS API宛のネットワークは安定しているはずで、待ってても好転することは少ないです。クライアント(ブラウザ/アプリ)からは状況に応じて。
http client
設定していますか?デフォルト値は言語やライブラリによります。打ち切るか待つかの方向性は、経由するネットワークや対象サーバの安定性で決めましょう。レガシーな相手に接続するなら、リトライも優しめにしてあげるとよいでしょう。
RDB connection pool
コネクションがタイムアウトするのか、クエリがタイムアウトするのか、意外とごちゃごちゃになります。まずはドキュメントを読みましょう。
動作を検証する
- wiremock
- failure lambda系
- タイムアウト値を極端にしてみる
参考になる資料
日本語のみ。
基本
応用
SRE本
アプリケーション設計の本でもあります。開発者が読むと良いでしょう。
最後に
分散システムを扱う上で、タイムアウトとリトライは必修科目です。まずは担当のサービスがどうなっているか調べてみましょう。
文責:高木