On Thu, Apr 02, 2009 at 10:55:32AM +0200, Oleg Kalnichevski wrote:
> On Thu, Apr 02, 2009 at 10:42:38AM +0200, Gruntz,Dominik wrote:
> > Thanks for your help!
> > I tried to simplify my question and therefore omitted some details.
> > Actually, the resource I am accessing has a body of length 0. It is
> > generated by a Servlet.service method which does not return any data and
> > simply sets the content length to zero.
> >
> > protected void service(HttpServletRequest req, HttpServletResponse res)
> > {
> > System.out.println("request from
> > "+req.getRemoteHost()+":"+req.getRemotePort());
> > res.setContentLength(0);
> > }
> >
> > Obviously, I measured the timings without the println statement. But with
> > that statement enabled I see, that both HttpClient and HttpURLConnection
> > reuse the same socket for their requests, thus they both have to read the
> > whole content (although in my case this content has size 0) and they both
> > reuse the connection (the method name connect on HttpURLConnection is
> > misleading).
> >
> > So still the question: why these timing differences?
> >
>
> HttpClient (at least version 4.0) is known to be faster or as fast as
> HttpURLConnection. Development of HttpClient 3.x effectively ceased
> several years ago.
>
> Look for flaws in your benchmark, like accidentally leaving logging on.
>
> Oleg
>
>
ran a few benchmarks of my own using test code I can trust
HttpCore, the low level toolkit HttpClient 4.0 is based on, is about 20% faster
than HttpURLConnection. HttpClient 4.0 is about 3% slower. Test code attached.
Oleg
==== Test code ====
--- TestHttpJRE ---
public class TestHttpJRE {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Usage: <target URI> <no of requests>");
System.exit(-1);
}
URI targetURI = new URI(args[0]);
int n = Integer.parseInt(args[1]);
URL url = targetURI.toURL();
byte[] buffer = new byte[4096];
long startTime;
long finishTime;
int successCount = 0;
int failureCount = 0;
String serverName = "unknown";
long total = 0;
long contentLen = 0;
long totalContentLen = 0;
startTime = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.connect();
InputStream instream = c.getInputStream();
try {
contentLen = 0;
if (instream != null) {
int l = 0;
while ((l = instream.read(buffer)) != -1) {
total += l;
contentLen += l;
}
}
if (c.getResponseCode() == 200) {
successCount++;
} else {
failureCount++;
}
totalContentLen += contentLen;
} catch (IOException ex) {
failureCount++;
}
String s = c.getHeaderField("Server");
if (s != null) {
serverName = s;
}
}
finishTime = System.currentTimeMillis();
float totalTimeSec = (float) (finishTime - startTime) / 1000;
float reqsPerSec = (float) successCount / totalTimeSec;
float timePerReqMs = (float) (finishTime - startTime) / (float)
successCount;
System.out.print("Server Software:\t");
System.out.println(serverName);
System.out.println();
System.out.print("Document URI:\t\t");
System.out.println(targetURI);
System.out.print("Document Length:\t");
System.out.print(contentLen);
System.out.println(" bytes");
System.out.println();
System.out.print("Time taken for tests:\t");
System.out.print(totalTimeSec);
System.out.println(" seconds");
System.out.print("Complete requests:\t");
System.out.println(successCount);
System.out.print("Failed requests:\t");
System.out.println(failureCount);
System.out.print("Content transferred:\t");
System.out.print(total);
System.out.println(" bytes");
System.out.print("Requests per second:\t");
System.out.print(reqsPerSec);
System.out.println(" [#/sec] (mean)");
System.out.print("Time per request:\t");
System.out.print(timePerReqMs);
System.out.println(" [ms] (mean)");
}
}
--------------------
--- TestHttpCore ---
public class TestHttpCore {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Usage: <target URI> <no of requests>");
System.exit(-1);
}
URI targetURI = new URI(args[0]);
int n = Integer.parseInt(args[1]);
HttpHost targetHost = new HttpHost(
targetURI.getHost(),
targetURI.getPort());
BasicHttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.PROTOCOL_VERSION,
HttpVersion.HTTP_1_1);
params.setBooleanParameter(HttpProtocolParams.USE_EXPECT_CONTINUE,
false);
params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK,
false);
params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE,
2 * 1024);
BasicHttpRequest httpget = new BasicHttpRequest("GET",
targetURI.getPath());
byte[] buffer = new byte[4096];
long startTime;
long finishTime;
int successCount = 0;
int failureCount = 0;
String serverName = "unknown";
long total = 0;
long contentLen = 0;
long totalContentLen = 0;
HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
BasicHttpProcessor httpproc = new BasicHttpProcessor();
// Required protocol interceptors
httpproc.addInterceptor(new RequestContent());
httpproc.addInterceptor(new RequestTargetHost());
// Recommended protocol interceptors
httpproc.addInterceptor(new RequestConnControl());
httpproc.addInterceptor(new RequestUserAgent());
httpproc.addInterceptor(new RequestExpectContinue());
HttpContext context = new BasicHttpContext();
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
DefaultConnectionReuseStrategy connStrategy = new
DefaultConnectionReuseStrategy();
startTime = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
if (!conn.isOpen()) {
Socket socket = new Socket(
targetHost.getHostName(),
targetHost.getPort() > 0 ? targetHost.getPort() : 80);
conn.bind(socket, params);
}
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost);
httpexecutor.preProcess(httpget, httpproc, context);
HttpResponse response = httpexecutor.execute(httpget, conn,
context);
httpexecutor.postProcess(response, httpproc, context);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
try {
contentLen = 0;
if (instream != null) {
int l = 0;
while ((l = instream.read(buffer)) != -1) {
total += l;
contentLen += l;
}
}
successCount++;
totalContentLen += contentLen;
} catch (IOException ex) {
conn.shutdown();
failureCount++;
} finally {
instream.close();
}
}
if (!connStrategy.keepAlive(response, context)) {
conn.close();
}
Header header = response.getFirstHeader("Server");
if (header != null) {
serverName = header.getValue();
}
}
finishTime = System.currentTimeMillis();
float totalTimeSec = (float) (finishTime - startTime) / 1000;
float reqsPerSec = (float) successCount / totalTimeSec;
float timePerReqMs = (float) (finishTime - startTime) / (float)
successCount;
System.out.print("Server Software:\t");
System.out.println(serverName);
System.out.println();
System.out.print("Document URI:\t\t");
System.out.println(targetURI);
System.out.print("Document Length:\t");
System.out.print(contentLen);
System.out.println(" bytes");
System.out.println();
System.out.print("Time taken for tests:\t");
System.out.print(totalTimeSec);
System.out.println(" seconds");
System.out.print("Complete requests:\t");
System.out.println(successCount);
System.out.print("Failed requests:\t");
System.out.println(failureCount);
System.out.print("Content transferred:\t");
System.out.print(total);
System.out.println(" bytes");
System.out.print("Requests per second:\t");
System.out.print(reqsPerSec);
System.out.println(" [#/sec] (mean)");
System.out.print("Time per request:\t");
System.out.print(timePerReqMs);
System.out.println(" [ms] (mean)");
}
}
--------------------
--- TestHttpClient ---
public class TestHttpClient {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Usage: <target URI> <no of requests>");
System.exit(-1);
}
String targetURI = args[0];
int n = Integer.parseInt(args[1]);
BasicHttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.PROTOCOL_VERSION,
HttpVersion.HTTP_1_1);
params.setBooleanParameter(HttpProtocolParams.USE_EXPECT_CONTINUE,
false);
params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK,
false);
params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE,
2 * 1024);
DefaultHttpClient httpclient = new DefaultHttpClient(params);
HttpGet httpget = new HttpGet(targetURI);
byte[] buffer = new byte[4096];
long startTime;
long finishTime;
int successCount = 0;
int failureCount = 0;
String serverName = "unknown";
long total = 0;
long contentLen = 0;
long totalContentLen = 0;
startTime = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
try {
contentLen = 0;
if (instream != null) {
int l = 0;
while ((l = instream.read(buffer)) != -1) {
total += l;
contentLen += l;
}
}
successCount++;
totalContentLen += contentLen;
} catch (IOException ex) {
httpget.abort();
failureCount++;
} finally {
instream.close();
}
}
Header header = response.getFirstHeader("Server");
if (header != null) {
serverName = header.getValue();
}
}
finishTime = System.currentTimeMillis();
float totalTimeSec = (float) (finishTime - startTime) / 1000;
float reqsPerSec = (float) successCount / totalTimeSec;
float timePerReqMs = (float) (finishTime - startTime) / (float)
successCount;
System.out.print("Server Software:\t");
System.out.println(serverName);
System.out.println();
System.out.print("Document URI:\t\t");
System.out.println(targetURI);
System.out.print("Document Length:\t");
System.out.print(contentLen);
System.out.println(" bytes");
System.out.println();
System.out.print("Time taken for tests:\t");
System.out.print(totalTimeSec);
System.out.println(" seconds");
System.out.print("Complete requests:\t");
System.out.println(successCount);
System.out.print("Failed requests:\t");
System.out.println(failureCount);
System.out.print("Content transferred:\t");
System.out.print(total);
System.out.println(" bytes");
System.out.print("Requests per second:\t");
System.out.print(reqsPerSec);
System.out.println(" [#/sec] (mean)");
System.out.print("Time per request:\t");
System.out.print(timePerReqMs);
System.out.println(" [ms] (mean)");
}
}
--------------------
==== Test results ====
--- TestHttpJRE ---
Server Software: Apache-Coyote/1.1
Document URI:
http://localhost:8080/servlets-examples/servlet/RequestInfoExample
Document Length: 689 bytes
Time taken for tests: 9.047 seconds
Complete requests: 20000
Failed requests: 0
Content transferred: 13780000 bytes
Requests per second: 2210.6775 [#/sec] (mean)
Time per request: 0.45235 [ms] (mean)
--------------------
--- TestHttpCore ---
Server Software: Apache-Coyote/1.1
Document URI:
http://localhost:8080/servlets-examples/servlet/RequestInfoExample
Document Length: 689 bytes
Time taken for tests: 7.031 seconds
Complete requests: 20000
Failed requests: 0
Content transferred: 13780000 bytes
Requests per second: 2844.5454 [#/sec] (mean)
Time per request: 0.35155 [ms] (mean)
--------------------
--- TestHttpClient ---
Server Software: Apache-Coyote/1.1
Document URI:
http://localhost:8080/servlets-examples/servlet/RequestInfoExample
Document Length: 689 bytes
Time taken for tests: 9.282 seconds
Complete requests: 20000
Failed requests: 0
Content transferred: 13780000 bytes
Requests per second: 2154.7083 [#/sec] (mean)
Time per request: 0.4641 [ms] (mean)
--------------------
>
> > Thanks for any further advice.
> >
> > Best wishes
> > Dominik
> >
> >
> > -----Original Message-----
> > From: Oleg Kalnichevski [mailto:[email protected]]
> > Sent: Donnerstag, 2. April 2009 09:50
> > To: HttpClient User Discussion
> > Subject: Re: HttpClient performance
> >
> > On Thu, Apr 02, 2009 at 01:54:56AM +0200, Gruntz,Dominik wrote:
> > > Hi,
> > > I wrote a method which requests a resource several times from on a
> > > servlet server (on localhost).
> > > It seems to me that the version using HttpClient is abouot a factor of
> > > 20-30 slower than the
> > > version based on Sun's HttpURLConnection. I cannot believe these figures
> > > and ask you, where
> > > I misused the HttpClient class. If the result is correct, what is the
> > > reasen that HttpClient
> > > is slower?
> > >
> > > The HttpClient method looks as follows:
> > >
> > > static void doJakartaCommons(String path) throws Exception {
> > > HttpClient client = new HttpClient();
> > > for (int i = 0; i < 1000; i++) {
> > > HttpMethod method = new GetMethod(path);
> > > client.executeMethod(method);
> > > int code = method.getStatusCode();
> > > if(code != 200)
> > > throw new IllegalStateException();
> > > method.releaseConnection();
> > > }
> > > }
> > >
> > >
> > > The version bsaed on HttpURLConnection looks as follows:
> > >
> > > static void doHttpConnection(String path) throws Exception {
> > > for (int i = 0; i < 1000; i++) {
> > > URL url = new URL(path);
> > > HttpURLConnection c = (HttpURLConnection)
> > > url.openConnection();
> > > c.connect();
> > > int code = c.getResponseCode();
> > > if(code != 200)
> > > throw new IllegalStateException();
> > > }
> > > }
> > >
> > >
> > > Thanks for your help.
> > > Dominik
> > >
> > >
> >
> > Your performance benchmark is completely flawed. You are comparing
> > apples to oranges. Here's what HttpURLConnection test does: open a
> > connection, execute request, read response head, drop connection. Here's
> > what your HttpClient test case does: open a connection, execute request,
> > read response head, read response body (!!!!), re-use connection.
> > Obviously opening a new local connection is significantly faster than
> > reading a larger response body
> >
> > Performance benchmarking is a tricky business.
> >
> > Oleg
> >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [email protected]
> > For additional commands, e-mail: [email protected]
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]