使用四种框架分别实现百万websocket常连接的服务器{转}
2017-02-22 00:00
363 查看
转:
http://colobu.com/2015/05/22/implement-C1000K-servers-by-spray-netty-undertow-and-node-js/
服务器的参数调优
TCP/IP参数配置
最大文件描述符
应用运行时调优
OutOfMemoryKiller
客户端的参数调优
服务器测试
Netty服务器
Spray服务器
Undertow
node.js
参考文档
事实上,最近我又增加了几个框架,现在包括Netty,Undertow,Jetty,Spray,Vert.x,Grizzly和Node.js七种框架。
测试数据可以看下一篇文章:七种WebSocket框架的性能比较
著名的C10K问题提出的时候,正是2001年。这篇文章可以说是高性能服务器开发的一个标志性文档,它讨论的就是单机为1万个连接提供服务这个问题,当时因为硬件和软件的限制,单机1万还是一个非常值得挑战的目标。但是时光荏苒,随着硬件和软件的飞速发展,单机1万的目标已经变成了最简单不过的事情。现在用任何一种主流语言都能提供单机1万的并发处理的能力。所以现在目标早已提高了100倍,变成C1000k,也就是一台服务器为100万连接提供服务。在2010年,2011年已经看到一些实现C1000K的文章了,所以在2015年,实现C1000K应该不是一件困难的事情。
本文是我在实践过程中的记录,我的目标是使用spran-websocket,netty,undertow和node.js四种框架分别实现C1000K的服务器,看看这几个框架实现的难以程度,性能如何。开发语言为Scala和Javascript。
当然,谈起性能,我们还必须谈到每秒每个连接有多少个请求,也就是RPS数,还要考虑每条消息的大小。
一般来说,我们会选取一个百分比,比如每秒20%的连接会收发消息。我的需求是服务器只是push,客户端不会主动发送消息。一般每一分钟会为这一百万群发一条消息。
所以实现的测试工具每个client建立60000个websocket连接,一共二十个client。实际不可能使用20台机器,我使用了两台AWSC3.2xlarge(8核16G)服务器作为客户端机。每台机器10个客户端。
服务器每1分钟群发一条消息。消息内容很简单,只是服务器的当天时间。
最近看到360用Go实现的消息推送系统,下面是他们的数据:
目前360消息推送系统服务于50+内部产品,万款开发平台App,实时长连接数亿量级,日独数十亿量级,1分钟内可以实现亿量级广播,日下发峰值百亿量级,400台物理机,3000多个实例分布在9个独立集群中,每个集群跨国内外近10个IDC。
四个服务器的代码和Client测试工具代码可以在github上下载。 (其实不止四种框架了,现在包括Netty,Undertow,Jetty,Spray-websocket,Vert.x,Grizzly和Node.js七种框架的实现)
测试下来可以看到每种服务器都能轻松达到同时120万的websocket活动连接,只是资源占用和事务处理时间有差别。120万只是保守数据,在这么多连接情况下服务器依然很轻松,下一步我会进行C2000K的测试。
在测试之前我们需要对服务器/客户机的一些参数进行调优。
/etc/sysctl.conf和/etc/security/limits.conf,用来配置TCP/IP参数和最大文件描述符。
/etc/sysctl.conf,配置网络参数。
数值根据需求进行调整。更多的参数可以看以前整理的一篇文章:LinuxTCP/IP协议栈调优。
执行/sbin/sysctl-p即时生效。
系统最大打开文件描述符数:/proc/sys/fs/file-max
临时性设置:echo1000000>/proc/sys/fs/file-max
永久设置:修改/etc/sysctl.conf文件,增加fs.file-max=1000000
进程最大打开文件描述符数
使用ulimit-n查看当前设置。使用ulimit-n1000000进行临时性设置。
要想永久生效,你可以修改/etc/security/limits.conf文件,增加下面的行:
还有一点要注意的就是hardlimit不能大于/proc/sys/fs/nr_open,因此有时你也需要修改nr_open的值。
执行echo2000000>/proc/sys/fs/nr_open
查看当前系统使用的打开文件描述符数,可以使用下面的命令:
其中第一个数表示当前系统已分配使用的打开文件描述符数,第二个数为分配后已释放的(目前已不再使用),第三个数等于file-max。
总结一下:
所有进程打开的文件描述符数不能超过/proc/sys/fs/file-max
单个进程打开的文件描述符数不能超过userlimit中nofile的softlimit
nofile的softlimit不能超过其hardlimit
nofile的hardlimit不能超过/proc/sys/fs/nr_open
服务器使用12G内存,吞吐率优先的垃圾回收器:
V8引擎
dmesg可以看到
这是Linux的OOMKiller主动杀死的。开启oom-killer的话,在/proc/pid下对每个进程都会多出3个与oom打分调节相关的文件。临时对某个进程可以忽略oom-killer可以使用下面的方式:
echo-17>/proc/$(pidofjava)/oom_adj
解决办法有多种,可以参看文章最后的参考文章,最好是换一个内存更大的机器。
要想达到更多的客户端连接,可以用更多的机器或者网卡,也可以使用虚拟IP来实现,比如下面的命令增加了19个IP地址,其中一个给服务器用,其它18个给client,这样
可以产生18*60000=1080000个连接。
修改/etc/sysctl.conf文件:
执行/sbin/sysctl-p即时生效。
这两台机器作为测试客户端绰绰有余,每台客户端机器创建了十个内网虚拟IP,每个IP创建60000个websocket连接。
客户端配置如下:
/etc/sysctl.conf配置
/etc/security/limits.conf配置
服务端配置如下:
/etc/sysctl.conf配置
/etc/security/limits.conf配置
每分钟给所有的120万个websocket发送一条消息,消息内容为当前的服务器的时间。这里发送显示是单线程发送,服务器发送完120万个总用时15秒左右。
发送时CPU使用率并不高,网络带宽占用基本在10M左右。
客户端(一共20个,这里选取其中一个查看它的指标)。每个客户端保持6万个连接。每个消息从服务器发送到客户端接收到总用时平均633毫秒,而且标准差很小,每个连接用时差不多。
平均每个client的RPS=1000,总的RPS大约为20000requests/seconds.
latency平均值为633ms,最长735ms,最短627ms。
每分钟给所有的120万个websocket发送一条消息,消息内容为当前的服务器的时间。
CPU使用较高,发送很快,带宽可以达到46M。群发完一次大约需要8秒左右。
客户端(一共20个,这里选取其中一个查看它的指标)。每个客户端保持6万个连接。每个消息从服务器发送到客户端接收到总用时平均1412毫秒,而且标准差较大,每个连接用时差别较大。
每分钟给所有的120万个websocket发送一条消息,消息内容为当前的服务器的时间。
群发玩一次大约需要15秒。
客户端(一共20个,这里选取其中一个查看它的指标)。每个客户端保持6万个连接。每个消息从服务器发送到客户端接收到总用时平均672毫秒,而且标准差较小,每个连接用时差别不大。
HTTP长连接200万尝试及调优
Linux最大打开文件描述符数
100万并发连接服务器笔记之1M并发连接目标达成
知乎:如何实现单服务器300万个长连接的?
构建C1000K的服务器
千万级并发实现的秘密
C1000k新思路:用户态TCP/IP协议栈
https://github.com/xiaojiaqi/C1000kPracticeGuide
600kconcurrentwebsocketconnectionsonAWSusingNode.js
https://plumbr.eu/blog/memory-leaks/out-of-memory-kill-process-or-sacrifice-child?utm_source=feedly&utm_reader=feedly&utm_medium=rss&utm_campaign=rss
http://it.deepinmind.com/java/2014/06/12/out-of-memory-kill-process-or-sacrifice-child.html
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-memory-captun.html
http://www.nateware.com/linux-network-tuning-for-2013.html#.VV0s6kawqgQ
http://warmjade.blogspot.jp/2014_03_22_archive.html
http://mp.weixin.qq.com/s?__biz=MjM5NzAwNDI4Mg==&mid=209282398&idx=1&sn=9ffef32b3ab93d1e239c9dc753a3a9bb
使用四种框架分别实现百万websocket常连接的服务器
目录[−]
事实上,最近我又增加了几个框架,现在包括Netty,Undertow,Jetty,Spray,Vert.x,Grizzly和Node.js七种框架。
测试数据可以看下一篇文章:
著名的
本文是我在实践过程中的记录,我的目标是使用spran-websocket,netty,undertow和node.js四种框架分别实现C1000K的服务器,看看这几个框架实现的难以程度,性能如何。开发语言为Scala和Javascript。
当然,谈起性能,我们还必须谈到每秒每个连接有多少个请求,也就是RPS数,还要考虑每条消息的大小。
一般来说,我们会选取一个百分比,比如每秒20%的连接会收发消息。我的需求是服务器只是
所以实现的测试工具每个client建立60000个websocket连接,一共二十个client。实际不可能使用20台机器,我使用了两台AWSC3.2xlarge(8核16G)服务器作为客户端机。每台机器10个客户端。
服务器每1分钟群发一条消息。消息内容很简单,只是服务器的当天时间。
最近看到360用Go实现的消息推送系统,下面是他们的数据:
目前360消息推送系统服务于50+内部产品,万款开发平台App,实时长连接数亿量级,日独数十亿量级,1分钟内可以实现亿量级广播,日下发峰值百亿量级,400台物理机,3000多个实例分布在9个独立集群中,每个集群跨国内外近10个IDC。
四个服务器的代码和Client测试工具代码可以在
测试下来可以看到每种服务器都能轻松达到同时120万的websocket活动连接,只是资源占用和事务处理时间有差别。120万只是保守数据,在这么多连接情况下服务器依然很轻松,下一步我会进行C2000K的测试。
在测试之前我们需要对服务器/客户机的一些参数进行调优。
服务器的参数调优
一般会修改两个文件,TCP/IP参数配置
修改文件2 3 | net.ipv4.tcp_rmem=4096873804161536 net.ipv4.tcp_mem=78643220971523145728 |
执行
最大文件描述符
Linux内核本身有文件描述符最大值的限制,你可以根据需要更改:系统最大打开文件描述符数:/proc/sys/fs/file-max
临时性设置:
永久设置:修改
进程最大打开文件描述符数
使用
要想永久生效,你可以修改
2 3 4 | *softnofile1000000 roothardnofile1000000 rootsoftnofile1000000 |
执行
查看当前系统使用的打开文件描述符数,可以使用下面的命令:
2 | 163201513506 |
总结一下:
所有进程打开的文件描述符数不能超过/proc/sys/fs/file-max
单个进程打开的文件描述符数不能超过userlimit中nofile的softlimit
nofile的softlimit不能超过其hardlimit
nofile的hardlimit不能超过/proc/sys/fs/nr_open
应用运行时调优
Java应用内存调优服务器使用12G内存,吞吐率优先的垃圾回收器:
OutOfMemoryKiller
如果服务器本身内存不大,比如8G,在不到100万连接的情况下,你的服务器进程有可能出现"Killed"的问题。运行解决办法有多种,可以参看文章最后的参考文章,最好是换一个内存更大的机器。
客户端的参数调优
在一台系统上,连接到一个远程服务时的本地端口是有限的。根据TCP/IP协议,由于端口是16位整数,也就只能是0到65535,而0到1023是预留端口,所以能分配的端口只是1024到65534,也就是64511个。也就是说,一台机器一个IP只能创建六万多个长连接。要想达到更多的客户端连接,可以用更多的机器或者网卡,也可以使用虚拟IP来实现,比如下面的命令增加了19个IP地址,其中一个给服务器用,其它18个给client,这样
可以产生18*60000=1080000个连接。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ifconfigeth0:1192.168.77.11netmask255.255.255.0up ifconfigeth0:2192.168.77.12netmask255.255.255.0up ifconfigeth0:3192.168.77.13netmask255.255.255.0up ifconfigeth0:4192.168.77.14netmask255.255.255.0up ifconfigeth0:5192.168.77.15netmask255.255.255.0up ifconfigeth0:6192.168.77.16netmask255.255.255.0up ifconfigeth0:7192.168.77.17netmask255.255.255.0up ifconfigeth0:8192.168.77.18netmask255.255.255.0up ifconfigeth0:9192.168.77.19netmask255.255.255.0up ifconfigeth0:10192.168.77.20netmask255.255.255.0up ifconfigeth0:11192.168.77.21netmask255.255.255.0up ifconfigeth0:12192.168.77.22netmask255.255.255.0up ifconfigeth0:13192.168.77.23netmask255.255.255.0up ifconfigeth0:14192.168.77.24netmask255.255.255.0up ifconfigeth0:15192.168.77.25netmask255.255.255.0up ifconfigeth0:16192.168.77.26netmask255.255.255.0up ifconfigeth0:17192.168.77.27netmask255.255.255.0up ifconfigeth0:18192.168.77.28netmask255.255.255.0up |
服务器测试
实际测试中我使用一台AWSC3.4xlarge(16cores,32Gmemory)作为应用服务器,两台AWSC3.2xlarge(8cores,16Gmemory)服务器作为客户端。这两台机器作为测试客户端绰绰有余,每台客户端机器创建了十个内网虚拟IP,每个IP创建60000个websocket连接。
客户端配置如下:
2 3 | fs.nr_open=2000000 net.ipv4.ip_local_port_range=102465535 |
2 3 4 5 | *hardnofile2000000 *softnproc2000000 *hardnproc2000000 |
2 3 | fs.nr_open=2000000 net.ipv4.ip_local_port_range=102465535 |
2 3 4 5 | *hardnofile2000000 *softnproc2000000 *hardnproc2000000 |
Netty服务器
建立120万个连接,不发送消息,轻轻松松达到。内存还剩14G未用。2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Total:1200231(kernel1200245) TCP:1200006(estab1200002,closed0,orphaned0,synrecv0,timewait0/0),ports4 TransportTotalIPIPv6 *1200245-- RAW000 UDP110 TCP120000612000060 INET120000712000070 FRAG000 totalusedfreesharedbufferscached Mem:30074154321464109254 -/+buffers/cache:1516714906 Swap:8150815 |
2 | 02:15:57.190[pool-1-thread-1]INFOcom.colobu.webtest.netty.WebServer$-sent1200000channelsforc4453a26-bca6-42b6-b29b-43653767f9fc |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | usrsysidlwaihiqsiq|readwrit|recvsend|inout|intcsw 00100000|00|60B540B|00|224440 00100000|00|60B870B|00|192382 00100000|00|59k74k|00|23062166 2787004|00|4998k6134k|00|169k140k 1787005|00|4996k6132k|00|174k140k 1787005|00|4972k6102k|00|176k140k 1787005|00|5095k6253k|00|178k142k 2787005|00|5238k6428k|00|179k144k 1787005|024k|4611k5660k|00|166k129k 1787005|00|5083k6238k|00|175k142k 1787005|00|5277k6477k|00|179k146k 1787005|00|5297k6500k|00|179k146k 1787005|00|5383k6607k|00|180k148k 1787005|00|5504k6756k|00|184k152k 1787005|048k|5584k6854k|00|183k152k 1787005|00|5585k6855k|00|183k153k 1787005|00|5589k6859k|00|184k153k 1591003|00|4073k4999k|00|135k110k 00100000|032k|60B390B|00|4822424 |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | count=60000 WebSocketErrorsforeb810c24-8565-43ea-bc27-9a0b2c910ca4 count=0 --Histograms------------------------------------------------------------------ Messagelatencyforeb810c24-8565-43ea-bc27-9a0b2c910ca4 count=693831 min=627 max=735 mean=633.06 stddev=9.61 median=631.00 75%<=633.00 95%<=640.00 98%<=651.00 99%<=670.00 99.9%<=735.00 --Meters---------------------------------------------------------------------- MessageRateforeb810c24-8565-43ea-bc27-9a0b2c910ca4 count=693832 meanrate=32991.37events/minute 1-minuterate=60309.26events/minute 5-minuterate=53523.45events/minute 15-minuterate=31926.26events/minute |
latency平均值为633ms,最长735ms,最短627ms。
Spray服务器
建立120万个连接,不发送消息,轻轻松松达到。它的内存相对较高,内存还剩7G。2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Total:1200234(kernel1200251) TCP:1200006(estab1200002,closed0,orphaned0,synrecv0,timewait0/0),ports4 TransportTotalIPIPv6 *1200251-- RAW000 UDP110 TCP120000612000060 INET120000712000070 FRAG000 totalusedfreesharedbufferscached Mem:30074223717703010259 -/+buffers/cache:221007973 Swap:8150815 |
CPU使用较高,发送很快,带宽可以达到46M。群发完一次大约需要8秒左右。
2 | 05/2204:43:05.279INFO[ool-2-worker-15]c.c.w.s.WebServer-sentmsgtoworkersfor8454e7d8-b8ca-4881-912b-6cdf3e6787bf.currentworkers:1200000 |
2 3 4 5 6 7 8 9 10 | usrsysidlwaihiqsiq|readwrit|recvsend|inout|intcsw 74914003|024k|6330k20M|00|20k1696 70230006|064k|11M58M|00|18k2526 75116007|00|9362k66M|00|24k11k 8248006|00|11M35M|00|24k10k 85014001|00|8334k12M|00|44k415 84015001|00|9109k16M|00|36k425 81019000|024k|919k858k|00|23k629 76023000|00|151k185k|00|18k1075 |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | count=60000 WebSocketErrorsfor6674c9d8-24c6-4e77-9fc0-58afabe7436f count=0 --Histograms------------------------------------------------------------------ Messagelatencyfor6674c9d8-24c6-4e77-9fc0-58afabe7436f count=454157 min=716 max=9297 mean=1412.77 stddev=1102.64 median=991.00 75%<=1449.00 95%<=4136.00 98%<=4951.00 99%<=5308.00 99.9%<=8854.00 --Meters---------------------------------------------------------------------- MessageRatefor6674c9d8-24c6-4e77-9fc0-58afabe7436f count=454244 meanrate=18821.51events/minute 1-minuterate=67705.18events/minute 5-minuterate=49917.79events/minute 15-minuterate=24355.57events/minute |
Undertow
建立120万个连接,不发送消息,轻轻松松达到。内存占用较少,还剩余11G内存。2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Total:1200234(kernel1200240) TCP:1200006(estab1200002,closed0,orphaned0,synrecv0,timewait0/0),ports4 TransportTotalIPIPv6 *1200240-- RAW000 UDP110 TCP120000612000060 INET120000712000070 FRAG000 totalusedfreesharedbufferscached Mem:300741849711576010286 -/+buffers/cache:1820011873 Swap:8150815 |
群发玩一次大约需要15秒。
2 | 03:19:46.755[pool-1-thread-1]INFOc.colobu.webtest.undertow.WebServer$-sent1200000channelsford9b450da-2631-42bc-a802-44285f63a62d |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | count=60000 WebSocketErrorsforb2e95e8d-b17a-4cfa-94d5-e70832034d4d count=0 --Histograms------------------------------------------------------------------ Messagelatencyforb2e95e8d-b17a-4cfa-94d5-e70832034d4d count=460800 min=667 max=781 mean=672.12 stddev=5.90 median=671.00 75%<=672.00 95%<=678.00 98%<=684.00 99%<=690.00 99.9%<=776.00 --Meters---------------------------------------------------------------------- MessageRateforb2e95e8d-b17a-4cfa-94d5-e70832034d4d count=460813 meanrate=27065.85events/minute 1-minuterate=69271.67events/minute 5-minuterate=48641.78events/minute 15-minuterate=24128.67events/minute SetupRateforb2e95e8d-b17a-4cfa-94d5-e70832034d4d |
node.js
node.js不是我要考虑的框架,列在这里只是作为参考。性能也不错。2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | count=60000 WebSocketErrorsfor537c7f0d-e58b-4996-b29e-098fe2682dcf count=0 --Histograms------------------------------------------------------------------ Messagelatencyfor537c7f0d-e58b-4996-b29e-098fe2682dcf count=180000 min=808 max=847 mean=812.10 stddev=1.95 median=812.00 75%<=812.00 95%<=813.00 98%<=814.00 99%<=815.00 99.9%<=847.00 --Meters---------------------------------------------------------------------- MessageRatefor537c7f0d-e58b-4996-b29e-098fe2682dcf count=180000 meanrate=7191.98events/minute 1-minuterate=10372.33events/minute 5-minuterate=16425.78events/minute 15-minuterate=9080.53events/minute |
参考文档
相关文章推荐
- 使用四种框架分别实现百万websocket常连接的服务器
- 使用四种框架分别实现百万websocket常连接的服务器--转
- 使用四种框架分别实现百万websocket常连接的服务器
- 使用四种框架分别实现百万websocket常连接的服务器
- 使用四种框架分别实现百万websocket常连接的服务器
- 使用四种框架分别实现百万websocket常连接的服务器
- 使用四种框架分别实现百万websocket常连接的服务器
- 使用四种框架分别实现百万websocket常连接的服务器
- 使用四种框架分别实现1百万websocket常连接的服务器
- 使用四种框架分别实现1百万websocket常连接的服务器
- 使用四种框架分别实现1百万websocket常连接的服务器
- 使用四种框架分别实现1百万websocket常连接的服务器
- 四种框架分别实现百万 websocket 常连接的服务器
- 四种框架分别实现百万 websocket 常连接的服务器
- 使用四种框架分别实现1百万websocket常连接的服务器
- 使用php的swoole框架,实现高性能长连接websocket
- android使用websocket连接服务器
- Android 使用Socket实现服务器与手机客户端的长连接三:clientA 发送给clientB,定点发送
- 菜鸟使用SSM框架搭建web服务器实现登录功能(Spring+SpringMVC+Mybatis)
- android socket基于mina框架实现和服务器长连接