软件测试中的C, Erlang, Java, Go 语言的Web Server 性能测试

发表于:2010-07-23来源:作者:点击数: 标签:软件测试性能测试javaJavaJAVA
软件测试中的C, Erlang, Java, Go 语言的Web Server 性能测试 对C, Erlang, Java and the Go 编程语言的Hello world web服务进行了测试 . * C, 使用高性能的web server-nginx,以及一个 hello world 的nginx模块 * Erlang/OTP * Java, 使用 MI NA 2.0框架. *

软件测试中的C, Erlang, Java, Go 语言的Web Server 性能测试

对C, Erlang, Java and the Go 编程语言的Hello world web服务进行了测试 .


* C, 使用高性能的web server-nginx,以及一个 hello world 的nginx模块
* Erlang/OTP
* Java, 使用MINA 2.0框架.
* Go, http://golang.org/

1. 测试环境

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 aclearcase/" target="_blank" >ccess)

1.2 软件版本

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
Go, hg clone -r release https://go.googlecode.com/hg/ $GOROOT (Nov 12, 2009)

1.3 源代码及配置

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 http://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);
        }
    }
}

$ taskset -c 1-7 \
java -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.

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/
ab -c 1000 -n 1000000 http://192.168.10.1:8080/
ab -c 5000 -n 1000000 http://192.168.10.1:8080/

2. 测试结果

2.1 request per second

30 (threads) 100 1000 5000
Nginx html(1C) 21,301 21,331 17,803 11,901
Nginx module(1C) 25,809 25,735 17,562 12,412
Nginx module(Multi-core) 25,057 24,507 18,110 11,681
Erlang(1C) 11,585 12,367 12,185 10,200
Erlang(Multi-Core) 15,101 20,255 18,687 11,613
Java, Mina2 30,631 26,846 18,134 11,945
Go 14,080 14,748 13,292 7,754

c_erlang_java_go
2.2 latency, 99% requests within(ms)

30 100 1,000 5,000
Nginx html(1C) 1 4 69 504
Nginx module(1C) 1 4 73 502
Nginx module(Multi-core) 1 6 70 501
Erlang(1C) 3 8 3,023 1,874
Erlang(Multi-Core) 2 7 73 495
Java, Mina2 3 5 67 501
Go 26 33 3,006 9,059

3. Notes

* On large concurrent connections, C, Erlang, Java no big difference on their performance, all are about 18k/s (1,000 threads) .
* Java runs better on small connections, but the code in this test doesn’t parse the HTTP request header.
* 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)

原文转自:http://www.ltesting.net