IOCPおよびEPOLLサーバー向けのTCPKeepAliveとKeepAliveTimeout | eSeGeCe ブログ

IOCPおよびEPOLLサーバー向けのTCPKeepAliveとKeepAliveTimeout

· コンポーネント
sgcWebSockets TCPKeepAliveとKeepAliveTimeout(IOCPおよびEPOLL向け)

sgcWebSocketsのIOCP(Windows)およびEPOLL(Linux)サーバーエンジンは、接続ごとに1スレッドを割り当てるのではなく、少数のスレッドプールで数千の接続を処理します。これが、高い同時接続負荷がかかるサーバーにとって最適な選択である理由です。しかし、これまでは、さよならも言わずに黙ってしまった相手に気づく手段がありませんでした。新しい2つのオプション、TCPKeepAliveKeepAliveTimeoutが、このギャップを埋めます。

沈黙した相手はイベントを発生させない

IOCPとEPOLLはイベント駆動型です。エンジンは、ソケットにデータがある、クローズされた、あるいはエラーが発生したとオペレーティングシステムが通知するまでスリープします。これは、クリーンなFINやRSTを送信せずに相手が消えてしまうまでは、うまく機能します。たとえば、クラッシュするクライアント、アイドル状態のマッピングを破棄するNATやファイアウォール、あるいは黙って変わってしまうルートなどです。そのソケットに対してイベントは二度と届かないため、接続はサーバー上でESTABLISHEDのまま無期限に残り続けます。

従来の、接続ごとに1スレッドを使うIOHandlerにはこの問題がありません。各接続はタイムアウト付きの読み取りでブロックするため、沈黙した接続はその読み取りが次にタイムアウトした時点で検知され、解放されるからです。IOCPとEPOLLにはこれに相当する仕組みがありませんでしたが、今回の2つの新しいオプションはまさにそれを追加するものです。

TCPKeepAlive: オペレーティングシステムに監視させる

TCPKeepAliveを有効にすると、接続がTime秒間アイドル状態になった時点で、オペレーティングシステム自体が接続へのプローブを開始し、相手が応答するか接続が切断されるまでInterval秒ごとに繰り返します。デフォルトでは無効になっており、以下の値は有効にした場合のデフォルト値と一致します。

Server.IOHandlerOptions.IOHandlerType := iohEPOLL;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Enabled  := True;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Time     := 60;  // seconds idle before probing
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Interval := 10;  // seconds between probes

Windowsサーバーでは、同じ3つのプロパティがIOHandlerOptions.IOCP.TCPKeepAliveの下にあります。

KeepAliveTimeout: アプリケーションレベルのアイドルタイムアウト

KeepAliveTimeoutは、これとは異なる、より直接的なアプローチを取ります。オペレーティングシステムのキープアライブプローブがどう判断するかに関わらず、指定した秒数を超えてアイドル状態が続いた接続をすべてクローズします。これは、接続ごとに1スレッドを使うIOHandlerが沈黙した接続を解放する仕組みに最も近いものであり、デフォルトでは無効(値は0)になっており、影響を受けるのは本当にアイドル状態の接続だけです。読み取り中のリクエストや書き込み中のレスポンスがこれによって中断されることは決してありません。

Server.IOHandlerOptions.EPOLL.KeepAliveTimeout := 120; // seconds

// Windows
Server.IOHandlerOptions.IOCP.KeepAliveTimeout := 120;

想定される最も遅いリクエストやレスポンスよりも十分に余裕を持った値、たとえば一般的なHTTPやWebSocketサーバーであれば120秒程度に設定してください。そうすることで、本当に死んでいる接続は速やかに回収されつつ、単に遅いだけの接続には一切触れずに済みます。

切断を検知する第3の方法

sgcWebSocketsには、相手がいなくなったことに気づくための方法がすでに2つありました。1つはTsgcWebSocketClientCleanDisconnectを有効にし、行儀の良いクライアントが去る前にサーバーへ知らせる方法、もう1つはサーバー側でheartbeatを実行し、一定間隔ですべてのクライアントにpingを送る方法です。どちらも協力が前提であり、前者はクライアント側の協力に、後者は自前のping/pongのやり取りに依存します。TCPKeepAliveKeepAliveTimeoutは、そうした協力を一切必要としない初めての選択肢です。サーバーが完全に単独で、死んだ接続を検知します。

提供状況

どちらのオプションも、Delphiおよび C++ Builder 7から13向けのsgcWebSocketsで今すぐ利用でき、既存のEPOLLThreadsIOCPThreadsWorkOpThreads設定と並んで、IOHandlerOptions.EPOLLIOHandlerOptions.IOCPの下に用意されています。デフォルトでは無効になっているため、有効にしない限り既存のサーバーには何も変わりません。

トライアル版をダウンロードし、IOCPとEPOLLの詳細なリファレンスはsgcWebSockets製品ページでご覧いただけます。

ご質問やご意見がありましたら、お問い合わせください。実際にコードを書いた担当者から返信いたします。