打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
node.js与java性能测试(http,与redis访问)

申明:

我对node.js与java这两种开发技术不会有什么偏爱的想法,觉得他们都有自己擅长的地方,将一门技术用在其适合的位置才是最合适的,个人观点是没有绝对的好与坏之分,所以请不要说我是什么黑。。。而且我也不会给出任何结论。。只如实的贴出数据。。。。

一直觉得网上有很多类似的对比,但是个人觉得都不是很客观,要么node.js懂的比较多,要么java懂的比较多。。。


测试环境:

服务器:亚马逊虚拟机,large,美国东部、。。。。(具体配置可以上亚马逊网站上面查)

http访问测试机器(客户端):亚马逊虚拟机,medium,美国东部

测试工具:apache ab

版本信息:node.js是v0.10.16    jre版本是1.7.0_45   netty版本是4.0final(java的nio框架)


测试用例(1):纯粹的http访问测试,客户端提交http请求,服务器返回hello world

node.js代码如下:

  1. var cluster = require('cluster');  
  2. var http = require('http');  
  3. var numCPUs = require('os').cpus().length;  
  4. var util = require("./util.js");  
  5.   
  6. if (cluster.isMaster) {  
  7.   // Fork workers.  
  8.     for (var i = 0; i < numCPUs; i++) {  
  9.         cluster.fork();  
  10.     }  
  11.   
  12.     cluster.on('exit', function(worker, code, signal) {  
  13.         console.log('worker ' + worker.process.pid + ' died');  
  14.     });  
  15. } else {  
  16.   // Workers can share any TCP connection  
  17.   // In this case its a HTTP server  
  18.     http.createServer(function(req, res) {  
  19.           
  20.         var buffer = new Buffer("hello world");  
  21.         var length = Buffer.byteLength("hello world");  
  22.         res.statusCode = 200;  
  23.         res.setHeader('Content-Length', length);  
  24.         res.end(buffer);  
  25.   
  26. /* 
  27.         util.getValue(function(reply){ 
  28.             var buffer = new Buffer(reply); 
  29.             var length = Buffer.byteLength(reply); 
  30.             res.statusCode = 200; 
  31.             res.setHeader('Content-Length', length); 
  32.             res.end(buffer); 
  33.         });*/  
  34.           
  35.     }).listen(8009);  
  36. }  

java代码如下:

  1. package fjs;  
  2.   
  3.   
  4. import io.netty.bootstrap.ServerBootstrap;  
  5. import io.netty.channel.ChannelFuture;  
  6. import io.netty.channel.ChannelInitializer;  
  7. import io.netty.channel.EventLoopGroup;  
  8. import io.netty.channel.nio.NioEventLoopGroup;  
  9. import io.netty.channel.socket.SocketChannel;  
  10. import io.netty.channel.socket.nio.NioServerSocketChannel;  
  11. import io.netty.handler.codec.http.HttpObjectAggregator;  
  12. import io.netty.handler.codec.http.HttpRequestDecoder;  
  13. import io.netty.handler.codec.http.HttpResponseEncoder;  
  14.   
  15. public class Server {  
  16.     private void start() throws InterruptedException {  
  17.         EventLoopGroup bossGroup = new NioEventLoopGroup(1);   //这个是用于serversocketchannel的eventloop  
  18.         EventLoopGroup workerGroup = new NioEventLoopGroup();    //这个是用于处理accept到的channel  
  19.         try {  
  20.             ServerBootstrap b = new ServerBootstrap();    //构建serverbootstrap对象  
  21.             b.group(bossGroup, workerGroup);   //设置时间循环对象,前者用来处理accept事件,后者用于处理已经建立的连接的io  
  22.             b.channel(NioServerSocketChannel.class);   //用它来建立新accept的连接,用于构造serversocketchannel的工厂类  
  23.               
  24.               
  25.             b.childHandler(new ChannelInitializer<SocketChannel>(){      //为accept channel的pipeline预添加的inboundhandler  
  26.                 @Override     //当新连接accept的时候,这个方法会调用  
  27.                 protected void initChannel(SocketChannel ch) throws Exception {  
  28.                       
  29.   
  30.                       
  31.                     ch.pipeline().addLast("decoder", new HttpRequestDecoder());   //用于解析http报文的handler  
  32.                     ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));   //用于将解析出来的数据封装成http对象,httprequest什么的  
  33.   
  34.                     ch.pipeline().addLast("encoder", new HttpResponseEncoder());   //用于将response编码成httpresponse报文发送  
  35.       
  36.                       
  37.                     ch.pipeline().addLast(new HttpHandler());  
  38.                 }  
  39.                   
  40.             });  
  41.             //bind方法会创建一个serverchannel,并且会将当前的channel注册到eventloop上面,  
  42.             //会为其绑定本地端口,并对其进行初始化,为其的pipeline加一些默认的handler  
  43.             ChannelFuture f = b.bind(8009).sync();      
  44.             f.channel().closeFuture().sync();  //相当于在这里阻塞,直到serverchannel关闭  
  45.         } finally {  
  46.             bossGroup.shutdownGracefully();  
  47.             workerGroup.shutdownGracefully();  
  48.         }  
  49.     }  
  50.       
  51.     public static void main(String args[]) throws InterruptedException {  
  52.         Server server = new Server();  
  53.         server.start();  
  54.     }  
  55. }  

  1. package fjs;  
  2.   
  3. import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;  
  4. import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;  
  5. import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;  
  6. import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;  
  7. import io.netty.buffer.ByteBuf;  
  8. import io.netty.channel.ChannelFutureListener;  
  9. import io.netty.channel.ChannelHandlerContext;  
  10. import io.netty.channel.ChannelInboundHandler;  
  11. import io.netty.handler.codec.http.DefaultFullHttpResponse;  
  12. import io.netty.handler.codec.http.FullHttpRequest;  
  13. import io.netty.handler.codec.http.HttpHeaders;  
  14. import io.netty.handler.codec.http.HttpHeaders.Values;  
  15. import io.netty.handler.codec.http.HttpResponseStatus;  
  16.   
  17.   
  18. public class HttpHandler implements ChannelInboundHandler{  
  19.   
  20.     public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  
  21.         // TODO Auto-generated method stu  
  22.     }  
  23.   
  24.     public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  
  25.         // TODO Auto-generated method stub  
  26.           
  27.     }  
  28.   
  29.     public void channelRegistered(ChannelHandlerContext ctx) throws Exception {  
  30.         // TODO Auto-generated method stub  
  31.           
  32.     }  
  33.   
  34.     public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {  
  35.         // TODO Auto-generated method stub  
  36.           
  37.     }  
  38.   
  39.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
  40.         // TODO Auto-generated method stub  
  41.           
  42.     }  
  43.   
  44.     public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
  45.         // TODO Auto-generated method stub  
  46.         ctx.pipeline().close();  
  47.     }  
  48.   
  49.     public void channelRead(ChannelHandlerContext ctx, Object req)  
  50.             throws Exception {  
  51.         // TODO Auto-generated method stub  
  52.         FullHttpRequest r = (FullHttpRequest)req;  //将其强制转化为httprequest  
  53.         ByteBuf b = ctx.alloc().buffer();  
  54.         //System.out.println(request.headers().get("Sec-WebSocket-Version"));  
  55.   
  56.           
  57.         b.writeBytes("hello world".getBytes());  
  58.         //b.writeBytes(Util.getValue().getBytes());  
  59.           
  60.         DefaultFullHttpResponse response = new DefaultFullHttpResponse( HTTP_1_1, HttpResponseStatus.OK, b);  
  61.         response.headers().set(CONTENT_LENGTH, b.readableBytes());  
  62.           
  63.         boolean keepAlive = isKeepAlive(r);   //判断当前的连接时否是keepalive的  
  64.         if (keepAlive) {  
  65.             response.headers().set(CONNECTION, Values.KEEP_ALIVE);  
  66.             ctx.writeAndFlush(response);  
  67.         } else {  
  68.             ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);  
  69.         }  
  70.           
  71.           
  72.           
  73.           
  74.   
  75.           
  76.     }  
  77.   
  78.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
  79.         // TODO Auto-generated method stub  
  80.           
  81.     }  
  82.   
  83.     public void userEventTriggered(ChannelHandlerContext ctx, Object evt)  
  84.             throws Exception {  
  85.         // TODO Auto-generated method stub  
  86.           
  87.     }  
  88.   
  89.     public void channelWritabilityChanged(ChannelHandlerContext ctx)  
  90.             throws Exception {  
  91.         // TODO Auto-generated method stub  
  92.           
  93.     }  
  94.   
  95.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)  
  96.             throws Exception {  
  97.         // TODO Auto-generated method stub  
  98.         ctx.pipeline().close();  
  99.         System.out.println(cause);  
  100.           
  101.     }  
  102.   
  103. }  

测试结果如下:

(1)node.js



(2)java:




其实上面java和node.js的数据都挺低的,还没有我自己的台式机上服务端和客户端一起跑跑出来的数据高。。。但是毕竟是虚拟机嘛,不能要求太高。。。。。


(2)测试用例(2),其实服务器还是返回hello world,只不过这个hello world是从redis里面取出来的。。。

node.js代码如下:

  1. var redis = require("redis");  
  2. var client;  
  3. client = redis.createClient(6379, "localhost");  
  4. client.auth('fjsfjs');  
  5. client.on("error", function (err) {  
  6.    // console.log("error event - " + client.host + ":" + client.port + " - " + err);  
  7.     console.log("aa" + err);  
  8. });  
  9.   
  10. exports.getValue = function(cb) {  
  11.     client.send_command('GET', ["node-netty-test"], function(err, reply){  
  12.         cb(reply);  
  13.     });  
  14. }  

  1. var cluster = require('cluster');  
  2. var http = require('http');  
  3. var numCPUs = require('os').cpus().length;  
  4. var util = require("./util.js");  
  5.   
  6. if (cluster.isMaster) {  
  7.   // Fork workers.  
  8.     for (var i = 0; i < numCPUs; i++) {  
  9.         cluster.fork();  
  10.     }  
  11.   
  12.     cluster.on('exit', function(worker, code, signal) {  
  13.         console.log('worker ' + worker.process.pid + ' died');  
  14.     });  
  15. } else {  
  16.   // Workers can share any TCP connection  
  17.   // In this case its a HTTP server  
  18.     http.createServer(function(req, res) {  
  19.         /* 
  20.         var buffer = new Buffer("hello world"); 
  21.         var length = Buffer.byteLength("hello world"); 
  22.         res.statusCode = 200; 
  23.         res.setHeader('Content-Length', length); 
  24.         res.end(buffer);*/  
  25.   
  26.         util.getValue(function(reply){  
  27.             var buffer = new Buffer(reply);  
  28.             var length = Buffer.byteLength(reply);  
  29.             res.statusCode = 200;  
  30.             res.setHeader('Content-Length', length);  
  31.             res.end(buffer);  
  32.         });  
  33.           
  34.     }).listen(8009);  
  35. }  

java代码如下:
  1. package fjs;  
  2.   
  3. import redis.clients.jedis.Jedis;  
  4. import redis.clients.jedis.JedisPool;  
  5. import redis.clients.jedis.JedisPoolConfig;  
  6. import redis.clients.jedis.exceptions.JedisConnectionException;  
  7.   
  8. public class Util {  
  9.     private static JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost", 6379, 2000, "fjsfjs");  
  10.     //private static JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");  
  11.     static {  
  12.         Jedis jedis = pool.getResource();  
  13.         try {  
  14.             jedis.set("node-netty-test", "hello world");  
  15.         } catch (JedisConnectionException e) {  
  16.             pool.returnBrokenResource(jedis);  
  17.         }finally {  
  18.             pool.returnResource(jedis);  
  19.         }  
  20.     }  
  21.       
  22.     public static String getValue() {  
  23.         Jedis jedis = pool.getResource();  
  24.         try {  
  25.             return jedis.get("node-netty-test");  
  26.         } catch (JedisConnectionException e) {  
  27.             pool.returnBrokenResource(jedis);  
  28.             return "";  
  29.         }finally {  
  30.             pool.returnResource(jedis);  
  31.         }  
  32.     }  
  33. }  

  1. package fjs;  
  2.   
  3. import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;  
  4. import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;  
  5. import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;  
  6. import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;  
  7. import io.netty.buffer.ByteBuf;  
  8. import io.netty.channel.ChannelFutureListener;  
  9. import io.netty.channel.ChannelHandlerContext;  
  10. import io.netty.channel.ChannelInboundHandler;  
  11. import io.netty.handler.codec.http.DefaultFullHttpResponse;  
  12. import io.netty.handler.codec.http.FullHttpRequest;  
  13. import io.netty.handler.codec.http.HttpHeaders;  
  14. import io.netty.handler.codec.http.HttpHeaders.Values;  
  15. import io.netty.handler.codec.http.HttpResponseStatus;  
  16.   
  17.   
  18. public class HttpHandler implements ChannelInboundHandler{  
  19.   
  20.     public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  
  21.         // TODO Auto-generated method stu  
  22.     }  
  23.   
  24.     public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  
  25.         // TODO Auto-generated method stub  
  26.           
  27.     }  
  28.   
  29.     public void channelRegistered(ChannelHandlerContext ctx) throws Exception {  
  30.         // TODO Auto-generated method stub  
  31.           
  32.     }  
  33.   
  34.     public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {  
  35.         // TODO Auto-generated method stub  
  36.           
  37.     }  
  38.   
  39.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
  40.         // TODO Auto-generated method stub  
  41.           
  42.     }  
  43.   
  44.     public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
  45.         // TODO Auto-generated method stub  
  46.         ctx.pipeline().close();  
  47.     }  
  48.   
  49.     public void channelRead(ChannelHandlerContext ctx, Object req)  
  50.             throws Exception {  
  51.         // TODO Auto-generated method stub  
  52.         FullHttpRequest r = (FullHttpRequest)req;  //将其强制转化为httprequest  
  53.         ByteBuf b = ctx.alloc().buffer();  
  54.         //System.out.println(request.headers().get("Sec-WebSocket-Version"));  
  55.   
  56.           
  57.         //b.writeBytes("hello world".getBytes());  
  58.         b.writeBytes(Util.getValue().getBytes());//改成从redis里面获取hello world  
  59.           
  60.         DefaultFullHttpResponse response = new DefaultFullHttpResponse( HTTP_1_1, HttpResponseStatus.OK, b);  
  61.         response.headers().set(CONTENT_LENGTH, b.readableBytes());  
  62.           
  63.         boolean keepAlive = isKeepAlive(r);   //判断当前的连接时否是keepalive的  
  64.         if (keepAlive) {  
  65.             response.headers().set(CONNECTION, Values.KEEP_ALIVE);  
  66.             ctx.writeAndFlush(response);  
  67.         } else {  
  68.             ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);  
  69.         }  
  70.           
  71.           
  72.           
  73.           
  74.   
  75.           
  76.     }  
  77.   
  78.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
  79.         // TODO Auto-generated method stub  
  80.           
  81.     }  
  82.   
  83.     public void userEventTriggered(ChannelHandlerContext ctx, Object evt)  
  84.             throws Exception {  
  85.         // TODO Auto-generated method stub  
  86.           
  87.     }  
  88.   
  89.     public void channelWritabilityChanged(ChannelHandlerContext ctx)  
  90.             throws Exception {  
  91.         // TODO Auto-generated method stub  
  92.           
  93.     }  
  94.   
  95.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)  
  96.             throws Exception {  
  97.         // TODO Auto-generated method stub  
  98.         ctx.pipeline().close();  
  99.         System.out.println(cause);  
  100.           
  101.     }  
  102.   
  103. }  

另外一个java源文件没有改变,


测试数据如下:

(1)node.js:



(2)java:



好了,所有的测试结果都已经贴出来了。。。

这里node.js考虑到了要绑定cpu的问题,但是后来实际发现这个影响不大。。。另外java对redis的访问因为采用的是连接池,官方文档本身就明确说这是线程安全的。。。。所以不会有问题。。。。


另外,因为服务器上有别的程序再跑,所以也有一定的影响,但这个影响不大,而且我贴出来的测试结果都是从好多结果中跳出来比较平均的结果贴出来的。。。。


另外对于测试用例以及其余的地方如果有什么不对的,还请指正。。。。。(没有测试 数据库,因为觉得太麻烦了,机器上没有装数据库。。。)


另外还要补充一下。。。node.js的cpu一般情况下是java的1.5-2 倍,内存都比较小,没啥对比的意思。。

好药补充一下。。java访问redis这里采用的是同步的,感觉影响也不大。。。毕竟redis访问性能太高了。。。所以对java的影响也不大。。。


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
你敢信?就是这个Netty的网络框架差点把我整疯了,哭jj
基于Netty5.0高级案例一之NettyWebsocket
Netty 4.0中的新变化和注意点 | 鸟窝
java编写基于netty的RPC框架
事件管道模型
基于Google Protobuf的Netty编解码技术
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服