10万Http(单机和集群Server)Subscribe的可行性实验和压测
0,前言
前文《基于Http协议订阅发布系统设计 》提到物联网的发布订阅系统是需要能够承受千万级别长连接的。因此,本文从实践的角度,验证基于Http协议的订阅系统的可行性。实验使用当前流行的Java Web开源技术,通过使用Servlet3.0的特性,可以看到单机条件下2.5G左右内存可以承受10万连接。最后,结合LVS的负载均衡技术,将10万连接均衡的负载到两台机器上。通过以上实验,说明企业有可能通过LVS强大的负载均衡能力,搭建千万级别的基于Http协议的发布订阅系统。
1,准备工作
环境: Linux, Jetty9.2, Jdk1.8-64bit
因为Unix内核实现的每一个socket连接都对应要打开一个文件,所以实验前需修改Linux系统临时配置,使用ulimit -n 修改单个进程可打开最大文件数(超过10^5)。
使用ConcurrentHashMap作为connection handler缓存(holder),参数使用默认参数(让map自动扩容): loadFactor= DEFAULT_LOAD_FACTOR = 0.75f; initialCapacity = DEFAULT_INITIAL_CAPACITY = 1 << 4。
2,单机环境实验
- 初始
连接数
由于实验机器有另一个Tomcat占用了8080端口,所以这里使用8088端口启动Jetty服务。
Jetty默认配置下启动服务的堆快照
- 建立2*10^4个http连接后
JVM堆快照
- 建立5*10^4个http连接后
JVM堆快照
- 建立10^5个连接后
JVM堆快照
- 系统和进程运行状态
3,多机环境实验
从上面单机服务下看,保持10万个Http连接,64位JVM大约需要消耗大约2.5G内存(32位JVM更省资源但内存寻址空间小,参见《深入理解Java虚拟机》第二版),这意味着需要超过25G的内存才能勉强承受百万连接,且不说CPU资源的要求。很显然,这种纵向拓展的方式不可行,因为在物联网环境下,硬件资源很快见顶。因此,横向拓展才应是物联网服务的首选。如果选用横向拓展的方式,就意味着集群机器可以运行更省资源的32位JVM,当然集群服务也有一系列问题需要解决。以下,将从集群角度来测试Http订阅请求的资源消耗以及可行性。市面上已有不少中间件支持Http协议的反向代理服务(开源如nginx、haproxy等)来搭建分布式集群,但是需要特别注意的是,订阅请求是一个Http长连接,Client向Server发送的请求将会保持很长时间,这意味着反向代理服务的端口会被一直占用,但用户可用最大端口范围是1024~2^16,这意味着TCP/IP的4层及以上协议的反向代理中间件都是不可行的,因此我们需要使用3层及以下协议的反向代理服务,本文使用开源的LVS(可以工作在3层和2层,不存在端口约束,资源消耗小)。考虑资源问题和实验性原则,本文使用4台机器(3太Linux VM实例,1台Windows),其中2台Request Client,2台Jetty Server,其中1台Server同时执行LVS服务。此外2台Server跑的是不同版本的Jdk(1.8和1.7),这样的目的是顺便检查一下不同JVM内存管理版本下的差异。
note: LVS集群搭建,新手简易入门(http://www.cnblogs.com/liwei0526vip/p/6370103.html),官方说明(http://www.austintek.com/LVS/LVS-HOWTO)。
- 同样使用ulimit -n 修改每台realserver的单个进程可打开最大文件数
- LVS请求统计
因为使用的权重是1:1负载,所以两台机器上分配了相等的连接数。
- 机器1(Jdk1.8):连接数和JVM栈数据
- 机器2(Jdk1.7):连接数和JVM栈数据
从上面两台Server的JVM堆快照可以看到,对于10^5个Http请求,LVS均匀地将请求负载到各个机器上去了。因此,使用TCP/IP 3层及以下协议作为负载均衡的集群方案是有可行性的。