`
m635674608
  • 浏览: 5052918 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

tomcat nodejs nginx 对比分析

 
阅读更多

  在互联网项目迅速膨胀的背景下,我们公司,一个传统的金融公司,也开始风风火火地开展互联网项目,最近被派到一个手机APP的项目做后台架构支 持。首先面临一个问题就是如何选择一个合适的WEB中间件产品来满足高并发的场景,也就是要构建一个IO密集型的应用,而且还要面向手机客户端(低带 宽)。

    在网上搜罗了一下相关的产品,主要就是tomcat,nodejs,nginx三种产品,但是对这三个产品从原理上对比分析的文章巨少无比,都是泛泛地做一个压力测试。

 

    先说一下我们公司的技术背景,我们公司技术都以JAVA为主,所以在选择WEB中间件的时候,我会以不改变公司基础技术为前提做选择,nodejs来佐证。

 

    首先我们有一个很关键的诉求,客户端是手机,而手机往往是低带宽的,我们需要先编程测试代码,模拟低带宽的场景,下面是我写的模拟低带宽的测试代码

 

package http.client;
 
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class BIOHttpClient {
	int taskAccount=1;
	static BIOHttpClient inst=new BIOHttpClient();
	public static void main(String args[]) { 
		inst.doTasksTest();
	}
	private void doTasksTest(){
		for(int i=0;i<taskAccount;i++ ){
			new RequestTask().start();
		}
	}
}

class RequestTask extends Thread{
	String host="localhost";
	int port=8080;
	public void run() { 
		this.doRequest(); 
	} 
	
	private void doRequest(){
		try {
			Socket socket=createNewSocket();  
			this.sendMsg(socket);
			//Thread.currentThread().sleep(10*1000);
			this.getResponseMsg(socket);
			socket.close(); // 关闭Socket 
		}catch (Exception e) { 
			throw new RuntimeException(e);
		}
	}
	
	private Socket createNewSocket()throws Exception{
		Socket socket= new Socket(host,port );// 向本机的端口发出客户请求
		socket.setReceiveBufferSize(1);//似乎不起作用。
		socket.setSendBufferSize(1);//似乎不起作用。
		System.out.println(this+"::客户端连接服务端成功!"  );
		return socket;
	}
	
	private void sendMsg(Socket socket)throws Exception{
		String postStr = "account=abc&password=123456789";
		int postStrLen = postStr.length();
		StringBuffer post = new StringBuffer("POST /test/test HTTP/1.1\r\n");
		post.append("Host: 127.0.0.1:8080\r\n");
		post.append("Accept: text/html\r\n");
		post.append("Connection: Close\r\n");
		post.append("Content-Length: " + postStrLen + "\r\n");
		post.append("Content-Type: application/x-www-form-urlencoded\r\n");
		post.append("\r\n");
		post.append(postStr);
		PrintWriter os = new PrintWriter(socket.getOutputStream());// 由Socket对象得到输出流,并构造PrintWriter对象
		os.println(post); 
		os.flush();// 刷新输出流,使Server马上收到该字符串
		System.out.println(this+"::send msg to server:" + post+"::"+System.currentTimeMillis() ); 
	}
	
	private void getResponseMsg(Socket socket)throws Exception{ 
		StringBuilder sb=new StringBuilder(); 
		InputStream reader = socket.getInputStream() ; // 由Socket对象得到输入流,并构造相应的BufferedReader对象
		int size=1;//通常是8K~64K,如果设置为1,则明显可以模拟低带宽。
		byte[] bs=new byte[size];//通过改变size来模拟低带宽读写。当size=1,且服务端数据量足够大(100万个字符以上),这样可以明显看到对BIOServer是有write阻塞的,但对NIOServer就不会阻塞。
		String tmp=null;
		while ( (reader.read(bs)) != -1) {//读完后会阻塞
			tmp=new String(bs).trim();
			if( tmp.lastIndexOf("#endflag#")>0 ){//为防止读完后,跳到循环阻塞住导致不退出循环,要求服务端必须返回特定字符作为双方结束通信的协议。
				break;
			}else{
				//Thread.currentThread().sleep(10);
				//System.out.println(tmp);
				sb.append(tmp); 
			} 
		}    
		System.out.println(this+"::get response msg from server,数据长度:"+sb.length()+"::"+System.currentTimeMillis() );  
	}
}

 

        通过控制读取的byte数组的长度来模拟低带宽,先通过这个测试代码来测试一下tomcat6,tomcat6默认配置采用的bio的模式来处理请求的,下面是服务端代码

 

package example;

import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

public class TestServlet extends HttpServlet {
	
	private byte[] data;
	
	public TestServlet(){
		try {
			InputStream in = this.getClass().getClassLoader().getResourceAsStream("data.txt");
			data = IOUtils.toByteArray(in);
			System.out.println("数据读取完毕");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		long start = System.currentTimeMillis();
		resp.getOutputStream().write(data);
		resp.getOutputStream().flush();
		System.out.println(Thread.currentThread() + "写数据结束 ,回写的数据长度为:" + data.length);
		System.out.println("use time : " + (System.currentTimeMillis() - start));
	}
	
}

 

    在byte数组长度设置为1的时候,服务端回写数据(数据大小为5M)耗时为7944毫秒,当byte数组长度设置为1024的时候,耗时 为167毫秒,也就是说,tomcat在bio模式下,处理客户端为低带宽的场景的能力是非常糟糕的!tomcat的bio模式是传统中间件的一类代表, 正由于这类阻塞式的IO模式的设计,导致这类中间件无法满足互联网高并发请求的需求。在高并发场景需求的驱动下,java nio 诞生了,对于java nio封装实现较好的产品有netty和mina两个产品,但是很遗憾,这两个产品不算一个完整WEB中间件,所以这里我就不做详细讨论了。通过寻找 tomcat的官方文档,发现tomcat6以后,可以通过修改connector的协议配置,能支持nio模式。发现新大陆,麻烦修改配置测试之!修改 配置如下。

 

     <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" 
               executor="tomcatThreadPool"
               connectionTimeout="20000" 
               redirectPort="8443" 
               />

 

    非常遗憾,测试结果是byte数组长度为1时耗时为8413毫秒,长度为1024时,耗时为2190。what!不是nio了么?继续查看 tomcat官方文档以及源码,发现这个tomcat6的nio是伪nio,因为它在读写io的时候仍然采用的blocking的方式的,下面附上 tomcat官网上的对比说明图。

 

 

        继续寻找,发现真正实现异步IO的产品有三个,tomcat6.x/tomcat7.x+nginx,tomcat8.x(servlet3.1),nodejs。针对这三个产品做测试,测试数据如下

 

  tomcat6 bio(tomcat6不支持 nio技术) tomcat6 bio + nginx Nodejs tomcat8 nio
低带宽场景 7944毫秒 147毫秒 111毫秒 78毫秒
正常带宽场景 167毫秒 141毫秒 118毫秒 32毫秒

    从 测试数据就可以看到,在低带宽场景下,传统的中间件的处理能力是远远小于其它三个产品。这组测试数据只是想证明后面三个产品是真正实现异步IO的。对于产 品的选择,个人意见是如果你们的技术平台已经背负了沉重的java的历史包袱,那就选择在已有的WEB中间件前增加代理服务器nginx,如果是新的项 目,则采用tomcat8的servlet3.1来实现。仅仅在处理异步IO上,三个产品都差不多,没有哪个最好,只有哪个更适合

 

http://m.oschina.net/blog/340539

分享到:
评论

相关推荐

    maven、java、tomcat、nginx、nodejs、mysql

    maven、java、tomcat、nginx、nodejs、mysql以及idea和navicate的注册使用

    一个服务器搭多个tomcat导致session丢失,或者同一个IP不同端口,多个应用的session会冲突解决方法

    一个服务器上搭建了多个tomcat或者weblogic,端口不一样,同时启动访问时session丢失。如:A,B两个服务,在浏览器中登录访问A后,当前打开的浏览器上在开一个选项卡访问B服务后,回过来点击访问A时session丢失,...

    3分钟快速搭建nodejs本地服务器方法运行测试html/js

    做前端的都知道,公司的项目在自己的电脑上搭建环境是挺麻烦的一件事情 首先:一般个人电脑没公司的配置性能好, 其次:搭建公司项目在自己电脑涉及很多缓存...于是百度看到了nodejs和nginx,带着对前端服务器的好奇

    dockerfiles:Dockerfile的集合(apache2,nginx,tomcat,beats,elasticsearch,openjdk,oraclejdk,mongodb,redis,couchdb)

    apache2-Apache 2( ) nginx-Nginx( ) Tomcat-Tomcat 9( ) elasticsearch-Elasticsearch( ) kibana-Kibana( ) logstash-Logstash( ) 节拍-节拍( ) java-runtime,openjdk-8-jre-OpenJDK 8 JRE( ) ...

    服务器部署(保姆级教程).pdf

    在开始服务器部署之前,需要下载和安装多个组件,包括JDK、Tomcat、MySQL、Redis、Nginx、Node和Maven。这些组件都是服务器部署的必要组件。 1. 下载JDK安装包: ...

    nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证示例

    http模块内部封装了http服务器和客户端,因此Node.js不需要借助Apache、IIS、Nginx、Tomcat等传统HTTP服务器,就可以构建http服务器,亦可以用来做一些爬虫。下面简单介绍该模块的使用,其具体API,大家可以自行去...

    基于nodejs的学习资料销售平台和微信小程序源码.zip

    项目部署可能涉及到Nginx反向代理、Docker容器化、持续集成/持续部署(CI/CD)流程等,确保应用稳定运行。 总的来说,这个项目涵盖了从前端到后端的完整开发流程,涉及的技术栈包括Node.js、Express、MongoDB、...

    基于jsp+mvc的企业财务管理系统源码.zip

    部署方面,可能使用Apache Tomcat、Nginx等Web服务器,或者Docker容器化部署。 这个项目为学习者提供了一个实践MVC设计模式和Java Web开发的实例,同时也展示了如何结合Node.js和Express构建现代Web应用的后端部分...

    shell-常用脚本.rar

    shell常用脚本:http、httpd、jdk1.7、jdk1.8、ip-location、kafka、lamp、nginx、nodejs、openssl、python、php、prce8、redis、rvm、tomcat、zabbix、nvm。。。。。。。。。。等等,不在逐一赘述,可以下载使用

    java雷电飞机源码-ajax-cors-json:ajax,请求行,头,主体,json数据,cors跨域

    HTTP服务器:Apache、Nginx、IIS、Tomcat、NodeJS等; 服务器想要对外提供什么服务,就安装相应的服务器软件。 1.3 服务器类型 按不同的划分标准,服务器可划分为以下类型: 按软件功能类型划分: 文件服务器、...

    唯品会服务化接入网关.pdf

    在技术栈选择和实现方面,唯品会选择了基于Java的技术栈,同时也依赖于nginx、nodejs、go等技术。Java技术栈具有良好的跨平台性、安全性,以及丰富的开发资源,适用于构建大型、复杂的系统。nginx作为高性能的HTTP和...

    word源码java-TechBoard:整理开发中积累的各种开源库、框架、工具、方法等

    Apache、Nginx、Tomcat、Nodejs、Docker 数据库 Oracle、SqlServer、MySql、PostgreSql、Sqlite、MongoDB WEB前端 AngularJS、JQuery、ReactJS、EasyUI、Bootstrap、Highcharts、Umediter、Meteor、Ember Python ...

    WEB搭建学习.docx

    本文档主要介绍了一种基于**Vue+Nginx+Element-UI+Tomcat+SpringBoot**的技术栈来搭建Web环境的方法。这种技术组合非常适合用于现代Web应用开发,尤其适用于前后端完全分离的场景。 #### 二、软件准备 ##### 1. ...

    avue技术讲解文档ffff

    - 分析部署失败的原因,排除配置问题。 以上就是从“avue技术讲解文档”中提取的关键知识点,涵盖了从环境搭建到二次开发再到部署优化的全流程,旨在帮助开发者全面了解并掌握Avue的相关技术和实践技巧。

    NiceFish博客系统-其他

    在 How to: Configure your server to work with html5Mode 这个小节里面把常见的 WEB 容器的配置方式都列举出来了,包括:IIS、Apache、nginx、NodeJS、Tomcat 全部都有。主要依赖:Angular 10.0.3PrimeNG 10.0.0...

    前后端分离系统架构概述.docx

    通过使用 nginx+tomcat 或者中间加一个 nodejs 的方式,可以有效地进行解耦,并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如:浏览器,车载终端,安卓,IOS 等等...

    基于Java记账管理系统源码.zip

    部署时,可能使用Tomcat作为Java应用服务器,Nginx作为反向代理和负载均衡器,确保服务的高可用性。 总的来说,这个基于Java的记账管理系统充分利用了Java和JavaScript的技术优势,实现了高效、安全的财务数据管理...

Global site tag (gtag.js) - Google Analytics