Ich versuche, mit einer Java-Implementierung eines einfachen HTTP-Client, der einen Socket offen hält und verwendet es wieder andere (oder gleiche) URLs auf dem gleichen Host abfragen .Java Socket Keep am Leben ist langsam, Wiedereröffnung eines Sockets ist schneller
Ich habe eine einfache Implementierung, die java.net.Socket verwendet, aber irgendwie ist die Leistung, wenn ich den Sockel offen halte, schlimmer als wenn ich einen neuen erzeuge.
Ergebnisse erste, voll ausführbaren Code unten:
Mit Keep-Alive: langsamer beginnend bei Iteration Nr 2
> java -server -Xms100M -Xmx100M -cp . KeepAlive 10 true
--- Warm up ---
18
61
60
60
78
62
59
60
59
60
Total exec time: 626
--- Run ---
26
59
60
61
60
59
60
60
62
58
Total exec time: 576
die Buchse Recreating jedes Mal bessere Ergebnisse gibt:
> java -server -Xms100M -Xmx100M -cp . KeepAlive 10 false
--- Warm up ---
188
34
39
33
33
33
33
33
34
33
Total exec time: 494
--- Run ---
33
35
33
34
44
34
33
34
32
34
Total exec time: 346
Keep-Alive. Java (Standalone, keine Abhängigkeiten)
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
public class KeepAlive {
private static final String NL = "\r\n";
private static final int READ_SIZE = 1000;
private Socket socket;
private DataOutputStream writer;
private BufferedReader reader;
public static void main(String[] args) throws Exception {
if (args.length == 2) {
KeepAlive ka = new KeepAlive();
System.out.println("--- Warm up ---");
ka.query(Integer.parseInt(args[0]), args[1].equals("true"));
System.out.println("--- Run ---");
ka.query(Integer.parseInt(args[0]), args[1].equals("true"));
} else {
System.out.println("Usage: keepAlive <n queries> <reuse socket>");
}
}
private void query(int n, boolean reuseConnection) throws Exception {
long t0 = System.currentTimeMillis();
if (reuseConnection) {
open();
for (int i = 0; i < n; i++) {
long tq0 = System.currentTimeMillis();
query();
System.out.println(System.currentTimeMillis() - tq0);
}
close();
} else {
for (int i = 0; i < n; i++) {
long tq0 = System.currentTimeMillis();
open();
query();
close();
System.out.println(System.currentTimeMillis() - tq0);
}
}
System.out.println("Total exec time: " + (System.currentTimeMillis() - t0));
}
private void open() throws Exception {
socket = new Socket();
socket.setKeepAlive(false);
socket.connect(new InetSocketAddress("example.org", 80));
writer = new DataOutputStream(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
private void query() throws Exception {
StringBuilder req = new StringBuilder();
req.append("GET/HTTP/1.1").append(NL);
req.append("Host: example.org").append(NL);
req.append("Connection: Keep-Alive").append(NL);
req.append(NL);
String reqStr = req.toString();
long t0 = System.currentTimeMillis();
writer.writeBytes(reqStr);
writer.flush();
String line;
int contentLength = 0;
while ((line = reader.readLine()) != null) {
if (line.startsWith("Content-Length: ")) {
contentLength = Integer.parseInt(line.substring(16));
}
if (line.equals("")) {
char[] buf = new char[contentLength];
int offset = 0;
while (offset < contentLength) {
int len = contentLength - offset;
if (len > READ_SIZE) {
len = READ_SIZE;
}
int ret = reader.read(buf, offset, len);
if (ret == -1) {
System.out.println("End of stream. Exiting");
System.exit(1);
}
offset += ret;
}
break;
}
}
}
private void close() throws Exception {
writer.close();
reader.close();
socket.close();
}
}
Jetzt
, ich bin ziemlich sicher, dass entweder:
der Web-Server der neuen Anforderungen im Umgang mit schnellen (HTTP Keep Alive and TCP keep alive)
etwas saugt ist falsch mit der Art, wie ich die gepufferten Leser verwenden, da das ist, wo die ganze Zeit verloren, aber bei den anderen Methoden zur Verfügung sucht (und ich versuche, ein paar), kann ich nicht finden, was ich tun müssen, um dieses Problem beheben ...
Jede Idee, wie ich kann mach das w Ork schneller? Vielleicht eine Config auf das ichduersiees Server ändern? ...
Lösung
Wie unten durch apangin erläutert, wird die langsame perf von Nagle-Algorithmus verursacht, die standardmäßig aktiviert ist. Mit setTcpNoDelay (true), habe ich die aktualisierten folgenden perfs erhalten:
Ohne Keep-Alive:
java -server -Xms100M -Xmx100M -cp . KeepAlive 10 false
--- Warm up ---
49
22
25
23
23
22
23
23
28
28
Total exec time: 267
--- Run ---
31
23
23
24
25
22
23
25
33
23
Total exec time: 252
Mit Keep-Alive: Also hier
java -server -Xms100M -Xmx100M -cp . KeepAlive 10 true
--- Warm up ---
13
12
12
14
11
12
13
12
11
12
Total exec time: 168
--- Run ---
14
12
11
12
11
12
13
11
21
28
Total exec time: 158
wir die Frieds sehen -alive Version, die bei jeder Iteration und auch beim Vergleich der gesamten Ausführungszeiten weitaus besser abschneidet als die nicht-keep-alive-Version. :)
Sie testen nicht wirklich wie hier. In einem hämmerst du den Server so hart wie du kannst. Auf der anderen Seite pausieren Sie zwischen den einzelnen Abfragen. Haben Sie versucht, die Gesamtzeit auf dem Client für jeden Lauf zu testen? – BevynQ
Ja, das ist der Punkt des Tests: zu sehen, welches der beiden unterschiedlichen Verhaltensweisen am besten abschneidet. Die Frage ist: "Wie schnell kann ich eine Anfrage stellen und die Antwort mit oder ohne Keep-Alive bekommen". Ich habe die Gesamtzeit der Ausführung für Sie hinzugefügt. – fabien