一 前言
当管理大量连接时,特别是只有少量活跃连接,NGINX有比较好的CPU和RAM利用率,如今是多终端保持在线的时代,更能让NGINX发挥这个优点。本文做一个简单测试,NGINX在一个普通PC虚拟机上维护100k的HTTP长连接,然后查看NGINX和系统的资源利用率。
二 测试环境
1.服务端
硬件:双核2.3GHz,2GB内存
软件:CentOS 6.5, kernel 2.6.32, gcc 4.4.7, nginx 1.4.7
IP:10.211.55.8
内核参数调整:
$ /sbin/sysctl -w net.netfilter.nf_conntrack_max=102400 # 提升系统整体连接数
$ /sbin/sysctl net.netfilter.nf_conntrack_max #验证是否生效
NGINX从源码编译时带--with-http_stub_status_module,只列出与默认设置不同的部分:
worker_rlimit_nofile 102400;
events {
worker_connections 102400;
}
http {
# 设一个比较大得超时,客户端能以平缓的方式发送HEAD请求来维持KeepAlive
keepalive_timeout 3600;
#监控连接数,本机访问
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
2. 客户端1
硬件:双核2.3GHz,2GB内存
软件:CentOS 6.5, kernel 2.6.32, gcc 4.4.7, Python 3.3.5
IP:10.211.55.9
内核参数调整:
$ /sbin/sysctl -w net.ipv4.ip_local_port_range="1024 61024” #实际只使用50000个端口
$ /sbin/sysctl net.ipv4.ip_local_port_range #验证是否生效
$ vi /etc/security/limits.conf #提升当前用户的最大打开文件数nofile(hard >= soft > 50000)
$ ulimit -n #验证是否生效,可能需重启shell
Python 3.3.5从源码编译,如下配置:
$ pyvenv ~/pyvenv #创建虚拟环境,便于测试
$ . ~/pyvenv/bin/activate #激活虚拟环境
(pyvenv) $ python get-pip.py #从pip官网下载get-pip.py
(pyvenv) $ pip install asyncio #安装异步IO模块
因为Apache ab只能批量请求,不能维持连接,所以自己写了一个HTTP长连接测试工具asyncli.py,详细实现见 。
基本用法:
(pyvenv) $ python --help
usage: [-h] [-c CONNECTIONS] [-k KEEPALIVE] url
asyncli
positional arguments:
url page address
optional arguments:
-h, --help show this help message and exit
-c CONNECTIONS, --connections CONNECTIONS
number of connections simultaneously
-k KEEPALIVE, --keepalive KEEPALIVE
HTTP keepalive timeout
工作机制:
每隔10毫秒连续创建10个连接(每秒约1000个连接),直到总连接数达到CONNECTIONS,每个连接都会睡眠[1, KEEPALIVE / 2]的一个随机数(单位为秒),然后向服务端url发送一个HEAD请求来维持HTTP KeepAlive,然后重复上一个睡眠步骤。。。
3. 客户端2
与客户端1完全一致,除了IP为10.211.55.10
三 运行与输出
1. 服务端系统空闲
# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 1723336 11624 76124 0 0 62 1 26 28 0 0 100 0 0
2. 服务端启动NGINX,无外部WEB请求
# nginx
# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 1681552 11868 76840 0 0 50 1 24 25 0 0 100 0 0
3. 客户端1和2先后启动,每个客户端发起50000个长连接,并维持直到服务端关闭或超时。
(pyvenv) $ python -c 50000 -k 3600 &
4. 约2小时后。。。查看服务端
# curl
Active connections: 100001
server accepts handled requests
165539 165539 1095055
Reading: 0 Writing: 1 Waiting: 100000
# ps -p 1899 -o pid,%cpu,%mem,rss,comm
PID %CPU %MEM RSS COMMAND
1899 2.0 4.9 94600 nginx
# vmstat 3
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 654248 62920 158924 0 0 6 6 361 108 0 1 98 0 0
0 0 0 654232 62920 158952 0 0 0 85 804 218 0 1 98 0 0
0 0 0 654108 62928 158976 0 0 0 9 813 214 0 1 98 0 0
0 0 0 654108 62928 159004 0 0 0 0 803 220 0 1 99 0 0
^C
# free
total used free shared buffers cached
Mem: 1918576 1264576 654000 0 62952 159112
-/+ buffers/cache: 1042512 876064
Swap: 4128760 0 4128760
四 总结
1. NGINX平均每个连接的内存占用很小,通过ps的rss看出,每个连接物理内存占用约1k。多数内存都被内核TCP缓存占用。
2. NGINX维持大量连接(少量活跃连接,本文中平均每秒活跃连接为总连接数的千分之一)占用很少CPU,上文仅为2%。
3. 最好的优化就是不优化。整个测试除了提升文件数和连接数的这些硬限制外,没有任何参数调优,但仔细计算下就发现平均每个连接内存占用不到10k,远小于默认的缓存大小(net.ipv4.tcp_rmem = 4096 87380 4194304)和 (net.ipv4.tcp_wmem = 4096 16384 4194304)
4. NGINX维持此类连接的主要瓶颈就是可用内存大小,我的2GB内存虚拟机其实可以支持15万长连接,只不过我物理机器没有内存再继续clone虚拟机客户端了:-(
5. 虽然会遇到更多内核参数的限制,但大内存服务器支持100万连接是完全没问题的。