I had tested a hello world web server in C, Erlang, Java and the Go programming language.
* C, use the well-known high performance web server nginx, with a hello world nginx module
* Erlang/OTP
* Java, using the MINA 2.0 framework, now the JBoss Netty framework.
* Go, http://golang.org/
1. Test environment
1.1 Hardware/OS
2 Linux boxes in a gigabit ethernet LAN, 1 server and 1 test client
Linux Centos 5.2 64bit
Intel(R) Xeon(R) CPU E5410 @ 2.33GHz (L2 cache: 6M), Quad-Core * 2
8G memory
SCSI disk (standalone disk, no other access)
1.2 Software version
nginx, nginx-0.7.63.tar.gz
Erlang, otp_src_R13B02-1.tar.gz
Java, jdk-6u17-linux-x64.bin, mina-2.0.0-RC1.tar.gz, netty-3.2.0.ALPHA1-dist.tar.bz2
Go, hg clone -r release https://go.googlecode.com/hg/ $GOROOT (Nov 12, 2009)
1.3 Source code and configuration
Linux, run sysctl -p
net.ipv4.ip_forward = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.default.accept_source_route = 0 kernel.sysrq = 0 kernel.core_uses_pid = 1 net.ipv4.tcp_syncookies = 1 kernel.msgmnb = 65536 kernel.msgmax = 65536 kernel.shmmax = 68719476736 kernel.shmall = 4294967296 kernel.panic = 1 net.ipv4.tcp_rmem = 8192 873800 8738000 net.ipv4.tcp_wmem = 4096 655360 6553600 net.ipv4.ip_local_port_range = 1024 65000 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216
# ulimit -n
150000
C: ngnix hello world module, copy the code ngx_http_hello_module.c from https://timyang.net/web/nginx-module/
in nginx.conf, set “worker_processes 1; worker_connections 10240” for 1 cpu test, set “worker_processes 4; worker_connections 2048” for multi-core cpu test. Turn off all access or debug log in nginx.conf, as follows
worker_processes 1; worker_rlimit_nofile 10240; events { worker_connections 10240; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 0; server { listen 8080; server_name localhost; location / { root html; index index.html index.htm; } location /hello { ngx_hello_module; hello 1234; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
$ taskset -c 1 ./nginx or $ taskset -c 1-7 ./nginx
Erlang hello world server
The source code is available at yufeng’s blog, see http://blog.yufeng.info/archives/105
Just copy the code after “cat ehttpd.erl”, and compile it.
$ erlc ehttpd.erl
$ taskset -c 1 erl +K true +h 99999 +P 99999 -smp enable +S 2:1 -s ehttpd
$ taskset -c 1-7 erl +K true -s ehttpd
We use taskset to limit erlang vm to use only 1 CPU/core or use all CPU cores. The 2nd line is run in single CPU mode, and the 3rd line is run in multi-core CPU mode.
Java source code, save the 2 class as HttpServer.java and HttpProtocolHandler.java, and do necessary import.
public class HttpServer { public static void main(String[] args) throws Exception { SocketAcceptor acceptor = new NioSocketAcceptor(4); acceptor.setReuseAddress( true ); int port = 8080; String hostname = null; if (args.length > 1) { hostname = args[0]; port = Integer.parseInt(args[1]); } // Bind acceptor.setHandler(new HttpProtocolHandler()); if (hostname != null) acceptor.bind(new InetSocketAddress(hostname, port)); else acceptor.bind(new InetSocketAddress(port)); System.out.println("Listening on port " + port); Thread.currentThread().join(); } } public class HttpProtocolHandler extends IoHandlerAdapter { public void sessionCreated(IoSession session) { session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); session.setAttribute(SslFilter.USE_NOTIFICATION); } public void sessionClosed(IoSession session) throws Exception {} public void sessionOpened(IoSession session) throws Exception {} public void sessionIdle(IoSession session, IdleStatus status) {} public void exceptionCaught(IoSession session, Throwable cause) { session.close(true); } static IoBuffer RESULT = null; public static String HTTP_200 = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\n" + "hello world\r\n"; static { RESULT = IoBuffer.allocate(32).setAutoExpand(true); RESULT.put(HTTP_200.getBytes()); RESULT.flip(); } public void messageReceived(IoSession session, Object message) throws Exception { if (message instanceof IoBuffer) { IoBuffer buf = (IoBuffer) message; int c = buf.get(); if (c == 'G' || c == 'g') { session.write(RESULT.duplicate()); } session.close(false); } } }
Nov 24 update Because the above Mina code doesn’t parse HTTP request and handle the necessary HTTP protocol, replaced with org.jboss.netty.example.http.snoop.HttpServer from Netty example, but removed all the string builder code from HttpRequestHandler.messageReceived() and just return a “hello world” result in HttpRequestHandler.writeResponse(). Please read the source code and the Netty documentation for more information.
$ taskset -c 1-7 \
java -server -Xmx1024m -Xms1024m -XX:+UseConcMarkSweepGC -classpath . test.HttpServer 192.168.10.1 8080
We use taskset to limit java only use cpu1-7, and not use cpu0, because we want cpu0 dedicate for system call(Linux use CPU0 for network interruptions).
Go language, source code
package main import ( "http"; "io"; ) func HelloServer(c *http.Conn, req *http.Request) { io.WriteString(c, "hello, world!\n"); } func main() { runtime.GOMAXPROCS(8); // 8 cores http.Handle("/", http.HandlerFunc(HelloServer)); err := http.ListenAndServe(":8080", nil); if err != nil { panic("ListenAndServe: ", err.String()) } }
$ 6g httpd2.go
$ 6l httpd2.6
$ taskset -c 1-7 ./6.out
1.4 Performance test client
ApacheBench client, for 30, 100, 1,000, 5,000 concurrent threads
ab -c 30 -n 1000000 http://192.168.10.1:8080/
ab -c 100 -n 1000000 http://192.168.10.1:8080/
1000 thread, 334 from 3 different machine
ab -c 334 -n 334000 http://192.168.10.1:8080/
5000 thread, 1667 from 3 different machine
ab -c 1667 -n 334000 http://192.168.10.1:8080/
2. Test results
2.1 request per second
30 (threads) | 100 | 1,000 | 5,000 | |
Nginx html(1C) | 21,301 | 21,331 | 23,746 | 23,502 |
Nginx module(1C) | 25,809 | 25,735 | 30,380 | 29,667 |
Nginx module(Multi-core) | 25,057 | 24,507 | 31,544 | 33,274 |
Erlang(1C) | 11,585 | 12,367 | 12,852 | 12,815 |
Erlang(Multi-Core) | 15,101 | 20,255 | 26,468 | 25,865 |
Java, Mina2(without HTTP parse) |
30,631 | 26,846 | 31,911 | 31,653 |
Java, Netty | 24,152 | 24,423 | 25,487 | 25,521 |
Go | 14,080 | 14,748 | 15,799 | 16,110 |

2.2 latency, 99% requests within(ms)
30 | 100 | 1,000 | 5,000 | |
Nginx html(1C) | 1 | 4 | 42 | 3,079 |
Nginx module(1C) | 1 | 4 | 32 | 3,047 |
Nginx module(Multi-core) | 1 | 6 | 205 | 3,036 |
Erlang(1C) | 3 | 8 | 629 | 6,337 |
Erlang(Multi-Core) | 2 | 7 | 223 | 3,084 |
Java, Netty | 1 | 3 | 3 | 3,084 |
Go | 26 | 33 | 47 | 9,005 |
3. Notes
* On large concurrent connections, C, Erlang, Java no big difference on their performance, results are very close.
* Java runs better on small connections, but the code in this test doesn’t parse the HTTP request header (the MINA code).
* Although Mr. Yu Feng (the Erlang guru in China) mentioned that Erlang performance better on single CPU(prevent context switch), but the result tells that Erlang has big latency(> 1S) under 1,000 or 5,000 connections.
* Go language is very close to Erlang, but still not good under heavy load (5,000 threads)
After redo 1,000 and 5,000 tests on Nov 18
* Nginx module is the winner on 5,000 concurrent requests.
* Although there is improvement space for Go, Go has the same performance from 30-5,000 threads.
* Erlang process is impressive on large concurrent request, still as good as nginx (5,000 threads).
4. Update Log
Nov 12, change nginx.conf work_connections from 1024 to 10240
Nov 13, add runtime.GOMAXPROCS(8); to go’s code, add sysctl -p env
Nov 18, realized that ApacheBench itself is a bottleneck under 1,000 or 5,000 threads, so use 3 clients from 3 different machines to redo all tests of 1,000 and 5,000 concurrent tests.
Nov 24, use Netty with full HTTP implementation to replace Mina 2 for the Java web server. Still very fast and low latency after added HTTP handle code.
The Go program cannot be compiled.
‘runtime’ should be imported.
‘panic’ only takes one argument now.
Moreover, now ‘;’s are not necessary.
You used taskset -c 1-7, but in the code
runtime.GOMAXPROCS(8); // 8 cores
The Go program cannot be compiled.
‘runtime’ should be imported.
‘panic’ only takes one argument now.
Moreover, the ‘;’s at the end of each statement are not necessary now.
You used taskset -c 1-7, but in the code
“runtime.GOMAXPROCS(8); // 8 cores”
How about chang ‘8’ to ‘7’ too?
hi timyang, very good article.
Could tell me which tools do You use to get the results and graphics?
Thank you very much
Victor
to vcitor:
excel
Great test. Interesting how well Java stands in these tests. At the level of C performance with much higher level features.
What would really really make the picture perfect is adding the node.js hello world. (It’s on the front page of http://nodejs.org/). People talk very highly about it’s performance, but I don’t know how it would stack-up to these top speed platforms.
It probably can’t be faster than compiled Go, and even go is relatively “bad” in this company.
博主牛啊,上Hacker News和reddit了。
+1 for adding node.js to the list here.
Too bad you did not include G-WAN in your test:
http://gwan.ch/
Not only G-WAN’s C scripts are much easier to write than the ‘modules’ of other servers, but they execute much faster.
Here is the (10-line) source code of an hello world sample:
http://gwan.ch/en_developers.html
And many other samples (SQL, etc.) are there:
http://gwan.ch/source/
Would like to see node.js included!
I saw a test of node.js vs Erlang somewhere else, and in that test node.js had memory leak issues. For me there’s no question, Erlang is better and more reliable then node.js for high load services.
Excellent work.
Go-lang must stay on improvement way.
Tim: I’d love to see run-time memory usage added to the results of the test.
homi nauter:
I tested node.js here: http://simonhf.wordpress.com/2010/10/23/node-js-versus-lua-hello-world-postmortem/
And nginx here: http://simonhf.wordpress.com/2010/10/02/nginx-versus-sxe-hello-world/
[…] Here is a excellent tutorial show you about C, Erlang, Java and Go Web Server performance test: I had tested a hello world web server in C, Erlang, Java and the Go programming language. * C, use the well-known high performance web server nginx, with a hello world nginx module * Erlang/OTP * Java, using the MINA 2.0 framework, now the JBoss Netty framework. * Go, http://golang.org/ […]
Node.js = cancer. If you use that piece of crap for any sizable project you have much bigger problems than performance.
unfair test .
Web Containers are few .
[…] 2009-11-11 《C, Erlang, Java 和 Go Web Server 性能测试》 Tim 原文 […]
C, Erlang, Java and Go Web Server performance test – Tim[åŽç«¯æŠ€æœ¯] I was recommended this blog by my cousin. I’m not sure whether this post is written by him as no one else know such detailed about my difficulty. You are incredible! Thanks! your article about C, Erlang, Java and Go Web Server performance test – Tim[åŽç«¯æŠ€æœ¯]Best Regards Shane
[…] 近日看到C, Erlang, Java and Go Web Server performance test一文,决定对SocketAsyncEventArgs做个简单的测试。测试平台为Thinkpad X200(CPU: P8400),Ubuntu 10.10,MONO 2.10,OpenJDK1.6。SocketAsyncEventArgs的代码来源于MSDN上的示例代码并稍作修改,另外使用Netty 3.2.4作为对比,配置及测试方法参考C, Erlang, Java and Go Web Server performance test一文。 […]
Interesting comparison. Can you rerun it now that Go get a new GC?
[…] Erlang, Java 和 Go Web Server 性能测试》 Tim 原文开源项目工具系列2011-12-27 密码生成器 […]
Very interested in seeing updated Go performance!
I use node.js in a project with 15k lines of code. It’s mature (even though it still didn’t reach v1) and definitely fast. I think it’s one of the best things happened to web development.
[…] 《C, Erlang, Java 和 Go Web Server 性能测试》 Tim 原文 分类: Go语言 标签: Go,Go语言资料,Golang 评论 (0) Trackbacks (0) […]
我想golang 你需要重新测试一下了。性能超高!
external blu ray player for mac…
C, Erlang, Java and Go Web Server performance test – Tim[后端技术]…
[…] 网络模型研究,09年做的的C, Erlang, Java and Go Web Server performance test得出了一些实验室的结论,打算继续观察各种网络模型在大并发真实网络慢连接的情况下表现的差异。打算比较Scala, Java, Erlang and Go. 关注点也是throughput, latency以及代码的可扩展性及可维护性。 […]
[…] 网络模型研究,09年做的的C, Erlang, Java and Go Web Server performance test得出了一些实验室的结论,打算继续观察各种网络模型在大并发真实网络慢连接的情况下表现的差异。打算比较Scala, Java, Erlang and Go. 关注点也是throughput, latency以及代码的可扩展性及可维护性。 […]
[…] 2009-11-11 《C, Erlang, Java 和 Go Web Server 性能测试》 Tim 原文 […]
[…] 此后不久看到了新浪微博架构师对netty的一个评测(原文:C, Erlang, Java and Go Web Server performance test),这个评测受到很多人关注,其中就有netty的作者 Trustin Lee。起因是这个评测最初使用mina测试,Trustin Lee看到后建议用netty,并且在测试后发现netty的性能表现果然不俗。现在想来这个测试略有些不公平,原来mina的作者也是这个人!大概顺序上先有了mina2,后来离开apache出了netty3(Jboss),所以在这个测试中netty3自然也胜券在握。 […]
这项性能比较突显了软件设计中的关键权衡。虽然C语言在速度上表现出色,但Erlang的并发处理则展示了其韧性。Java的Netty在低负载下表现良好,但其缺乏请求解析会影响结果。Go在不同负载下的稳定结果引发了关于原始速度与构建可维护系统之间平衡的问题,这些系统能够提升开发者的生产力。在我们优化应用性能的同时,也不要忘记在其他领域确保稳健解决方案的重要性,比如提供安全和质量服务的 Windscreen Medics