6

アプリケーションの説明:

  • 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 スレッドが停止します。いつ発生するかわからないため、これまで例外をキャッチできませんでした
  • lsofJavaプロセスを実行すると、何万ものファイル記述子があり、それらのほとんどすべてがCLOSE_WAITにあることがわかります(これは、I / Oリアクタースレッドが機能しなくなったり停止したりして、実際にそれらを閉じることができないためです)
  • アプリケーションが中断している間、サーバーが過度に過負荷になったり、CPU に負荷がかかったりすることはありません

質問

  • 私はどこかである種の境界に到達していると推測していますが、それが何またはどこに存在するかについてはまったくわかりません. 以下を除く
  • OSポートに到達している可能性はありますか(すべての適用可能なリクエストは結局単一の内部IPから発信されています)制限し、IO Reactorスレッドを停止させるエラー(open files limit errorsに似たもの)を作成しますか?
4

1 に答える 1

2

これに答えるのを忘れましたが、質問を投稿してから約1週間後に何が起こっているのかわかりました:

  1. io-reactor が 2 つのスレッドのみでスポーンする原因となる、ある種の設定ミスがありました。

  2. より多くのリアクター スレッドを提供した後でも、問題は解決しませんでした。送信リクエストのほとんどが SSL であることがわかりました。Apache SSL 接続処理は、コア処理を JVM の SSL 機能に伝達します。これは、1 秒あたり数千の SSL 接続要求を処理するには効率的ではありません。より具体的に言えば、SSLEngine 内のいくつかのメソッド (私の記憶が正しければ) が同期されます。高負荷下でスレッド ダンプを実行すると、SSL 接続を開こうとしているときに、IORecator スレッドが互いにブロックしていることがわかります。

  3. 接続リースタイムアウトの形式で圧力解放バルブを作成しようとしても、作成されたバックログが大きすぎてアプリケーションが役に立たなくなったため、機能しませんでした。

  4. SSL 発信リクエスト処理を nginx にオフロードすると、パフォーマンスがさらに低下します。リモート エンドポイントがリクエストをプリエンプティブに終了しているため、SSL クライアント セッション キャッシュを使用できませんでした (JVM 実装についても同様です)。

モジュール全体の前にセマフォを配置し、特定の瞬間に全体を最大6000に制限して、問題を解決しました。

于 2017-03-06T06:22:29.483 に答える