アプリケーションの説明:
- Comsat の Quasar FiberHttpClient (バージョン 0.7.0) によってラップされた Apache HTTP Async Client (バージョン 4.1.1) を使用して、複数の HTTP エンドポイントに HTTP 要求を内部的に送信するためにファイバーを使用する高度な並行 Java アプリケーションを実行および実行します。
- アプリケーションは tomcat 上で実行されます (ただし、ファイバーは内部要求のディスパッチにのみ使用されます。Tomcat サーブレット要求は引き続き標準のブロッキング方法で処理されます)。
- 各外部リクエストは内部で 15 ~ 20 のファイバーを開き、各ファイバーは HTTP リクエストを作成し、FiberHttpClient を使用してそれをディスパッチします。
- アプリケーションをテストするために c44xlarge サーバー (16 コア) を使用しています
- つまり、ソケットを再利用して維持しようとすると、リクエストの実行試行中に接続が閉じられます。そのため、接続のリサイクルを無効にします。
上記のセクションによると、私のファイバー http クライアントの調整は次のとおりです (もちろん、私は の単一のインスタンスを使用しています)。
PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager( new DefaultConnectingIOReactor( IOReactorConfig. custom(). setIoThreadCount(16). setSoKeepAlive(false). setSoLinger(0). setSoReuseAddress(false). setSelectInterval(10). build() ) ); connectionManager.setDefaultMaxPerRoute(32768); connectionManager.setMaxTotal(131072); FiberHttpClientBuilder fiberClientBuilder = FiberHttpClientBuilder. create(). setDefaultRequestConfig( RequestConfig. custom(). setSocketTimeout(1500). setConnectTimeout(1000). build() ). setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE). setConnectionManager(connectionManager). build();
open-files の ulimits は非常に高く設定されています (ソフト値とハード値の両方で 131072 )
- Eden は 18GB に設定され、合計ヒープ サイズは 24GB です
- OS Tcp スタックも適切に調整されています。
kernel.printk = 8 4 1 7 kernel.printk_ratelimit_burst = 10 kernel.printk_ratelimit = 5 net.ipv4.ip_local_port_range = 8192 65535 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.core.rmem_default = 16777216 net.core .wmem_default = 16777216 net.core.optmem_max = 40960 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 65536 16777216 net.core.netdev_max_backlog = 100000 net.ipv4.tcp_max_syn_backlog = 100000 net.ipv4.tcp_max_tw_buckets = 2000000 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 10 net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.tcp_sack = 0 net.ipv4.tcp_timestamps = 1
問題の説明
- 低中負荷ではすべて問題なく、接続はリースされ、クローズされ、プールが補充されます
- いくつかの同時実行ポイントを超えると、IOReactor スレッド (16 個) は、死ぬ前に適切に機能しなくなったようです。
- プールの統計を取得して毎秒出力する小さなスレッドを作成しました。約 25K のリース接続で、実際のデータはソケット接続を介して送信されなくなり、
Pending
統計は急増する 30K の保留中の接続要求にも上昇します。 - この状況は持続し、基本的にアプリケーションは役に立たなくなります。ある時点で、I/O Reactor スレッドが停止します。いつ発生するかわからないため、これまで例外をキャッチできませんでした
lsof
Javaプロセスを実行すると、何万ものファイル記述子があり、それらのほとんどすべてがCLOSE_WAITにあることがわかります(これは、I / Oリアクタースレッドが機能しなくなったり停止したりして、実際にそれらを閉じることができないためです)- アプリケーションが中断している間、サーバーが過度に過負荷になったり、CPU に負荷がかかったりすることはありません
質問
- 私はどこかである種の境界に到達していると推測していますが、それが何またはどこに存在するかについてはまったくわかりません. 以下を除く
- OSポートに到達している可能性はありますか(すべての適用可能なリクエストは結局単一の内部IPから発信されています)制限し、IO Reactorスレッドを停止させるエラー(open files limit errorsに似たもの)を作成しますか?