1
Apache HTTPClient 4.3.6接続プールマネージャを試して、HTTP呼び出しのスループットを向上させようとしています。私の前提は、HTTPClientの実装は一般的に永続性接続を使用していることです。しかし、私のテストコードの結果(最後に含まれています)では、JDK URLConnection
を使用した複数の同時HTTP接続のパフォーマンスが向上しています。Apache HTTPClient 4.xと複数のJDK URL接続
HTTPClient
を速くするにはどうすればよいですか?HTTPClient
がhttp://localhost:9000/user/123
とhttp://localhost:9000/user/456
に同じHTTP接続を使用していますか?
私はいくつかの観察と結論を作ったおかげ
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class FooTest {
public static void main(String[] args) throws Exception {
runWithConnectionPool();
}
private static String extract(BufferedReader reader) throws Exception {
StringBuilder buffer = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
}
private static void runWithConnectionPool() throws Exception {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(1);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.setMaxConnTotal(100)
.setMaxConnPerRoute(100)
.build();
long start = System.currentTimeMillis();
HttpGet getReq = new HttpGet("http://www.google.com");
/*
Option A: Using HTTP connection pool
Option B: Individual JDK 8 URL connection
*/
// Thread[] workers = generateAndStart(10, httpClient, getReq, 0); // (A)
Thread[] workers = generateAndStart(10, getReq.getURI().toURL(), 0); // (B)
for (int i = 0; i < workers.length; i++) {
workers[i].join();
}
System.out.println("Elasped: " + (System.currentTimeMillis() - start));
}
private static Thread[] generateAndStart(int num, URL url, long delay) {
Thread[] workers = new Thread[num];
for (int i = 0; i < num; i++) {
System.out.println("Starting worker: " + i);
int j = i;
workers[i] = new Thread(() -> connect(url, delay, j));
workers[i].start();
}
return workers;
}
private static void connect(URL url, long delay, int ndx) {
try {
System.out.println(url.toURI().toString() + " started.");
} catch (Exception e) {
e.printStackTrace();
}
try {
URLConnection connection = url.openConnection();
connection.addRequestProperty("Accept", "application/json");
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
ObjectMapper mapper = new ObjectMapper();
System.out.println(line);
}
if (delay > 0) {
System.out.println("Delayed.");
sleep(delay);
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static Thread[] generateAndStart(int num, CloseableHttpClient httpClient, HttpGet getReq, long delay) {
Thread[] workers = new Thread[num];
for (int i = 0; i < num; i++) {
System.out.println("Starting worker: " + i);
final int j = i;
workers[i] = new Thread(() -> connect(httpClient, getReq, delay, j));
workers[i].start();
}
return workers;
}
private static void connect(CloseableHttpClient httpClient, HttpGet request, long delay, int ndx) {
System.out.println(request.getURI().toString() + " started.");
try(
CloseableHttpResponse response = httpClient.execute(request, HttpClientContext.create());
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
String line;
while ((line = reader.readLine()) != null) {
ObjectMapper mapper = new ObjectMapper();
System.out.println(line);
}
if (delay > 0) {
System.out.println("Delayed.");
sleep(delay);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (Exception e) {
e.printStackTrace();
}
}
}
アップデート1(2017年3月28日)
、
- を
URLConnection.getInputStream()
が呼び出されるまで、JDKjava.net.URLConnection
は、接続を行うことはありません。 java.net.URLConnection
不適切な接続が発生した場合は現在のソケットを閉じます。 HTTPエラーを返し、新しいソケットを作成します。サーバに複数のソケットを作成するマルチスレッド環境で同じjava.net.URL
インスタンスから作成されたjava.net.URLConnection
のインスタンスを使用して- 。代わりに、簡略化のためにブロックの
URL.openConnection()
を呼び出してください。同じノートでは、私は間違っていた。作成されるソケットの数は、URL.openConnection()
へのすべての呼び出しが新しいソケットを作成することを意味するものではありません。私はURL
がこれを規制していると信じています。URL.openConnection()
を呼び出すスレッドの数に従います。 - URLConnectionを閉じたり切断したりしてもソケットを閉じることはありません。
- 同じサーバーの別のパスに接続しても、別の接続ソケットは作成されません。言い換えると、永続的な接続は異なるパスで使用可能です。
- 一般にApache HTTPClientは使いやすく、より直感的です。ユーザーの介入なしに、マルチスレッド環境で永続的な接続(接続に同じソケットを使用)をサポートします。
- 私は
http.maxConnections
とhttp.keepAlive
に準拠しURL
を取得できませんでした。たとえば、実行時に-Dhttp.keepAlive=false
を含めると、HTTPヘッダーに含まれているConnection: keep-alive
が防止されません。
私が貼り付けた例からの観察は、hereです。これらは、上に貼り付けられたコードよりも優れた例です。
最大100個の接続を管理するようにプールを定義したため、プールが既に「テスト」のためにプールを利用しているかどうかはわかりませんが、プールによって各作業者に新しい接続が作成される可能性があります。このプールは、限られた数の接続(多くの場合、5つの同時アクセスに制限されるDB接続)を共有する必要がある場合、1つのHTTP 1.1に対して同じドメイン(同じ発信元ポリシー)へのHTTP接続の場合は8 Webアプリケーション) –
接続ツールのネットトップから、10個ではなく1個の接続しか使用していないことがわかりました – thlim
'java.net.HttpURLConnection'も接続プーリングを行っていますか?これには意味がないかもしれません。 – EJP