前言
在性能测试过程中,经常会接触到链接数相关的问题,那就是一台服务器最多能支持多少链接数呢?
有的朋友可能会说是65535,因为操作系统有65535个端口,那么这个答案准确吗?
首先先了解下如何标识一个链接,操作系统是通过一个四元组来标识一个TCP链接:
{本地ip,本地port,远程ip,远程port}
这四个要素唯一确定一个TCP链接,任意一个要素不相同,就认为是一个不同的链接。
在Linux系统中,一切皆文件,每一个TCP链接都要占用一个文件句柄,系统允许创建的链接数取决于句柄数的上限。超过这个值再创建链接就会报这样的错误:
Can’t open so many files
内核文件描述符
查看及修改内核文件描述符的最大限制
查看
1 | more /proc/sys/fs/file-max |
临时生效
1 | echo 3195430 > /proc/sys/fs/file-max |
立即生效,永久生效
1 | echo "fs.file-max = 3195430" >> /etc/sysctl.conf |
系统连接数
查看
1 | ulimit -n |
参数
1 | -S use the soft resource limit # 设置软限制 |
临时生效
1 | ulimit -HSn 65535 |
永久生效
1 | cat /etc/security/limits.conf |
配置如下1
2
3
4* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
通过
1 | sysctl -p |
使得配置生效,可用通过ulimit -a查看file配置是否生效,临时设置也可用通过ulimit -u 65535
配置。
查看系统当前的连接数
1 | netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' |
结果
LAST_ACK 54
SYN_RECV 5
ESTABLISHED 4636
FIN_WAIT1 52
FIN_WAIT2 299
CLOSING 3
TIME_WAIT 1344
解析:
LAST_ACK
//等待所有分组死掉SYN_RECV
//一个连接请求已经到达,等待确认ESTABLISHED
//正常数据传输状态/当前并发连接数FIN_WAIT1
//应用说它已经完成FIN_WAIT2
//另一边已同意释放CLOSING
//两边同时尝试关闭TIME_WAIT
//另一边已初始化一个释放
单独查看TIME_WAIT
1 | ss -nat | grep TIME-WAIT |
这里看到大部分都是9001和9011端口的服务占用的
我们查询一下数量
1 | ss -nat | grep TIME-WAIT | grep 9001 | wc -l |
内核参数的优化
查看内核参数
1 | sysctl -a |
注意
调整内核参数后,内核处于不稳定状态,请务必重启实例。
打开配置文件
1 | vi /etc/sysctl.conf |
修改
1 | # 打开文件句柄数量 |
使得配置生效
1 | sysctl -p |
跟TIME_WAIT
有关的配置
1 | # TIME_WAIT 最高的队列数 |
调整次参数的同时,要调整TIME_WAIT_2到TIME_WAIT的超时时间,默认是60s,优化到30s:
1 | # TIME_WAIT_2到TIME_WAIT的超时时间 |
其它TCP本身的配合参数类似与synack重传次数、syn重传次数等以后介绍,优化后也是有所益处的。
1 | # 开启时就是同一个源IP来连接同一个目的端口的数据包时间戳必须是递增的,否则就丢弃 |
机器作为客户端时起作用,开启后time_wait在一秒内回收
不要开启,现在互联网NAT结构很多,可能直接无法三次握手
1 | # 不要开启,现在互联网NAT结构很多,可能直接无法三次握手 |
Nginx连接数
查看连接数
查看Nginx并发连接数
1 | netstat -apn|grep 'nginx: worker'|wc -l |
CPU相关信息查看
1 | # 逻辑CPU个数: |
配置连接数
Nginx总并发连接数 = worker数量 * worker_connections
一般建立连接的角度:客户并发连接为1.
nginx作为http服务器的时候:
max_clients = worker_processes * worker_connections
nginx作为反向代理服务器的时候:
max_clients = worker_processes * worker_connections/2
nginx做反向代理时,和客户端之间保持一个连接,和后端服务器保持一个连接。
但是怎样合理的设置worker_processes与worker_connections这两个参数?
1 | user nginx; |
根节点配置
1 | worker_processes auto; |
worker_processes
worker角色的进程个数(nginx启动后有多少个worker处理http请求。master不处理请求,而是根据相应配置文件信息管理worker进程. master进程主要负责对外揽活(即接收客户端的请求),并将活儿合理的分配给多个worker,每个worker进程主要负责干活(处理请求))。
nginx运行工作进程个数,一般设置cpu的核心或者核心数x2,如:worker_processes 4;
可以设置为auto
,auto
这个参数值是从nginx 1.3.8和nginx 1.2.5 开始进行支持的,自动参数可以自动检测 cpu cores
并设置 worker_processes
参数 。
1 | worker_processes auto; |
worker_processes最多开启8个,8个以上性能就不会再提升了,而且稳定性会变的更低,因此8个进程够用了。
查看nginx当前进程数:
1 | ps -aux | grep nginx |grep -v grep |
worker_rlimit_nofile
Nginx最多可以打开文件数,与ulimit -n
保持一致,如:worker_rlimit_nofile 65535;
为nginx工作进程改变打开最多文件描述符数目的限制。用来在不重启主进程的情况下增加限制。
worker_cpu_affinity
运行CPU亲和力,与worker_processes对应,如:worker_cpu_affinity 0001 0010 0100 1000;
2核cpu,开启2个进程
1 | worker_processes 2; |
解释:01表示启用第一个CPU内核,10表示启用第二个CPU内核
worker_cpu_affinity 01 10;表示开启两个进程,第一个进程对应着第一个CPU内核,第二个进程对应着第二个CPU内核。
2核cpu,开启4个进程
1 | worker_processes 4; |
解释:开启了四个进程,它们分别对应着开启2个CPU内核
4个cpu,开启4个进程
1 | worker_processes 4; |
解释:0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推
4核cpu,开启2个进程
1 | worker_processes 2; |
解释:0101表示开启第一个和第三个内核,1010表示开启第二个和第四个内核;2个进程对应着四个内核;worker_cpu_affinity配置是写在/etc/nginx/nginx.conf里面的;2核是 01,四核是0001,8核是00000001,有多少个核,就有几位数,1表示该内核开启,0表示该内核关闭。
8核cpu,开启8个进程
1 | worker_processes 8; |
解释:0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推;worker_processes最多开启8个,8个以上性能提升不会再提升了,而且稳定性变得更低,所以8个进程够用了。
配置完之后可以重启nginx,用ab工具或者wrk工具,可以进行性能测试。
在服务器上执行top
,然后按1
,就可以多个CPU工作情况,如果多个CPU内核的利用率差不多,就证明Nginx已经成功利用了多核CPU。
events
事件处理模型。
1 | events { |
use epoll:nginx采用epoll事件模型,处理效率高
work_connections:是单个worker进程允许客户端最大连接数,这个数值一般根据服务器性能和内存来制定,实际最大值就是worker进程数乘以work_connections,实际我们填入一个65535,足够了,这些都算并发值,一个网站的并发达到这么大的数量,也算一个大站了!
multi_accept :告诉nginx收到一个新连接通知后接受尽可能多的连接,默认是on,设置为on后,多个worker按串行方式来处理连接,也就是一个连接只有一个worker被唤醒,其他的处于休眠状态,设置为off后,多个worker按并行方式来处理连接,也就是一个连接会唤醒所有的worker,直到连接分配完毕,没有取得连接的继续休眠。当你的服务器连接数不多时,开启这个参数会让负载有一定的降低,但是当服务器的吞吐量很大时,为了效率,可以关闭这个参数。
重启
检查配置文件是否可用
1 | nginx -t |
重新加载配置文件
1 | service nginx reload |
或者重启
1 | service nginx restart |
进程信息
查看进程连接数
总连接数
1 | ps -ef |wc -l |
查询用户的连接数统计
1 | ps -ef |awk '{print $1}' |sort |uniq -c |sort -rn |
查看某个进程连接数:
1 | lsof -i:8|wc -l |
其中
-p:对应进程的PID
-i:对应进程的端口号
或者使用下面命令也能获取到
1 | netstat -nat|grep -i 8018|wc -l |
查看进程的线程数
物理内存决定的系统进程数上限
1 | cat /proc/sys/kernel/threads-max |
系统的进程或线程限制数
这个值表示进程ID的上限。为了兼容旧版,默认为32768(即两个字节)
1 | cat /proc/sys/kernel/pid_max |
用户最大进程或线程数
使用命令:
1 | ulimit -u |
ps -ef只打印进程,而ps -eLf会打印所有的线程
1 | ps -eLf | grep java |
ps -eLf各字段含义
UID:用户ID
PID:process id 进程id
PPID: parent process id 父进程id
LWP:表示这是个线程;要么是主线程(进程),要么是线程
NLWP: num of light weight process 轻量级进程数量,即线程数量
STIME: start time 启动时间
TIME: 占用的CPU总时间
TTY:该进程是在哪个终端运行的;pts/0255代表虚拟终端,一般是远程连接的终端;tty1tty7 代表本地控制台终端
CMD:进程的启动命令
查看pid
1 | lsof -i:8018 |
假如pid为26281
查询线程
1 | top -H -p ${pid} |
查询线程数量
1 | cat /proc/${pid}/status |
获取线程的PID
1 | ls /proc/${pid}/task |
树状显示线程
1 | pstree -p ${pid} |
列表显示线程
1 | ps -hH -p ${pid} |
进程命令数
查询进程正在运行的命令数
1 | lsof |awk '{print $1}' |sort |uniq -c |sort -rn |