1. 优化策略
1.1. 软件方面
- 增加CPU利用率
- 增加内存利用率
- 加强I/O优化
-
1.2. 硬件方面
使用更高性能的网卡,如千兆网卡换万兆网卡
- 使用更好的CPU,增加CPU性能
- 使用更快更大的内存
- 使用更好的固态硬盘
-
2. CPU部分
减少非Nginx进程对CPU的消耗
- 设置Nginx的worker进程数量等于CPU逻辑核心数
- 将Nginx的worker进程和CPU核心进行绑定,降低上下文切换,提高缓存命中率
- 适当提高Nginx进程的优先级
- 大流量场景中,当软中断占比较大时,使用软中断负载均衡,平衡CPU压力
worker_processes auto ; ## auto表示worker进程数和CPU核心数一致
worker_cpu_affinity auto ; ## auto表示worker进程进程自动进行cpu绑定
worker_priority 0 ; ## 0是默认优先级
3. 文件句柄数
3.1. 系统配置
# 根据实际场景针对用户进行调整, 用户重新登录后生效
[root@localhost ~]# cat /etc/security/limits.conf
* soft nproc 65535
* hard nproc 65535
* soft nofile 655350
* hard nofile 655350
* soft core unlimited
* hard core unlimited
# 根据实际场景针对服务调整,此处修改的是默认系统配置
[root@localhost ~]# vim /etc/systemd/system.conf
[Manager]
DefaultLimitCORE=infinity
DefaultLimitNOFILE=655350:655350
DefaultLimitNPROC=65535:65535
# 重载sysctem.conf配置,然后再重启服务
[root@localhost ~]# systemctl daemon-reexec
3.2. nginx进程限制
worker_rlimit_nofile 655350 ; ## 限制所有工作进程能打开的最大文件数,一般不用设置
4. TCP连接
4.1. 内核参数配置
net.core.netdev_max_backlog = 65535
# 当内存处理数据包速度低于网卡接收数据包速率时,数据包会存放在缓冲区。
# 此参数设置网卡缓冲区数据包队列大小,默认1000。可以适当设置大一些,如65535。
net.ipv4.tcp_timestamps = 1
# 在数据包中加上时间戳,针对带宽特别高的场景下,数据包中的sequence会出现重复,从而导致数据包混乱。
# 一般万兆网卡设备建议开启,大流量场景下容易出现sequence重复
net.ipv4.tcp_syn_retries = 2
# 初次握手时,未收到服务端响应情况下,重试syn握手包次数。
net.ipv4.tcp_synack_retries = 2
# 二次握手时,未收到客户端响应时,服务端重试发送syn+ack包数量。建议调小一些,降低syn攻击的影响。
net.ipv4.tcp_max_syn_backlog = 655350
# 设置半连接队列大小,在收到syn攻击时这个值要尽可能大一些
net.core.somaxconn = 655350
# 系统单个socket全连接大小,适当调高用于应对高并发场景。Centos 7默认128。
net.ipv4.tcp_fin_timeout=20
# 断开fin_wait_2的超时时间
net.ipv4.tcp_tw_reuse = 1
# 启用time_wait重新利用。
net.ipv4.tcp_tw_recycle = 0
# 在NAT环境中,当大量客户端穿过NAT网络访问Nginx时,如果开启这个参数会导致大量数据包异常。
net.ipv4.tcp_max_tw_buckets = 65535
# timewait 的数量限制,如果想让timewait连接减少,适当降低这个数值即可。
net.ipv4.ip_local_port_range = 10240 60999
# 允许系统打开的端口限制,根据实际情况适当调整范围,一般对服务端来说影响不是很大
4.2. Nginx配置
worker_connections 65535 ; ## 单个worker进程能创建的连接大小,包括与客户端连接、代理连接。
use epoll ; ## 使用epoll提高高并发下Nginx处理能力
listen 8080 backlog=655350 ; ## Nginx的全连接队列大小,默认511
tcp_nopush on ; ## 大量小数据包场景中,积累多个数据表一起发送,提高带宽利用率
keepalive_timeout 70 60 ; ## 启用长连接,让能识别header_timeout的客户端主动断开连接,可用减少timewait数量
keepalive_requests 200 ; ## 提高单个长连接发送的请求数,减少长连接的重新建立,一般场景下不需要配置
5. Nginx的其它配置
5.1. 使用客户端缓存
map $sent_http_content_type $expires {
default off;
~image/ 3d ;
~vedio/ 7d ;
text/plain 24h;
text/css 24h;
text/html 24h;
application/javascript 24h;
application/pdf 30d;
application/zip 30d;
}
expires $expires ;
## 一般根据实际场景在对不同的文件类型设置缓存时间,在静态资源服务器中非常管用
## map是一种很好的实现方式,也可以根据不同的location来匹配
5.2. 使用gzip压缩
gzip on ;
gzip_comp_level 2 ; ## 根据实际情况考虑,CPU空闲资源多可用提高压缩级别
gzip_disable msie6 ; ## IE 6启用压缩
gzip_min_length 1024 ; ## 最小被压缩文件长度
gzip_types text/css text/plain application/javascript application/xml image/gif image/jpeg image/png ;
## 在部分大文件下载场景中,可用将预压缩文件直接发送给客户端,在包含反向代理中需要考虑再哪个机器上进行压缩。
gzip_static on ;
5.3. 磁盘I/O
Nginx在socket上有epoll事件驱动模型,可用非阻塞的处理socket连接,但针对普通文件而言,磁盘I/O在所难免,尤其是在静态资源服务器和缓存服务器中。
5.3.1. Nginx配置
open_file_cache max=65535 inactive=30 ; ## 缓存的文件数和过期时间
open_file_cache_min_uses 2 ; ## 引用次数超过2次就缓存
open_file_cache_valid 60 ; ## 检查缓存有效性的时间间隔
#####
sendfile on ; ## 使用sendfile,可用将文件系统缓存中的文件直接发送到socket缓冲区
sendfile_max_chunk 1024k ; ## 限制单次发送的文件量,避免大文件发送时阻塞进程
directio 10m ; ## 针对大文件使用直接I/O,在内存不足的情况用途很大
aio threads ; ## 当directio效果不明显时,可用启用aio和多线程任务卸载功能
5.3.2. 文件系统缓存
在不跳过文件系统缓存的情况下,系统内存中的cache会缓存大量的文件页和目录项,这种场景下配合sendfile也能降低磁盘I/O操作。
5.4. 请求和响应配置
5.4.1. 请求配置
client_header_buffer_size 1k ; ## 请求头的缓冲区大小,一般无需调整。
large_client_header_buffers 4 8k ; ## 超大请求头,一般无需调整。注意414和400返回码可能是请求头字段过大
client_header_timeout 60s ; ## 请求头读取超时时间,超时返回408
client_body_buffer_size 8k ; ## 默认是两个内存页大小(4k*2)
client_max_body_size 1m ; ## 最大请求体大小,在上传服务器上,这个值会设置的非常大
client_body_temp_path path 1 2 ; ## 对应较大请求体临时存放位置,一般用于应对上传服务器
client_body_timeout 60s ; ## 两次读取请求体之间的最大时间间隔,超时返回408
5.4.2. 代理配置
proxy_buffering on ; ## 开启对后端服务器响应的缓存,默认开启
proxy_buffer_size 4k ; ## 缓存后端服务器响应的第一部分内容,一般就是响应头,此设置一般不需要调整。
proxy_buffers 8 4k ; ## 单个连接读取后端服务器响应的缓冲区大小,超出则放入临时文件中。大文件比较大的情况下,可增加缓冲区大小
proxy_max_temp_file_size 1024m ; ## 存储响应的临时文件总大小
proxy_temp_file_write_size 8k ; ## 单个请求能写入临时文件中的大小
proxy_busy_buffers_size 8k ; ## 当未发送的响应超过该值,则发送给响应给客户端,直到未发送的响应小于该值
proxy_connect_timeout 30s ; ## 与后端服务器建立连接的超时时间
proxy_read_timeout 30s ; ## 同一个请求,从后端服务器两次连续读取响应最大间隔时间
proxy_send_timeout 30s ; ## 同一个请求,两次成功发送请求给后端服务器的间隔时间
#### 以下在upstream模块配置
keepalive 32 ; ## 每个工作进程与后端服务器保持的空闲连接数,不应该设置太大,避免影响后端服务器处理新的连接
keepalive_timeout 60s ; ## 与后端服务器最长空闲连接时间
keepalive_requests 100 ; ## 与后端服务器之间单个连接的完成的最大请求次数
### 以下针对健康检查配置,在upstream模块配置
check interval=3000 fall=2 rise=3 timeout=1000 default_down=true type=http ;
check_http_send "HEAD /check.html HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: keep-alive\r\n\r\n" ;
check_http_expect_alive http_2xx http_3xx ;
## interval: 检查间隔(ms),此设置是上次检查失败或服务器异常情况下,下次检查的间隔。如果服务器正常则间隔为1min
## fall: 连续失败两次认为异常; rise: 连续成功两次认为正常; timeout: 请求超时时间(ms);
## default_down: 后端服务器初始状态,设置为true,表示后端服务器初始是异常的,通过检查后才认为正常; type: 检查方式
## check_http_send: http检查的方式,一般以head方式检查
## check_http_expect_alive: 认为后端服务器返回的正常状态码
## 这种健康检查方式在版本升级时非常有用,升级前移除check.html,升级完毕后恢复check.html
5.4.3. 响应配置
send_timeout 60 ; ## 一个响应中,两次成功发送响应的最大时间间隔
limit_rate 4096k ; ## 针对单个响应每秒中的限速,在大文件下载场景中比较有用
5.4.4. 流控
为了避免出现浪涌和攻击,可用使用流控方式来限制连接和请求。
## 针对连接的限制,不同http协议版本,同一个连接能完成的请求数量不一样,超出返回503
limit_conn_zone $binary_remote_addr zone=addr:10m ; ## 1m大约能存储1.6万的地址池
limit_conn addr 100 ; ## 限制单个客户端最大活跃连接数
## 针对请求的限制,超出返回503
limit_req_zone $binary_remote_addr zone=limit_addr:10m rate=100r/s ; ## 系统将1s切成时间片来计算
limit_req zone=limit_addr burst=100 nodelay; ## 延迟响应的请求数
5.4.5. HTTPS 服务器配置
SSL会话一般建议尽可能早的卸载掉,之后和后端服务器直接通过HTTP进行交互。SSL会话的成本较高,一个SSL会话尽可能完成更多的请求。
keepalive_timeout 100s ; ## 长链接维持的时间
keepalive_requests 200 ; ## 单个连接完成请求次数
ssl_session_cache shared:SSL:30m ; ## 所有worker共享的会话缓存,1m大约能存4000会话
ssl_session_timeout 10m ; ## SSL会话维持时间
5.4.6. 其它
server_tokens off ; ## 不显示nginx版本号
## DNS 服务器配置
resolver 223.5.5.5 ; ## dns服务器
resolver_timeout 30s ; ## DNS解析超时时间
## 日志配置,合理配置日志切割脚本
error_log logs/error.log error ; ## 适当提高error日志级别,减少磁盘IO
log_format access '$time_local|$http_x_real_ip|$http_x_forwarded_for|$remote_addr|$upstream_addr|'
'$request_method|$server_protocol|$host|$request_uri|$http_referer|$http_user_agent|'
'$proxy_host|$status' ; ## 合理设置日志格式,时间格式可以修改源码
access_log logs/access.log access buffer=128k flush=5s ; ## 当日志量较大时,使用日志缓冲区
access_log off ; ## 针对部分请求,如健康检查、部分静态资源(css,js等)选择不记录日志