私のアプリケーションが特定のURLをポーリングし、htmlと応答時間が戻られる(HTTP / 2が有効になっている)私のTomcatサーバに約千のPOSTリクエスト/分をお送りします、私は再利用のTCP接続に真のhttp / 2の多重化を実現したいです私のアプリケーションとTomcatサーバー間。私のクライアントの用途はokhttpと私は正常に長い時間のためにそれを接続を確立し、再利用することができますが、とき(キューに入れられたようなもの、:50、ランニング:50)要求カウントの数が増加し、また、応答時間が増加し(それは2000ms-にスパイク通常、300msの-500msのを取るとさらに悪い15000msまたは、)。私は、オープン複数のTCP接続することを決定しましたので、これが原因であまりにも多くの要求とのTCP接続のオーバーロードで起こっている理解し、それがTCPコネクション間で要求の負荷を分散できるようにすることができます。私が使用して複数の接続を開くために、クライアントを強制します
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(100);
dispatcher.setMaxRequestsPerHost(5);
ConnectionPool cp = new ConnectionPool(5, 5, TimeUnit.MINUTES);
wiresharkのの助けを借りて、私は開かれた5つの接続を確認しても、要求の4は最初のハンドシェイクが成功した直後に閉鎖されている見ることができ、私はそれがHTTP / 2多重化の期待されるふるまいのかどうかわかりません。
その者が行動を期待している場合、どのように私はそれがピーク負荷時に各要求の応答時間を短縮するために最適化することができますか?
またはそれは、ピーク負荷時の負荷を分散するために複数の接続を使用することが可能でしょうか?
私のサンプルプログラムで次のように、
Security.insertProviderAt(Conscrypt.newProvider(), 1);
sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
}, new java.security.SecureRandom());
sslSocketFactory = sslContext.getSocketFactory();
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(100);
dispatcher.setMaxRequestsPerHost(5);
ConnectionPool cp = new ConnectionPool(5, 1, TimeUnit.DAYS);
okHttpClient = new OkHttpClient().newBuilder()
.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustManager[0])
.dispatcher(dispatcher)
.connectionPool(cp)
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
.build();
私たちは、jdk8自体にALPNを有効にするためにconscrytを使用します
try {
String url = "https://localhost:8081/myAent/getOutput?1000000004286_1520339351002_"+System.currentTimeMillis();
String json = "<?xml version=\"1.0\" standalone=\"no\"?><UC mid=\"1000000005011\" pollNow=\"true\" use_ipv6=\"false\" rca=\"0\" rcaFN=\"P|TA|D|J|M\" pFtct=\"\" sFtct=\"\" issecondarydc=\"false\" ssDc=\"false\" nocache=\"1\" storeHtmlResp=\"true\" storeTroubleScrnSht=\"false\" moConfig=\"false\" xconlen=\"8265\" noScreenshotRecheckForSSLErrors=\"true\" avgDnsTime=\"null\" isProxyRequired=\"false\" userroles=\"EVAL_USER\" uid=\"102030230293029021\" retryDelay=\"2\" retry=\"true\" idcLocUrl=\"http://localhost:8080/app/receivemultipartdata\" isRemoteAgent=\"true\" sendHeaders=\"false\" api=\"ab_345nnn4l4lj4lk23nl4k23342lk4l23j4\" ut=\""+(System.currentTimeMillis()+"")+"\" mt=\"URL\" dctimeout=\"70\" pollinterval=\"1440\" locid=\"48\" log=\"1\" currentstatus=\"1\" postUrl=\"https://example.com\"><Url acc=\"\" forced_ips=\"\" use_ipv6=\"false\" client_cert=\"\" mid=\"1000000005011\" sotimeout=\"60\" ua=\"\" ds=\"117.20.43.94\" ucc=\"\" md=\"false\" client_cert_pass=\"\" context=\"default\" unavail_alert=\"\" ssl_protocol=\"\" avail_alert=\"\" enabledns=\"false\" enableBouncyCastle=\"false\" cc=\"false\" a=\"https://www.example.com/tools.html\" upStatusCodes=\"\" regex_alert=\"\" probeproxy=\"false\" m=\"G\" keyword_case=\"0\" regex=\"\" rbc=\"\" t=\"30\" lc=\"English\"><PD></PD><CH hn=\"\" hd=\"_sep_\" hv=\"\"/><AI ps=\"\" un=\"\"/></Url></UC>";
RequestBody body = RequestBody.create(MediaType.get("application/json; charset=utf-8"), json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
long nanoStartTime = System.nanoTime();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("okhttp3:: Request failed"+ e);
}
@Override
public void onResponse(Call call, okhttp3.Response responseObj) throws IOException {
try (ResponseBody body = responseObj.body()) {
long nanoEndTime = System.nanoTime();
long nanoDiffTime = TimeUnit.NANOSECONDS.toMillis(nanoEndTime - nanoStartTime);
System.out.println("okhttp3:: Succeded response ***"+body+"$$$");
System.out.println("okhttp3:: Request Succeded protocol ***"+responseObj.protocol()+"$$$, time is "+nanoDiffTime);
}
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
どのように私は、要求の負荷を分散するためにachieveing HTTP / 2多重化するための複数のTCPソケット/接続を使用するokhttpclient最適化することができます。
クライアント:Tomcatのapacheの - 9.0.xの、JDK - 8は、httpライブラリ - Okhttp3、Osの - Ubuntuの/ CentOSに、セキュリティプロバイダ - Conscrypt(JDK 8にALPNをサポートするため)。
サーバ:Tomcatのapacheの - 9.0.16、JDK -10.0.1、Osの - Ubuntuの/ CentOSに、OpenSSLの - TLSv1.3のサポートのための1.1.1a
あなたが見ていることはOkHttpに合体接続の結果です。OkHttpは、HTTP / 2接続は(HTTP / 1.1対)を確立するかどうかを事前に把握していないので、続行するための接続のsetMaxRequestsPerHost値ができます。現在ありません*これらはすぐにあなたが見ているものである単一の接続に合体されているので、何もクライアント側のロードバランシングは、。
現在、あなたは複数のクライアント、または完全に異なるホストとの接続の慎重な管理を通じてこれを達成することができます。NB OkHttpは、単一の接続がサブジェクト代替名の重複、複数例えばSSL証明書の指定よりも優れている典型的なケースのためにここにあなたと最適化に対して動作します
*サポートのために、この問題をフォローhttps://github.com/square/okhttp/issues/4530