最近闲来无事,对tomcat、netty以及nodejs的性能对比比较有兴趣,于是自行测试了一下。
测试环境:
测试工具:Apache JMeter2.9
测试代码:
-
tomcat下的jsp:
1<%@page language="java" contentType="text/html; charset=GBK" %> 2<%@page import = "java.util.Date" %> 3 4<html> 5<body> 6 hello world! 7 <%= new Date() %> 8</body> 9</html> -
netty下的server:
1package com.hannah.netty; 2import java.net.InetSocketAddress; 3import java.util.concurrent.Executors; 4 5import org.jboss.netty.bootstrap.ServerBootstrap; 6import org.jboss.netty.channel.ChannelPipeline; 7import org.jboss.netty.channel.ChannelPipelineFactory; 8import org.jboss.netty.channel.Channels; 9import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; 10import org.jboss.netty.handler.codec.http.HttpRequestDecoder; 11import org.jboss.netty.handler.codec.http.HttpResponseEncoder; 12 13public class AdminServer { 14 public static void main(String[] args) { 15 start(8080); 16 } 17 18 public static void start(int port) { 19 // 配置服务器-使用java线程池作为解释线程 20 ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( 21 Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); 22 // 设置 pipeline factory. 23 bootstrap.setPipelineFactory(new ServerPipelineFactory()); 24 // 绑定端口 25 bootstrap.bind(new InetSocketAddress(port)); 26 System.out.println("admin start on " + port); 27 } 28 29 private static class ServerPipelineFactory implements ChannelPipelineFactory { 30 public ChannelPipeline getPipeline() throws Exception { 31 // Create a default pipeline implementation. 32 ChannelPipeline pipeline = Channels.pipeline(); 33 pipeline.addLast("decoder", new HttpRequestDecoder()); 34 pipeline.addLast("encoder", new HttpResponseEncoder()); 35 // http处理handler 36 pipeline.addLast("handler", new AdminServerHandler()); 37 return pipeline; 38 } 39 } 40} 41 42package com.hannah.thirdparty.netty; 43 44import java.util.Date; 45 46import org.jboss.netty.buffer.ChannelBuffer; 47import org.jboss.netty.buffer.ChannelBuffers; 48import org.jboss.netty.buffer.DynamicChannelBuffer; 49import org.jboss.netty.channel.Channel; 50import org.jboss.netty.channel.ChannelFutureListener; 51import org.jboss.netty.channel.ChannelHandlerContext; 52import org.jboss.netty.channel.ExceptionEvent; 53import org.jboss.netty.channel.MessageEvent; 54import org.jboss.netty.channel.SimpleChannelUpstreamHandler; 55import org.jboss.netty.handler.codec.frame.TooLongFrameException; 56import org.jboss.netty.handler.codec.http.DefaultHttpResponse; 57import org.jboss.netty.handler.codec.http.HttpHeaders.Names; 58import org.jboss.netty.handler.codec.http.HttpRequest; 59import org.jboss.netty.handler.codec.http.HttpResponse; 60import org.jboss.netty.handler.codec.http.HttpResponseStatus; 61import org.jboss.netty.handler.codec.http.HttpVersion; 62import org.jboss.netty.util.CharsetUtil; 63 64public class AdminServerHandler extends SimpleChannelUpstreamHandler { 65 66 @Override 67 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { 68// HttpRequest request = (HttpRequest) e.getMessage(); 69// String uri = request.getUri(); 70// System.out.println("uri:" + uri); 71 HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); 72 ChannelBuffer buffer = new DynamicChannelBuffer(2048); 73 buffer.writeBytes(("Hello World!\t" + new Date()).getBytes("UTF-8")); 74 response.setContent(buffer); 75 response.setHeader("Content-Type", "text/html; charset=UTF-8"); 76 response.setHeader("Content-Length", response.getContent().writerIndex()); 77 Channel ch = e.getChannel(); 78 // Write the initial line and the header. 79 ch.write(response); 80 ch.disconnect(); 81 ch.close(); 82 } 83 84 @Override 85 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { 86 Channel ch = e.getChannel(); 87 Throwable cause = e.getCause(); 88 if (cause instanceof TooLongFrameException) { 89 sendError(ctx, HttpResponseStatus.BAD_REQUEST); 90 return; 91 } 92 cause.printStackTrace(); 93 if (ch.isConnected()) { 94 sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR); 95 } 96 } 97 98 private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { 99 HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status); 100 response.setHeader(Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); 101 response.setContent(ChannelBuffers.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8)); 102 103 // Close the connection as soon as the error message is sent. 104 ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE); 105 } 106} -
nodejs下的example.js:
1// var url = require('url'); 2var http = require('http'); 3http.createServer(function (req, res) { 4 // var pathname = url.parse(req.url).pathname; 5 res.writeHead(200, {'Content-Type': 'text/plain'}); 6 res.end('Hello World!\t' + new Date()); 7}).listen(1337, '127.0.0.1'); 8console.log('Server running at http://127.0.0.1:1337/');
测试结果:
- 线程数:100;循环次数:100;

- 线程数:1000;循环次数:10;

- 线程数:1000;循环次数:100;

结果分析:整体上来看,并发小的时候,区别不大;当并发逐渐加大时,tomcat首先承受不住,nodejs和netty性能大致相当(netty性能略低点);最后一次请求的时候,tomcat报OutOfMemory的错误了!