tomcat、netty以及nodejs的helloworld性能对比

原创
2013/04/05 16:39
阅读数 3.1W

最近闲来无事,对tomcat、netty以及nodejs的性能对比比较有兴趣,于是自行测试了一下。

测试环境:

测试工具:Apache JMeter2.9

测试代码:

  1. tomcat下的jsp:
    <%@page language="java" contentType="text/html; charset=GBK" %>
    <%@page import = "java.util.Date" %>
    
    <html>
    <body>
      hello world!
      <%= new Date() %>
    </body>
    </html>
  2. netty下的server:
    package com.hannah.netty;
    import java.net.InetSocketAddress;
    import java.util.concurrent.Executors;
    
    import org.jboss.netty.bootstrap.ServerBootstrap;
    import org.jboss.netty.channel.ChannelPipeline;
    import org.jboss.netty.channel.ChannelPipelineFactory;
    import org.jboss.netty.channel.Channels;
    import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
    import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
    import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
    
    public class AdminServer {
    	public static void main(String[] args) {
    		start(8080);
    	}
    
    	public static void start(int port) {
    		// 配置服务器-使用java线程池作为解释线程
    		ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
    				Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
    		// 设置 pipeline factory.
    		bootstrap.setPipelineFactory(new ServerPipelineFactory());
    		// 绑定端口
    		bootstrap.bind(new InetSocketAddress(port));
    		System.out.println("admin start on " + port);
    	}
    
    	private static class ServerPipelineFactory implements ChannelPipelineFactory {
    		public ChannelPipeline getPipeline() throws Exception {
    			// Create a default pipeline implementation.
    			ChannelPipeline pipeline = Channels.pipeline();
    			pipeline.addLast("decoder", new HttpRequestDecoder());
    			pipeline.addLast("encoder", new HttpResponseEncoder());
    			// http处理handler
    			pipeline.addLast("handler", new AdminServerHandler());
    			return pipeline;
    		}
    	}
    }
    package com.hannah.thirdparty.netty;
    
    import java.util.Date;
    
    import org.jboss.netty.buffer.ChannelBuffer;
    import org.jboss.netty.buffer.ChannelBuffers;
    import org.jboss.netty.buffer.DynamicChannelBuffer;
    import org.jboss.netty.channel.Channel;
    import org.jboss.netty.channel.ChannelFutureListener;
    import org.jboss.netty.channel.ChannelHandlerContext;
    import org.jboss.netty.channel.ExceptionEvent;
    import org.jboss.netty.channel.MessageEvent;
    import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
    import org.jboss.netty.handler.codec.frame.TooLongFrameException;
    import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
    import org.jboss.netty.handler.codec.http.HttpHeaders.Names;
    import org.jboss.netty.handler.codec.http.HttpRequest;
    import org.jboss.netty.handler.codec.http.HttpResponse;
    import org.jboss.netty.handler.codec.http.HttpResponseStatus;
    import org.jboss.netty.handler.codec.http.HttpVersion;
    import org.jboss.netty.util.CharsetUtil;
    
    public class AdminServerHandler extends SimpleChannelUpstreamHandler {
    
    	@Override
    	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    //		HttpRequest request = (HttpRequest) e.getMessage();
    //		String uri = request.getUri();
    //		System.out.println("uri:" + uri);
    		HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
    		ChannelBuffer buffer = new DynamicChannelBuffer(2048);
    		buffer.writeBytes(("Hello World!\t" + new Date()).getBytes("UTF-8"));
    		response.setContent(buffer);
    		response.setHeader("Content-Type", "text/html; charset=UTF-8");
    		response.setHeader("Content-Length", response.getContent().writerIndex());
    		Channel ch = e.getChannel();
    		// Write the initial line and the header.
    		ch.write(response);
    		ch.disconnect();
    		ch.close();
    	}
    
    	@Override
    	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
    		Channel ch = e.getChannel();
    		Throwable cause = e.getCause();
    		if (cause instanceof TooLongFrameException) {
    			sendError(ctx, HttpResponseStatus.BAD_REQUEST);
    			return;
    		}
    		cause.printStackTrace();
    		if (ch.isConnected()) {
    			sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
    		}
    	}
    
    	private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
    		HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status);
    		response.setHeader(Names.CONTENT_TYPE, "text/plain; charset=UTF-8");
    		response.setContent(ChannelBuffers.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
    
    		// Close the connection as soon as the error message is sent.
    		ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
    	}
    }
  3. nodejs下的example.js:
    // var url = require('url');
    var http = require('http');
    http.createServer(function (req, res) {
      // var pathname = url.parse(req.url).pathname;
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('Hello World!\t' + new Date());
    }).listen(1337, '127.0.0.1');
    console.log('Server running at http://127.0.0.1:1337/');


测试结果:

  1. 线程数:100;循环次数:100;
  2. 线程数:1000;循环次数:10;
  3. 线程数:1000;循环次数:100;

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

展开阅读全文
加载中

作者的其它热门文章

打赏
0
21 收藏
分享
打赏
20 评论
21 收藏
0
分享
返回顶部
顶部