TT Lab
はじめる
学ぶ 学習パス コース

接続ひとつが遅くなり、残り全部が止まった

運用者の接続診断器:予算・原因・解放

TT Labで続きを見る

一言でいうと

運用できるソケットコードは、成功したバイトだけでなく、終了の原因・リソースの上限・キャンセルと例外での回収まで、証拠で説明できなければなりません。

なぜ必要なのか

診断器を10回実行して、毎回結果が出ました。ところが、実行のたびにFDが2つずつ残るなら、短いデモは成功しても、長く動かしておく運用ツールは、いつか失敗します。逆に、すべてのエラーをtimeoutにまとめると、グラフはもっともらしくても、ポートの拒否とユーザーのキャンセルを区別できません。コードを通過させるテストと、ユーザーの判断を助ける証拠の間に、欠けている条件がないかを確認する必要があります。

今回の最後のモジュールは、これまで学んだ接続状態、準備キュー、制御チャネルを、1つの診断器にまとめます。性能を競うツールや、任意のアドレスをスキャンするスキャナーではありません。授業の通信は、自分のラボ環境のloopbackでのみ再現し、他人のサーバーを対象に実行しません。外部通信やcapabilityを追加しなくても、重要な境界条件を作れます。

どう動くのか

上限は、複数の層にあります。run(limit=8)は、進行中の接続を最大8個に制限します。しかし、Dialを作るときにソケットをあらかじめ開いていたなら、残りの待機項目もFDを持っています。このラボは、総リストを128個に制限し、制御ソケット2つとselectorのリソースも、別に計算します。limitを8と書いたから、全体のFDが8個だという報告は、間違いです。

Python resourceのRLIMIT_NOFILEは、プロセスが開けるファイル記述子の上限です。これを上げることは、リークの解決ではありません。ソケットだけでなく、ファイル・制御チャネル・selectorまで、どの経路で開いて閉じるかを、先に調べる必要があります。この授業は、ホストの設定やプロセスの上限を変更しません。学習者のファイルを、採点ツールが修正したり削除したりもしません。

実行バジェットを別々に数える

1ターンに、新しい接続をbudget個だけ開始し、完了準備の作業もbudget個だけ処理します。2つは別々のカウンターです。すべての接続がすぐに完了する環境だけをテストすると、2つのバジェットが同じに見えます。採点ツールの決定的なスケジュールテストは、最初の2ターンで完了イベントを保留しておいて、複数をまとめて返します。そのため、開始は制限したのに、完了キューはすべて空にしてしまう誤ったコードも、明らかになります。

入力リストは有限なので、締め切りの検査はリスト全体を走査しても、今回の上限の範囲内です。この構造を数十万の接続に拡大するには、締め切りのヒープやタイマー構造、イベントバッチのメモリコストも検討する必要があります。小さなラボの線形走査を、大規模なシステムにそのまま適用することは、勧めません。

結果をありのままに集計する

各項目は、connected、failed、timed_out、cancelledのいずれかと、errorの整数を残します。connectedの0は、欠落ではありません。error or 기본값(プレースホルダーは既定値です)のように書くと、成功を、情報がないものに変えてしまうことがあります。timed_outは、この診断器の締め切り超過で、cancelledはユーザーの中断です。failedのerrnoは、運用者が次の調査対象を選ぶ手がかりですが、それだけで、ファイアウォール・アプリケーション・ネットワークのどれが原因かは確定できません。

最終的な集計は、総数と4つの状態の件数を示し、失敗系のerrno別の件数を、別に集めます。完了していないpendingを、成功率の分母に黙って混ぜないように、集計の入力で拒否します。この結果は、1回の実行の要約です。時間に沿って累積するメトリクスやレイテンシのヒストグラムを実装したわけではありません。

証拠 確認できること 確認できないこと
実際のTCP listen/bindの対比 接続確立の成功と拒否 TLS・HTTP・業務処理
いっぱいになったsocketpairの待機 締め切りと制御のウェイクアップ 実際のリモートSYNの損失
合成した完了イベントのまとまり ターンごとのバジェットと準備キューの順序 カーネルの公平性の保証
closeのエラー注入 あとのリソースまで後始末するか すべてのOSエラーの組み合わせ

採点ツールのPendingSocketは、実際に接続が遅れているリモートサーバーではありません。connectの結果だけを進行中として返し、いっぱいになったローカルソケットで、書き込みの準備完了がない条件を作ります。この区別を教材に残すのは、模擬テストの結果を、実際のネットワーク検証だと誇張しないためです。

finallyだけでは足りない

後始末のループの最初のcloseで例外が出ると、あとのソケットは閉じられないことがあります。それぞれのソケットの回収を試み、最初の後始末のエラーを保管したあとで、残りと制御チャネルまで後始末する必要があります。エラーは隠さず、最後に伝えます。正常な結果が返ったかどうかだけでなく、失敗のあとにも開いたFDが残っていないかを、確認してください。登録リストから取り除くときも、closeより先にunregisterします。

現場での姿

障害報告には、「テスト通過」の代わりに条件を書きます。対象数、同時上限、作業バジェット、成功・拒否・キャンセル・締め切りの数、終わったあとのFDの回収の有無を残します。CPUが低いというだけで速いとは言えず、スループットが高いというだけで、小さなリクエストが公平に処理されたとは言えません。今回のラボは運用指標の設計の出発点であり、実際のサービスのSLOや負荷の容量を保証するものではありません。

次のラボですること

90分の総合ラボで、接続診断器をステップ8で完成させます。正解が通るかどうかと、それぞれの契約を1つずつ壊した誤答が失敗するかを、あわせて見ます。セッションが終わるとファイルが消えるので、+時間で延長し、重要な成果物は、終了前に別に保管してください。