web-dev-qa-db-ja.com

TIME-WAIT状態のソケット数が多く、サーバーがロード時に応答しない

高負荷でアプリが応答しなくなり、待機時間が長くなりました。プロセスの使用率が異常に低かった(プロセスあたりのCPU使用率は約15%、アプリは8つのプロセスで実行されます)。

Nginxエラーログの出力には、次の数が示されました。

2014/12/04 03:39:31 [crit] 24383#0: *2008067 connect() to 127.0.0.1:4567 failed (99: Cannot assign requested address) while connecting to upstream, client: 108.162.246.229, server: example.org, request: "GET /socket.io/?EIO=3&transport=polling&t=1417682366937-11501 HTTP/1.1", upstream: "http://127.0.0.1:4567/socket.io/?EIO=3&transport=polling&t=1417682366937-11501", Host: "example.org", referrer: "https://example.org/unread"

私が見たもの

  • ss -tan | grep TIME-WAIT | wc -lの出力は、30,000近くのどこかにありました。
  • アプリは応答し、その後:
    • すべてのプロセスが突然CPU使用率が0近くまで低下する
    • アプリが応答しなくなる
    • 〜30秒後、アプリはバックアップされ、無限に繰り返します

アプリを起動する必要があるため、応急処置ソリューション:

  • echo 28000 65535 > ip_local_port_range(MongoDBは27101で実行されるため、それよりも低い上限を選択しました)
  • echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
  • echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle

これにより、TIME-WAIT状態のソケットの数がより管理しやすい〜400に減少しました。


ss -tan | grep TIME-WAITのスニペットは次のとおりです:

State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
TIME-WAIT  0      0                 127.0.0.1:29993            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:28522            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:29055            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:31849            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:32744            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:28304            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:34858            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:36707            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:34756            127.0.0.1:4567  
TIME-WAIT  0      0            104.131.91.122:443          108.162.250.6:55549 
TIME-WAIT  0      0                 127.0.0.1:32629            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:34544            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:34732            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:33820            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:33609            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:34504            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:32463            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:35089            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:30003            127.0.0.1:4567  
TIME-WAIT  0      0            104.131.91.122:443         199.27.128.100:36383 
TIME-WAIT  0      0                 127.0.0.1:33040            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:34038            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:28096            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:29541            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:30022            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:31375            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:29827            127.0.0.1:4567  
TIME-WAIT  0      0                 127.0.0.1:29334            127.0.0.1:4567  

私の質問:

  • これらの多くは127.0.0.1から127.0.0.1ですが、これは正常ですか?ピアアドレスはすべて外部IPからのものではありませんか?
    • Node.jsアプリはnginxプロキシの背後にあり、CloudFlare DNSの背後にあります。これにより、一意の受信IPアドレスの数が制限されますが、これは関連しているのでしょうか?
  • どのようにして適切にTIME-WAIT状態のソケットの数を減らしますか?
  • 3000の一意のソケット接続がないことは確かです毎秒、何かが私たちの側で誤って構成されており、1つを開く必要があるときに何百ものソケットを開くのですか?

あなたが提供できるあらゆる助けを事前に感謝します!

4
Julian H. Lam

最後に、私はより多くの調査を行い、これを読みました 非常に優れたガイド スケーリングについてNode nginxプロキシの背後にあるアプリ。

大きな違いは、nginxのkeepaliveブロックにupstreamパラメータを追加したときです。結局のところ、nginxワーカーは着信接続をキャッシュして再利用しないため、何千もの新しい接続が作成されます(特に、socket.ioハンドシェイクなど)。

@MichaelHamptonの提案によるUNIXドメインソケットの使用も、これを非常にうまく解決します。

2
Julian H. Lam