小弟有點菜, 測試不科學的地方敬請指教。
java
環境:nginx
16G內存, 8核雙線程CPU, cenos6, jmeter, netty5, tomcat6, JDK1.7-64web
1 netty的源碼:example下的hello worldbootstrap
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; public class HttpHelloWorldServer { private final int port; public HttpHelloWorldServer(int port) { this.port = port; } public void run() throws Exception { // Configure the server. EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(50); try { ServerBootstrap b = new ServerBootstrap(); b.option(ChannelOption.SO_BACKLOG, 1024); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new HttpHelloWorldServerInitializer()); Channel ch = b.bind(port).sync().channel(); System.out.println(" connection is ok"); ch.closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8125; } new HttpHelloWorldServer(port).run(); } }
HttpHelloWorldServerHandler:tomcat
import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpRequest; import static io.netty.handler.codec.http.HttpHeaders.Names.*; import static io.netty.handler.codec.http.HttpHeaders.*; import static io.netty.handler.codec.http.HttpResponseStatus.*; import static io.netty.handler.codec.http.HttpVersion.*; public class HttpHelloWorldServerHandler extends ChannelHandlerAdapter { private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }; @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof HttpRequest) { HttpRequest req = (HttpRequest) msg; if (is100ContinueExpected(req)) { ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE)); } boolean keepAlive = isKeepAlive(req); FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(CONTENT)); response.headers().set(CONTENT_TYPE, "text/plain"); response.headers().set(CONTENT_LENGTH, response.content().readableBytes()); if (!keepAlive) { ctx.write(response).addListener(ChannelFutureListener.CLOSE); } else { response.headers().set(CONNECTION, Values.KEEP_ALIVE); ctx.write(response); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
HttpHelloWorldServerInitializer:app
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpServerCodec; public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); // Uncomment the following line if you want HTTPS //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); //engine.setUseClientMode(false); //p.addLast("ssl", new SslHandler(engine)); p.addLast("codec", new HttpServerCodec()); p.addLast("handler", new HttpHelloWorldServerHandler()); } }
2 tomcat的代碼, 就一個sevlet異步
package testTomcatHttp; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub PrintWriter printWriter = resp.getWriter(); printWriter.println("<h1>Hello World!</h1>"); } }
web.xmljvm
<servlet> <servlet-name>hello</servlet-name> <servlet-class>testTomcatHttp.TestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
測試備註:socket
1) 因爲tomcat6中, 有個bug, acceptor參數設置無效,只能是1, 因此咱們只改變maxThreads的值;ide
2) tomcat和netty的jvm參數配置爲: -server -Xms2048m -Xmx3098m -Xloggc:/root/nettyhttp/gc.log
3) jMeter循環次數都是1000次,sleep 1ms
測試用例:
(1) netty : acceptor=1, I/O Threads=50, jMeter的用戶線程數分別爲100和50
(2) tomcat nio: acceptor=1, maxThreads=50, jMeter的用戶線程數分別爲100和50
(3) tomcat bio: acceptor=1, maxThreads=50, jMeter的用戶線程數分別爲100和50
備註: 不穩定,第一次測試500多, 第二次700多, 且剛開始的Throughput很高, 可是越後越慢, 且開始error
(4) 在tomcat bio模式下, 把maxThreads=16 netty I/OThreads默認, 在本機上也是16,
測試的結果, tomcat只有300多, 且有報錯, 而netty的測試結果800上下,且沒有報錯。
因此, 根據測試結果能夠推斷出,
a netty+http在性能上和可靠性和仍是不錯的, 且能夠nginx搭配使用。
b tomcat, nio模式還能夠, 可是bio模式,測試結果不怎麼好。
且,
netty + http 定製不用受web容器的限制, IO線程對於執行時間比較長的task, 能夠異步交給現場池, 猜想tomcat的nio模式中, actiom-server中也能夠這樣作。可是tomcat, 別人都封裝好了, 不會出現大問題。
具體使用哪一個, 根據場景進行選擇。
歡迎指教!