背景/イントロ:
非常に奇妙な問題です。特定の例外がスローされると、例外が処理されるまで他のすべてのスレッドの実行が停止するように見えます。アプリケーションはプロキシ サーバーであり、ソックス接続を介して N 個の他のプロキシ クライアントに接続する tcp ソケットのプールを介して複数の要求 (任意の時間枠で数百) をパイプします。これは、例外を使用するのではなく、デリゲートを渡すことによっても試行されましたが、同じパフォーマンスの結果が得られませんでした。
通常の運用時のログ スニペット:
14:40:17.700 [PrxSvc:9058] --> [200] 1217ms http://redact.example.com
14:40:17.700 [PrxSvc:9058] C-DEBUG:C
14:40:17.716 [PrxSvc:9058] --> [200] 1098ms http://redact.example.com
14:40:17.716 [PrxSvc:9058] C-DEBUG:C
14:40:17.727 [PrxSvc:9054] --> [200] 905ms http://redact.example.com
14:40:17.727 [PrxSvc:9054] C-DEBUG:C
14:40:17.778 [PrxSvc:9050] --> [200] 453ms http://redact.example.com
14:40:17.778 [PrxSvc:9050] C-DEBUG:C
14:40:17.781 [Unnamed Thread] C-DEBUG:A
14:40:17.781 [Unnamed Thread] C-DEBUG:B
14:40:17.796 [PrxSvc:9058] --> [200] 652ms http://redact.example.com
14:40:17.796 [PrxSvc:9058] C-DEBUG:C
14:40:17.807 [PrxSvc:9056] --> [200] 1555ms http://redact.example.com
14:40:17.807 [PrxSvc:9056] C-DEBUG:C
14:40:17.816 [PrxSvc:9064] --> [200] 396ms http://redact.example.com
ソケット プールはドメインへの接続を再利用しますが、接続が外部サーバーによって閉じられた場合、明らかにこれに関する通知を受け取りません。TcpSocksHandler.TaskHandler メソッドを介してこの接続を再利用しようとすると、次のようになります。
socks.Send(buffer, 0, rcv, SocketFlags.None);
socks.Receive(new byte[1], 0, 1, SocketFlags.Peek);
この例外は、次のようにキャッチされます。
catch
{
//The socket is bad, we should get a new socket.
Log("This socket has expired! - Server has closed the connection.");
Log(String.Format("This socket was {0} seconds old: {1}", seconds, socks.Guid));
socks.Dispose();
Log("C-DEBUG:1");
throw new SocksSocketFailureException(); //throw exception. to bubble back up.
}
これは、呼び出し元のコードによってキャッチされ、次のようにスタックを複数回アップします。
DoHandleRequest{...
try
{
_actualEndPoint = TcpSocksHandler.TaskHandler(socket, context.SocksSocket, 30000000, method);
}
catch (SocksSocketFailureException ssfe)
{
context.SocksSocket = null;
Logger.Log("C-DEBUG:2");
throw;
}
}
ProxyBase.HandleRequest{...
try
{
...
success = DoHandleRequest(context, out bytes);
}
catch (SocksSocketFailureException ssfex)
{
Logger.Log("C-DEBUG:3");
throw;
}
}
ProxyManager.HandleRequest{
while (true)
{
// Pick the best available proxy to handle the request
Logger.Log("C-DEBUG:A");
IProxy proxy = GetNextProxy(context) ?? NullProxy.Instance;
Logger.Log("C-DEBUG:B");
try
{
// Process the request
proxy.HandleRequest(context);
Logger.Log("C-DEBUG:C");
break;
}
catch(SocksSocketFailureException ssfex)
{
Logger.Log("C-DEBUG:4");
}
catch (Exception)
{
break;
}
}
}
以下のログ スニペットから、このパフォーマンス (またはその欠如) を確認できます。
14:40:34.090 [PrxSvc:9068] C-DEBUG:A
14:40:34.090 [PrxSvc:9068] C-DEBUG:B
14:40:34.231 [PrxSvc:9068] This socket has expired! - Server has closed the connection.
14:40:34.231 [PrxSvc:9068] This socket was 6.281049 seconds old: 61cc51b9-f121-4529-9649-7defcc1f5586
14:40:34.231 [PrxSvc:9068] C-DEBUG:1
14:40:34.528 [PrxSvc:9068] C-DEBUG:2
14:40:34.715 [PrxSvc:9068] C-DEBUG:3
14:40:34.918 [PrxSvc:9068] C-DEBUG:4
14:40:34.918 [PrxSvc:9068] C-DEBUG:A
上記のログ行は編集されていません - ほぼ 1 秒間、他に何も処理されていません! (通常、おそらく100のリクエストを処理できます)。さらに、例外をスタックにバブリングするだけでも、1 秒 (場合によってはそれ以上) かかるようです。- 上記のログ行のタイミングに注意してください。例: DEBUG:3 と DEBUG:4 の間に 2 秒のギャップ!!
何が原因なのかわかりません。どんなアドバイスやアイデアも大歓迎です!
アップデート:
Eamon の質問に基づいて、同じ x64 ビルドを、Windows8 64 ビットを実行している非運用のローカル マシンにプッシュしました。前の例のように、サービス、リリース ビルドとしてインストールされます。他の唯一の違いは、以前の 80 ではなく、4 つのプロキシ ノード (PrxSvc 9050、9052、9054、9056) をターゲットにしていることです。今風のファッション:
16:53:59.787 [PrxSvc:9056] This socket has expired! - Server has closed the connection.
16:53:59.787 [PrxSvc:9056] This socket was 0.1280009 seconds old: 69d12cc9-9456-47db-86b2-a2ebf87b41bf
16:53:59.787 [PrxSvc:9056] C-DEBUG:1
16:53:59.787 [PrxSvc:9056] C-DEBUG:2
16:53:59.787 [PrxSvc:9056] C-DEBUG:3
16:53:59.787 [PrxSvc:9056] C-DEBUG:4
16:53:59.787 [PrxSvc:9056] C-DEBUG:A
このマシンでは、コードは現在、1 秒あたり約 80 リクエストの速度で 800 の同時リクエストを問題なく処理しており、さらに多くのリクエストを簡単に処理できます...一体何がこの違いを引き起こしているのでしょうか?!
完全を期すために、最初のテスト (win2008 サーバー上) を 80 ノードではなく 4 ノードで再実行しましたが、同じゴミの結果が得られました。
17:22:44.891 [PrxSvc:9054] C-DEBUG:B
17:22:45.063 [PrxSvc:9054] This socket has expired! - Server has closed the connection.
17:22:45.063 [PrxSvc:9054] This socket was 25.84375 seconds old: cfdee74d-9941-4c8c-80cd-f32aa14b7877
17:22:45.063 [PrxSvc:9054] C-DEBUG:1
17:22:45.485 [PrxSvc:9054] C-DEBUG:2
17:22:45.751 [PrxSvc:9054] C-DEBUG:3
17:22:46.016 [PrxSvc:9054] C-DEBUG:4