Following from my last post on benchmarking hello world http server on various platforms, I continued with increasing the number of requests and concurrency. In addition, I added scalatra, play, and greenlet tornado to the list.
What is greenlet? To make it short, it’s just like goroutine in golang. What’s goroutine? Read about it here.
This time, I excluded node.js, twisted, and eventmachine from the list, because apache bench could not finish the benchmark at 100,000 number of requests with 100 multiple requests at a time.
node.js and eventmachine could still perform well at 15000 requests with 100 multiple requests, and the results of both don’t have a significant difference compared to the last time I tested it. Beyond that, the test was aborted after 10 failures, with the same error:
apr_socket_connect(): Operation already in progress (37)
I have also made an upgrade on ab executable to Version 2.3 Revision 1430300. This could be built from the latest httpd source code at version 2.4.4.
That being said, I may try to find out what are the problems in my test setup — Mac OS X 10.8.4, Retina MacBook Pro, Mid 2012 with Quad Core i7 at 2.3 GHz — that fails apache bench to finish it for node.js, twisted, and eventmachine. I figured that to do a full-scale benchmark with apache bench, it needs to be run on a Linux server.
The apache bench command that I was using:
% ab -r -k -n 100000 -c 100 -e ~/Documents/each_platform_results.csv http://localhost:port/
The source code for greenlet with tornado:
1 | import tornado.httpserver |
As you can see, there’s not much difference except for the @greenlet_asynchronous
decorator.
The result is not that different either:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37Server Software: TornadoServer/3.0.2
Server Hostname: 0.0.0.0
Server Port: 8001
Document Path: /
Document Length: 12 bytes
Concurrency Level: 100
Time taken for tests: 32.202 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 100000
Total transferred: 23100000 bytes
HTML transferred: 1200000 bytes
Requests per second: 3105.36 [#/sec] (mean)
Time per request: 32.202 [ms] (mean)
Time per request: 0.322 [ms] (mean, across all concurrent requests)
Transfer rate: 700.52 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 5
Processing: 6 32 10.7 29 100
Waiting: 6 32 10.7 29 100
Total: 10 32 10.7 29 100
Percentage of the requests served within a certain time (ms)
50% 29
66% 29
75% 30
80% 30
90% 51
95% 61
98% 63
99% 68
100% 100 (longest request)
Actually, tornado without greenlet is slightly faster by 0.01 ms.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37Server Software: TornadoServer/3.0.2
Server Hostname: 0.0.0.0
Server Port: 8001
Document Path: /
Document Length: 12 bytes
Concurrency Level: 100
Time taken for tests: 31.168 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 100000
Total transferred: 23100000 bytes
HTML transferred: 1200000 bytes
Requests per second: 3208.39 [#/sec] (mean)
Time per request: 31.168 [ms] (mean)
Time per request: 0.312 [ms] (mean, across all concurrent requests)
Transfer rate: 723.77 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 4
Processing: 7 31 11.0 27 108
Waiting: 7 31 11.0 27 108
Total: 8 31 11.0 27 108
Percentage of the requests served within a certain time (ms)
50% 27
66% 28
75% 28
80% 29
90% 50
95% 59
98% 63
99% 73
100% 108 (longest request)
Next up, Scalatra which is a sinatra inspired web framework written in scala, but it takes much longer to setup compared to its predecessor.
Here’s the code:
1 | package com.jessearmand.helloscala |
Yes, that simple! Once you set it up with some effort, if you never done any Scala programming.
How does it perform? Roughly, it’s twice as fast as python’s tornado.
1 | Server Software: Jetty(8.1.8.v20121106) |
Now, let’s try Play framework which I guess is the best framework written in Scala to build a web application with non-blocking IO.
1 | package controllers |
Note how I commented out the code responsible for rendering the default index.html view. This is only because I want a pure “Hello World” comparison. Although, I do understand that it’s not a comprehensive way to benchmark web apps for what it can do in various other cases. Read here for a good example of doing this.
Result on initial launch of the app:
1 | Server Software: |
Then, after the first benchmark:
1 | Server Software: |
It seems Play framework takes some time from the initial launch to achieve some kind of a “steady state”.
Last, let’s do some benchmark with go lang again. This time, I didn’t set GOMAXPROCS which sets the maximum number of CPUs that can be executing simultaneously. Thus, I let it use a default value that I don’t know of.
Result:
1 | Server Software: |
Go is definitely still a clear winner with half the speed compared to my last benchmark. Next to Go performance is Play framework.
On a related note, there’s an interesting article for Python developers if you’re thinking about migrating to Go.