以前没有动手实践高并发系统搭建,对它的认知局限在事务控制,异步处理,微服务,负载均衡的应用层处理上。这两天在服务器的实践调优,了解如何配置参数,更重要的是知道为什么要这么配置,从而认识到了应用与操作系统的一些相关联系。
这个过程遇到了许多bug和系统相关,在这次记录中也会一起提到。文章后面会附上实测情况。
nginx配置
下面是nginx的主要主要配置。
# 避免权限问题
user root;
# 一般设置逻辑cpu数,可参看自身系统配置:cat /proc/cpuinfo| grep "processor"| wc -l
worker_processes 6;
# 内核一切皆文件,所以有客户端连接就会有文件使用。
worker_rlimit_nofile 256000;
events {
# Linux内核为处理大批量文件选择的模式
use epoll;
# 收到一个新连接通知后接受尽可能多的连接。
multi_accept on;
# 单个进程连接数
worker_connections 65535;
}
http {
# 负载均衡服务器,我这里用了10个节点不一一列举
upstream load{
server dc-sit-226:8881 max_fails=1 fail_timeout=60s;
...
server dc-sit-226:8890 max_fails=1 fail_timeout=60s;
}
open_file_cache max=102400 inactive=20s;
client_header_buffer_size 4k;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
server {
listen 80;
server_name dc-sit-226;
location / {
proxy_pass http://load;
}
}
}
配置完成后记得重新加载配置:nginx -s reload
。可先测试请求是否正常,并查看nginx日志是否存在异常。
部分异常
- connect() to 192.168.9.226:8885 failed (13: Permission denied) while connecting to upstream, client: 192.168.64.243, server: dc-sit-226, request: “GET /value HTTP/1.1”, upstream: “http://192.168.9.226:8885/value”, host: “dc-sit-226”
设置网络访问配置:setsebool -P httpd_can_network_connect 1
- [alert] 12637#0: setrlimit(RLIMIT_NOFILE, 50000) failed (1: Operation not permitted)
很多人知道nginx配置了worker_rlimit_nofile这个参数,但是成功没有就不知道了,reload时如果error.log日志中有这个异常我们就需要先执行:setsebool -P httpd_setrlimit 1
,当然除了nginx需要配置文件限制,内核也不要进行修改。 - [alert] 12291#0: *55710 socket() failed (24: Too many open files) while connecting to upstream, client: 192.168.9.226, server: dc-sit-226, request: “GET /value HTTP/1.0”, upstream: “http://192.168.9.226:8882/value”, host: “dc-sit-226”
当我们worker_rlimit_nofile没有设置成功,超过1024文件访问会抛出这种异常,当然除了设置nginx的值,linux也需要做ulimit配置。下面我们会讲到系统配置。
系统配置
网上的实践配置每篇不是写的很全,或者适配自身系统,有时候还是要通过实际bug针对性的进行配置的添加、修改。这里你也更有机会了解其背后实际作用。
- /etc/sysctl.conf
# 打开文件句柄数量
fs.file-max = 655360
# 最大ip跟踪数
net.nf_conntrack_max = 655360
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为2分钟。
net.netfilter.nf_conntrack_tcp_timeout_established = 120
# 允许系统打开的端口范围,扩大端口数
net.ipv4.ip_local_port_range = 10000 65535
# 用来限制监听(LISTEN)队列最大数据包的数量,超过这个数量就会导致链接超时或者触发重传机制,
net.core.somaxconn = 65535
# 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.core.netdev_max_backlog = 262144
# 开启时就是同一个源IP来连接同一个目的端口的数据包时间戳必须是递增的,否则就丢弃
net.ipv4.tcp_timestamps = 0
# 是否启用timewait 快速回收。如果服务器身处NAT环境,tcp_timestamps为1,安全起见,要禁止
net.ipv4.tcp_tw_recycle = 1
# 开启重用。允许将TIME-WAIT sockets 重新用于新的TCP 连接。
net.ipv4.tcp_tw_reuse = 1
# timeout状态时间
net.ipv4.tcp_fin_timeout = 15
# 在TIME_WAIT数量等于该值时,不会有新的产生,
net.ipv4.tcp_max_tw_buckets = 262144
# 系统中最多有多少个TCP 套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。
net.ipv4.tcp_max_orphans = 262144
# 是指定所能接受SYN同步包的最大客户端数量。
net.ipv4.tcp_max_syn_backlog = 262144
# 为了打开对端的连接,内核需要发送一个SYN,以确认收到上一个 SYN连接请求包。也就是所谓三次握手中的第二次握手。
# 这个设置决定了内核放弃连接之前发送SYN+ACK 包的数量。
net.ipv4.tcp_synack_retries = 1
# 对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃,测试感觉两个更稳定
net.ipv4.tcp_syn_retries = 2
# 开启SYN Cookies,当出现SYN 等待队列溢出时,启用cookies 来处理,目的是为了防止syn flood攻击。合法用户的高负载应该调整tcp_max_syn_backlog、tcp_synack_retries属性,
net.ipv4.tcp_syncookies = 0
- /etc/security/limits.conf 末尾添加文件打开数量
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
通过sysctl -p
使得配置生效,可用通过ulimit -a查看file配置是否生效,临时设置也可用通过ulimit -u 65535
配置。
压测
- apache-ab
ab单条测试-c 不能超过1w。下面是测试发送60w请求,服务器每秒处理1.3w,90%响应在1.4s内。
# 通过脚本多线程压测,3个线程每个并发1w,实现3w Concurrency Level,总共24w请求
#!/bin/bash
for((i=1;i<=3;i++));
do
ab -k -n 80000 -c 10000 http://dc-sit-226/value > request.log${i} &
done
sleep 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
下面为执行成功结果,单个分析打印在request.log${i} 中,
我们抽选一个结果可能看到3w 并发的情况下,服务器90% 的响应时长在3.3s内。高并发以响应90%请求5s内返回指标来看,服务器的理论极限承载应该可以调整到4w左右RPS(requests per second)
- webbench
webbench据说可以直接实现3w并发、测试前两次数据量小还正常,后面就有问题了,通过命令netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
,才发现测试请求全部变CLOSE_WAIT占用资源。 - jmeter
因为服务器没有GUI界面,生成jmt文件又比较繁琐,所以没选择这个工具。大家可以根据自己情况选择压测工具。
测试部分问题
- apr_socket_connect(): Cannot assign requested address (99)
查看net.ipv4.ip_local_port_range、net.ipv4.tcp_tw_recycle、net.ipv4.tcp_tw_reuse、net.ipv4.tcp_timestamps 等系统配置
- connect() failed (110: Connection timed out) while connecting to upstream
要查看系统日志:dmesg
异常信息:nf_conntrack: table full, dropping packet.
解决方案:查看系统上述net.nf_conntrack_max
配置。
当然如果并发数达到一定数量、业务系统服务器也会超过承载极限,出现请求超时。 - apr_pollset_poll: The timeout specified has expired (70007)
主要是timeout连接超时了,可以加个-k参数,让连接KeepAlive,另外注意nginx的超时配置。 - apr_socket_connect(): 由于目标系统积极拒绝
业务系统服务器引起,可能是请求过载。 - no live upstreams while connecting to upstream, client: 192.168.9.226, server: dc-sit-226, request: “GET /value HTTP/1.0”, upstream: “http://load/value”, host: “dc-sit-226”
与第二个问题类似,这里的load 我配置的负载均衡服务名,所以nginx应该是端时间找不到后端可用server,就会报no live upstream。可以考虑增加业务服务器数据或者改进接口效率。
转载请注明:SuperIT » nginx服务器高并发配置详解(单机3w+并发)