单机千万并发连接实战

很早以前就听说了c10k,c100k,c1000k等问题,每个问题的解决都是并发编程的一个里程碑。随着硬件的快速提升,那么10m(千万)并发连接呢?能否做到?如何做到?会有什么限制?小编对此很好奇,折腾了不少时间,终于有了令人兴奋的答案!
下面我们使用github.com/yedf/handy库自带的例子程序,来跑出一个单机千万并发连接的实例,先上操作步骤,后面解释。

准备机器

10m连接,大家的个人电脑肯定无法满足要求,如果不是在大公司任职,弄个实际的物理机对大家是个奢望。那么怎么办?我也面临同样问题。
现在的云计算这么发达,还可以按小时计费,一小时的费用也就几元,那就试试云计算产品吧。小编先是在阿里云上测试,但阿里云的按需付费主机配置不高,费了不少时间,最终只跑到了3m个连接。阿里云的不行,是主机的配置问题还是程序的问题呢?为了得到最终的结论,我尝试了其他的云产品,最终ucloud的云主机给了我惊喜。

首先创建ucloud主机
ucloud主机(一共需要两台,一台作为服务器,一台作为客户端):
. 选择主机管理的创建主机
. 系统选择ubuntu14.4 64bit (小编的测试程序是c++11,需要高版本的g++)
. 机型标准版
. 网络增强一定要选择开启 (千万连接是网络IO密集型,网络当然要强大型)
. cpu 16核 内存64G 数据盘0
. 下一步中的网络类型选择基础网络即可,创建主机之后,需要购买弹性ip,并且绑定到主机
. 价格:小编实验时(2015年8月),上述的配置,一台仅需7.2元一小时,两台不到15元

做实验的时候,大家记得要眼疾手快哦,一小时十几元,获得了自己想要的结果就赶紧释放主机哈

调整系统参数

10m并发连接对系统是个挑战,需要调整相关的参数

sysctl -w fs.file-max=10485760 #系统允许的文件描述符数量10m
sysctl -w net.ipv4.tcp_rmem=1024 #每个tcp连接的读取缓冲区1k,一个连接1k
sysctl -w net.ipv4.tcp_wmem=1024 #每个tcp连接的写入缓冲区1k
#修改默认的本地端口范围
sysctl -w net.ipv4.ip_local_port_range='1024 65535' 
sysctl -w net.ipv4.tcp_tw_recycle=1  #快速回收time_wait的连接
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_timestamps=1
#用户单进程的最大文件数,用户登录时生效
echo '* soft nofile 1048576' >> /etc/security/limits.conf 
echo '* hard nofile 1048576' >> /etc/security/limits.conf 
ulimit -n 1048576 #用户单进程的最大文件数 当前会话生效

部署程序

下面可以开始部署我们的测试程序了

apt-get update
apt-get install -y screen git make g++ nload iptraf
git clone https://github.com/yedf/handy
cd handy
git checkout 97b5426f91d37
make -j4

运行测试程序

选取一台主机S作为服务器,运行服务器

10m/10m-svr 100 300 10 301 #启动10个子进程,每个进程分别监听100-300的端口

选取另一台主机C作为客户端,运行客户端,(需要填写S的内网ip)

#启动10个客户端子进程,连接到S的100-300端口,发起10m个连接,在500秒内创建所有的连接,每600秒发送一个心跳,心跳数据为64字节,多进程的管理端口为301
10m/10m-cli <S> 100 300 10000000 500 10 600 64 301 

观察结果

然后,10m连接的建立就不需要更多的步骤啦,使用命令
watch ss -s
我们就可以开始观察连接的创建进度啦,看着连接渐渐的往上走,超过10k,100k, 1m是不是很有成就感。

说明

并发连接数到达千万时,有诸多方面的问题需要解决:

. 单进程最大文件数量限制:limit -n 最多能把这个数字修改到1048575,因此单个进程最多能够打开百万个文件,千万并发连接需要千万个文件描述符,于是我们使用多进程来做到千万文件的支持

.多进程之间的负载均衡:nginx使用多进程来增加自己的吞吐量,原先采用共享锁的方式来平衡负载,对核数较多的服务器,较多的进程并没有达到性能的线性提升。最新的linux内核引入了SO_REUSEPORT选项,该选项可以自动平衡监听同一端口的多进程,是内核级的解决方案。handy采用该方案,优于nginx的旧有方式(最新的nginx也支持SO_REUSEPORT)。

.测试中客户端本地端口不够:让服务器监听了200个端口,这样客户端连接服务器的每个端口只有50k个连接,然后加大默认的本地端口范围就可以满足要求(见前面的服务器系统参数)

测试中如果一次性创建千万个连接,则绝大部分的连接创建都会失败,因此让客户端每100ms创建2000个连接,提高连接创建的成功率。

系统在运行中,并没有多少的负载,当然啦,一部分负载跑到底层的hypervisor去了

小编实验的机器上内存占用大约40G,平均一个连接前后一共用了4k,不多不多

大家可以通过iptraf,nload等工具来查看系统的网络情况

写到这里,顺便给出我测是的ucloud主机的性能参数吧:
网卡流量最多可以到1.2GBit/s,并非所有时间都到了这么高,并不稳定,一般在800M-1.2G之间波动
tcp收包发包的最高qps是12w/s,多了就上不去了

后续

为了达到千万条连接,折腾了不少问题,上面只是个大概,有些地方的细节并没有深入探讨。如果大家有兴趣,后续会慢慢把其他细节分享出来。


--------2017-12-02更新测试结果-------

最近看见阿里推出了网络增强型服务器,pps能够达到450w,于是拿handy的千万连接进行了测试。在阿里云上面,按量购买无法购买到最高配的虚机,最高的只购买了下面机型:

网络增强型,60w pps,16核,64G

命令如下

handy/10m/10m-svr 100 500 16 501 #服务器
handy/10m/10m-cli <S> 100 500 10000000 150 16 170 64 501 # 150s创建1千万连接

能够完成千万条连接,达到的pps大约是20w,进一步增加网络负载会导致一定程度丢包,这个qps与主机声称的60w差距较大,可能跟当时共享的机器有关


网络增强型,100wpps,8核,32G

命令如下

handy/10m/10m-svr 100 500 16 501 #服务器
handy/10m/10m-cli <S> 100 500 6500000 30 16 40 64 501 # 30s 创建650w连接

32G内存只到650w连接,达到的pps大约是65w,进一步增加网络负载会导致一定程度丢包


handy的各个测试中,应用的性能都会随着主机的性能提升而提升,瓶颈主要是在系统的内存和网卡IO处

大家如果有更高配的机型,并且有兴趣测一测,欢迎大家把测试结果发给我,合并到本文的结果中

编辑于 2017-12-02

文章被以下专栏收录