なぜTIME_が存在するのかWAIT
7783 ワード
新年の出勤初日、突然socket接続No buffer space availableの問題に遭遇し、インタフェースの大面積呼び出し(webservice,httpclient)に失敗した問題が発生し、サーバーを再起動した後、正常に戻った.
具体的な例外スタック情報は次のとおりです.
ネット上の資料を調べて、基本的に問題をロックすることができます:システムは同時に大きすぎて、接続数が多すぎて、一部のsocket接続は閉鎖を解放することができなくて、持続的な要求はまた解放できないsocket接続が絶えず蓄積して、最終的にNo buffer space availableを招きます.
最も速い解決策:サーバーを再起動し、tomcatを再起動しても機能しないことに注意してください.最終的な解決策を分析します.
サーバを再起動すると、socket接続を最も早く解放できますが、問題は再現されやすく、問題の根本的な解決策ではないことは明らかです.さらに分析する必要がある問題はいくつかあります.
l cmd入力netstat-anを開くと、TIME_に大量に存在することが分かった.WAIT状態のTCP接続、すなわち前述の未解放のソケット接続であり、serverポートが変化しているのはどのような現象なのでしょうか.図のように
lシステムは自動的に接続を閉じる措置がありますか?コードの問題ですか?それとも性能の問題ですか?
以下、これらの問題を分析して解決します.
TIME_WAIT状態の由来
TCPクローズ接続には4回の握手が必要であることを知っています.なぜ4回の握手なのか、接続を確立するように3回の握手ではなく、次の3回の握手と4回の握手のフローチャートを見てみましょう.
3回の握手で接続を確立する概略図
4回の握手で接続を閉じる概略図
上記の3回の握手による接続確立の概略図から分かるように,クライアント側とサーバ側が両方とも相手から送信されたACK応答を受信すれば,双方が接続を確立し,その後データインタラクションを行うことができ,このプロセスには3ステップが必要である.
一方、4回の握手で接続を閉じる模式図では、TCPプロトコルでは、TCP接続を閉じるのがサーバ側(もちろん、どちらからでも開始可能)であり、サーバ側が接続を閉じる要求を開始すると、クライアント側にFINメッセージが送信され、Client側がFINメッセージを受信すると、データが送信される可能性が高いため、すぐにSOCKETを閉じることはないので、まずACKメッセージに返信し、サーバ側に伝える.「あなたが送ったFINメッセージを受け取りました」.Client側のすべてのメッセージが送信された後、Client側はサーバ側にFINメッセージを送信し、Client側は閉じた状態に入り、データを送信しない.
サーバ側はFINメッセージを受信すると、接続を閉じることができることを知っていますが、ネットワークは信頼できません.Client側はサーバ側が閉じることを知らないので、サーバ側はACKを送信してTIME_に入ります.WAIT状態で、Client側がACKを受信していない場合、サーバセグメントは再送信可能である.Client側がACKを受け取ると、接続を切断できることがわかります.Server側は2 MSL(Max Segment Lifetime、最大メッセージ生存時間)を待っても返信を受け取っていないため、Client側が正常に切断されていることを証明し、この時、Server側も接続を切断することができます.2 MSLのTIME_WAIT待ち時間はここからです.
分かったTIME_WAITの由来、TIME_WAIT状態の最大保持時間は2*MSLで、1-4分の間にあるので、システムが同時に大きすぎると、Client-Server接続数が多すぎて、Server端は1-4分以内に大量のTIME_WAIT状態で解放できないsocket接続は、サーバの効率を急激に低下させ、サーバのすべてのリソースを消費し、最終的にNo buffer space available(maximum connections reached?): connect
問題の発生.
ポートの変化の由来
大規模なアプリケーションでは、アクセスが高く、1台のサーバがサービスニーズを満たすことができない場合が多い.この場合、複数のサーバが共同で対外的にサービスを提供する必要がある.複数のサーバのリソースを最大限に活用して要求を処理するには、スケジューリングを要求し、要求を各サーバに合理的に均一に割り当てる必要があります.
LVS(Linux Virtual Server)クラスタ技術は、このニーズを実現する方法の一つです.IP負荷等化技術とコンテンツリクエストに基づく配信技術を採用している.スケジューラはスループットに優れ、要求を異なるサーバに均等に移行して実行し、スケジューラはサーバの障害を自動的に遮断し、高性能で高可用性の仮想サーバを構成します.
LVSクラスタは三層構造を採用し、その主な構成部分は以下の通りである.
l負荷等化スケジューラ(load balancer)は、クラスタ全体が外部のフロントエンドマシンに対して、顧客の要求をサーバのセットに送信して実行する責任を負い、顧客はサービスがIPアドレス(仮想IPアドレスと呼ぶことができる)から来ていると考えている.
lサーバプール(server pool)は、実際に顧客要求を実行するサーバのグループであり、実行するサービスはWEB、MAIL、FTP、DNSなどである.
l共有ストレージ(shared storage)は、サーバプールに共有ストレージ領域を提供し、サーバプールが同じコンテンツを持ち、同じサービスを提供することを容易にする.
その構造は下図の通りです.
LVS構造概略図
LVS構造の概略図から分かるように、バックエンドから見るとLoad BalancerからバックエンドサーバまでのIPのパケットのソースIPアドレスは同じ(Load BalancerのIPアドレスとサーバのIPアドレスは同じセグメントに属する)であり、クライアントはサービスが1つのIPアドレス(実際にはLoad BalancerのIP)から来ていると考えている.load Balencerは負荷均衡を行うため、実際には、サーバ1がTIME_にある場合、クライアントがどのサーバに接続するか分からない新しい接続ごとに新しいセッションが確立されます.WAITはクライアントが1つのload balencerしか見えないため、クライアントは他のサーバが存在することを知らず、(すべての)サーバがTIME_にあると考えられるWAIT状態、頻繁なTCP接続の確立と閉鎖により、Load BalancerからバックエンドサーバへのTCP接続が制限され、サーバに多くのTIME_が残るWAIT状態の接続であり、これらの状態に対応するリモートIPアドレスはすべてLoad Balancerである.Load Balancerのポートは最大で60000個以上(2^16=65536,1~1023は予約ポートであり、その他のポートはデフォルトでは使用されないものもある)であり、各Load BalancerのポートがサーバのTIME_に入るとWAITブラックリストでは、240秒でサーバとの接続を確立できないため、Load Balancerとサーバの接続は限られています.したがって、netstat-anコマンドを使用してネットワーク接続状況を表示すると、同じremote IPに多くのポートが表示されます.
上記の分析から、No buffer space availableという問題の原因は多岐にわたっており、原因と解決策は以下の通りである.
lコード面から見ると、webserviceまたはhttpclient呼び出しは接続解放されず、リソースが回収できない.
解決策はaxis 2のクライアントコードで接続を閉じることです.以下のようにします.
stub._getServiceClient().cleanupTransport(); stub._getServiceClient().cleanup(); stub.cleanup(); stub = null;
タイムリーなシャットダウンとcleanは、メモリオーバーフローの問題を効果的に回避し、リソースをタイムリーに回収します.
またはhttpClientで最終的にfinallyでresponseを呼び出す.close()またはhttpPost.releaseConnection()を使用して接続を解除します.
lシステムの面から見ると、システムのsocket接続数の設定は合理的ではなく、socket接続数が小さすぎて、上限に達しやすい.次に2 MSLの設定が長すぎてTIMEが溜まりやすいWAIT状態のTCP接続.
解決策はLinuxカーネルパラメータを変更することです.
システムsocketの最大接続数をファイル/etc/security/limitsで変更します.confは最後に次の2行を追加します.
* soft nofile 32768
* hard nofile 32768
あるいは2 MSLの時間を縮小し、TIME_に再利用を許可するWAIT状態のTCP接続、クイックリサイクルはTIME_WAIT状態のTCP接続、修正/etc/sysctl.conf、次の行を追加します.
#システムのデフォルトのTIMEOUT時間netを変更する.ipv4.tcp_fin_timeout=2
#再利用を開始し、TIME_を許可WAITソケットが新しいTCP接続に再利用するデフォルトは0でnetを閉じることを示す.ipv4.tcp_tw_reuse=1
#TCP接続中TIME_を開くWAIT socketsの迅速な回収は0がnetを閉じることを示すと考えている.ipv4.tcp_tw_recycle=1
Windows環境では、レジストリを変更して構成できます.
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
DWORDタイプの値TcpTimedWaitDelayを追加します.値は実際の状況に応じて構成できます.
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters
DWORDタイプの値MaxUserPortを追加します.値は実際の状況に応じて構成できます.
上記のパラメータは、実際の状況に応じて構成されています.
l LVSレベルではスケジューリングアルゴリズムが不合理であり,あるサーバに要求が多すぎる.
解決策は、実際の状況に応じて合理的な負荷分散ソリューションを指定します.
lセキュリティ面から見ると、サーバーがDDoS(サービス拒否***)に遭った場合、サーバーはTIME_を大量に蓄積する.WAIT状態のTCP接続で外部へのサービス提供ができない.
出典:http://www.itwenku.net/dev/20160108/1961.html
問題の詳細
具体的な例外スタック情報は次のとおりです.
Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connect
at org.apache.axis.AxisFault.makeFault(AxisFault.java:101)
at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:154)
at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
at org.apache.axis.client.AxisClient.invoke(AxisClient.java:165)
at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
at org.apache.axis.client.Call.invoke(Call.java:2767)
at org.apache.axis.client.Call.invoke(Call.java:2443)
at org.apache.axis.client.Call.invoke(Call.java:2366)
at org.apache.axis.client.Call.invoke(Call.java:1812)
Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:519)
at sun.reflect.GeneratedMethodAccessor24.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.axis.components.net.DefaultSocketFactory.create(DefaultSocketFactory.java:153)
at org.apache.axis.components.net.DefaultSocketFactory.create(DefaultSocketFactory.java:120)
at org.apache.axis.transport.http.HTTPSender.getSocket(HTTPSender.java:191)
at org.apache.axis.transport.http.HTTPSender.writeToSocket(HTTPSender.java:404)
at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:138)
ネット上の資料を調べて、基本的に問題をロックすることができます:システムは同時に大きすぎて、接続数が多すぎて、一部のsocket接続は閉鎖を解放することができなくて、持続的な要求はまた解放できないsocket接続が絶えず蓄積して、最終的にNo buffer space availableを招きます.
最速の解決策
最も速い解決策:サーバーを再起動し、tomcatを再起動しても機能しないことに注意してください.最終的な解決策を分析します.
もんだいぶんせき
サーバを再起動すると、socket接続を最も早く解放できますが、問題は再現されやすく、問題の根本的な解決策ではないことは明らかです.さらに分析する必要がある問題はいくつかあります.
l cmd入力netstat-anを開くと、TIME_に大量に存在することが分かった.WAIT状態のTCP接続、すなわち前述の未解放のソケット接続であり、serverポートが変化しているのはどのような現象なのでしょうか.図のように
lシステムは自動的に接続を閉じる措置がありますか?コードの問題ですか?それとも性能の問題ですか?
以下、これらの問題を分析して解決します.
TIME_WAIT状態の由来
TCPクローズ接続には4回の握手が必要であることを知っています.なぜ4回の握手なのか、接続を確立するように3回の握手ではなく、次の3回の握手と4回の握手のフローチャートを見てみましょう.
3回の握手で接続を確立する概略図
4回の握手で接続を閉じる概略図
上記の3回の握手による接続確立の概略図から分かるように,クライアント側とサーバ側が両方とも相手から送信されたACK応答を受信すれば,双方が接続を確立し,その後データインタラクションを行うことができ,このプロセスには3ステップが必要である.
一方、4回の握手で接続を閉じる模式図では、TCPプロトコルでは、TCP接続を閉じるのがサーバ側(もちろん、どちらからでも開始可能)であり、サーバ側が接続を閉じる要求を開始すると、クライアント側にFINメッセージが送信され、Client側がFINメッセージを受信すると、データが送信される可能性が高いため、すぐにSOCKETを閉じることはないので、まずACKメッセージに返信し、サーバ側に伝える.「あなたが送ったFINメッセージを受け取りました」.Client側のすべてのメッセージが送信された後、Client側はサーバ側にFINメッセージを送信し、Client側は閉じた状態に入り、データを送信しない.
サーバ側はFINメッセージを受信すると、接続を閉じることができることを知っていますが、ネットワークは信頼できません.Client側はサーバ側が閉じることを知らないので、サーバ側はACKを送信してTIME_に入ります.WAIT状態で、Client側がACKを受信していない場合、サーバセグメントは再送信可能である.Client側がACKを受け取ると、接続を切断できることがわかります.Server側は2 MSL(Max Segment Lifetime、最大メッセージ生存時間)を待っても返信を受け取っていないため、Client側が正常に切断されていることを証明し、この時、Server側も接続を切断することができます.2 MSLのTIME_WAIT待ち時間はここからです.
分かったTIME_WAITの由来、TIME_WAIT状態の最大保持時間は2*MSLで、1-4分の間にあるので、システムが同時に大きすぎると、Client-Server接続数が多すぎて、Server端は1-4分以内に大量のTIME_WAIT状態で解放できないsocket接続は、サーバの効率を急激に低下させ、サーバのすべてのリソースを消費し、最終的にNo buffer space available(maximum connections reached?): connect
問題の発生.
ポートの変化の由来
大規模なアプリケーションでは、アクセスが高く、1台のサーバがサービスニーズを満たすことができない場合が多い.この場合、複数のサーバが共同で対外的にサービスを提供する必要がある.複数のサーバのリソースを最大限に活用して要求を処理するには、スケジューリングを要求し、要求を各サーバに合理的に均一に割り当てる必要があります.
LVS(Linux Virtual Server)クラスタ技術は、このニーズを実現する方法の一つです.IP負荷等化技術とコンテンツリクエストに基づく配信技術を採用している.スケジューラはスループットに優れ、要求を異なるサーバに均等に移行して実行し、スケジューラはサーバの障害を自動的に遮断し、高性能で高可用性の仮想サーバを構成します.
LVSクラスタは三層構造を採用し、その主な構成部分は以下の通りである.
l負荷等化スケジューラ(load balancer)は、クラスタ全体が外部のフロントエンドマシンに対して、顧客の要求をサーバのセットに送信して実行する責任を負い、顧客はサービスがIPアドレス(仮想IPアドレスと呼ぶことができる)から来ていると考えている.
lサーバプール(server pool)は、実際に顧客要求を実行するサーバのグループであり、実行するサービスはWEB、MAIL、FTP、DNSなどである.
l共有ストレージ(shared storage)は、サーバプールに共有ストレージ領域を提供し、サーバプールが同じコンテンツを持ち、同じサービスを提供することを容易にする.
その構造は下図の通りです.
LVS構造概略図
LVS構造の概略図から分かるように、バックエンドから見るとLoad BalancerからバックエンドサーバまでのIPのパケットのソースIPアドレスは同じ(Load BalancerのIPアドレスとサーバのIPアドレスは同じセグメントに属する)であり、クライアントはサービスが1つのIPアドレス(実際にはLoad BalancerのIP)から来ていると考えている.load Balencerは負荷均衡を行うため、実際には、サーバ1がTIME_にある場合、クライアントがどのサーバに接続するか分からない新しい接続ごとに新しいセッションが確立されます.WAITはクライアントが1つのload balencerしか見えないため、クライアントは他のサーバが存在することを知らず、(すべての)サーバがTIME_にあると考えられるWAIT状態、頻繁なTCP接続の確立と閉鎖により、Load BalancerからバックエンドサーバへのTCP接続が制限され、サーバに多くのTIME_が残るWAIT状態の接続であり、これらの状態に対応するリモートIPアドレスはすべてLoad Balancerである.Load Balancerのポートは最大で60000個以上(2^16=65536,1~1023は予約ポートであり、その他のポートはデフォルトでは使用されないものもある)であり、各Load BalancerのポートがサーバのTIME_に入るとWAITブラックリストでは、240秒でサーバとの接続を確立できないため、Load Balancerとサーバの接続は限られています.したがって、netstat-anコマンドを使用してネットワーク接続状況を表示すると、同じremote IPに多くのポートが表示されます.
最終的な解決策
上記の分析から、No buffer space availableという問題の原因は多岐にわたっており、原因と解決策は以下の通りである.
lコード面から見ると、webserviceまたはhttpclient呼び出しは接続解放されず、リソースが回収できない.
解決策はaxis 2のクライアントコードで接続を閉じることです.以下のようにします.
stub._getServiceClient().cleanupTransport(); stub._getServiceClient().cleanup(); stub.cleanup(); stub = null;
タイムリーなシャットダウンとcleanは、メモリオーバーフローの問題を効果的に回避し、リソースをタイムリーに回収します.
またはhttpClientで最終的にfinallyでresponseを呼び出す.close()またはhttpPost.releaseConnection()を使用して接続を解除します.
lシステムの面から見ると、システムのsocket接続数の設定は合理的ではなく、socket接続数が小さすぎて、上限に達しやすい.次に2 MSLの設定が長すぎてTIMEが溜まりやすいWAIT状態のTCP接続.
解決策はLinuxカーネルパラメータを変更することです.
システムsocketの最大接続数をファイル/etc/security/limitsで変更します.confは最後に次の2行を追加します.
* soft nofile 32768
* hard nofile 32768
あるいは2 MSLの時間を縮小し、TIME_に再利用を許可するWAIT状態のTCP接続、クイックリサイクルはTIME_WAIT状態のTCP接続、修正/etc/sysctl.conf、次の行を追加します.
#システムのデフォルトのTIMEOUT時間netを変更する.ipv4.tcp_fin_timeout=2
#再利用を開始し、TIME_を許可WAITソケットが新しいTCP接続に再利用するデフォルトは0でnetを閉じることを示す.ipv4.tcp_tw_reuse=1
#TCP接続中TIME_を開くWAIT socketsの迅速な回収は0がnetを閉じることを示すと考えている.ipv4.tcp_tw_recycle=1
Windows環境では、レジストリを変更して構成できます.
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
DWORDタイプの値TcpTimedWaitDelayを追加します.値は実際の状況に応じて構成できます.
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters
DWORDタイプの値MaxUserPortを追加します.値は実際の状況に応じて構成できます.
上記のパラメータは、実際の状況に応じて構成されています.
l LVSレベルではスケジューリングアルゴリズムが不合理であり,あるサーバに要求が多すぎる.
解決策は、実際の状況に応じて合理的な負荷分散ソリューションを指定します.
lセキュリティ面から見ると、サーバーがDDoS(サービス拒否***)に遭った場合、サーバーはTIME_を大量に蓄積する.WAIT状態のTCP接続で外部へのサービス提供ができない.
出典:http://www.itwenku.net/dev/20160108/1961.html