最近在优化一个电商网站的服务器性能,主要瓶颈集中在 Nginx 的并发连接数上。在第十八周周报中,详细记录了整个优化过程,包括问题重现、原理剖析、解决方案以及一些实战避坑经验。这次优化的目标是提升服务器的吞吐量,降低响应延迟,最终提升用户体验。
问题场景重现:突发流量导致 502 错误
电商大促期间,服务器突然涌入大量流量,导致 Nginx 频繁出现 502 Bad Gateway 错误。查看 Nginx 错误日志 (/var/log/nginx/error.log),发现大量 upstream 连接超时的错误:
2024/10/27 10:30:00 [error] 30#0: *100 upstream timed out (110: Connection timed out) while connecting to upstream, client: 192.168.1.1, server: example.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "example.com"
使用 netstat -an | grep 80 | wc -l 命令查看 TCP 连接数,发现大量连接处于 TIME_WAIT 状态,表明服务器无法及时释放连接,导致新的连接无法建立。
底层原理深度剖析:TCP 连接与 Nginx 工作模型
要解决这个问题,需要理解 TCP 连接的生命周期以及 Nginx 的工作模型。
TCP 连接建立需要三次握手,关闭需要四次挥手。TIME_WAIT 状态是 TCP 四次挥手过程中,主动关闭连接的一方在发送 ACK 报文后进入的状态。这个状态是为了保证被动关闭方能够收到 ACK 报文,避免数据丢失。TIME_WAIT 状态会占用端口资源,如果大量连接处于 TIME_WAIT 状态,会导致新的连接无法建立。
Nginx 是一个事件驱动的 Web 服务器,采用多进程或多线程模型。每个 worker 进程负责处理客户端的请求。当客户端请求到达时,Nginx 会将请求分配给一个 worker 进程处理。如果 worker 进程处理请求的时间过长,或者 worker 进程的数量不足,会导致请求排队,最终导致 502 错误。
另外,也要注意 Nginx 的 worker_connections 配置,这个参数限制了每个 worker 进程可以处理的最大并发连接数。如果 worker_connections 设置的太小,会导致 Nginx 无法处理大量的并发请求。
代码/配置解决方案:Nginx 调优与 Linux 内核参数优化
针对上述问题,我们采取了以下解决方案:
- Nginx 配置优化:
worker_processes auto; # 根据 CPU 核心数自动设置 worker 进程数
worker_connections 1024; # 增加每个 worker 进程可以处理的最大并发连接数
http {
keepalive_timeout 60; # 设置 keep-alive 连接的超时时间
client_max_body_size 10m; # 允许客户端上传的最大 body 大小
upstream backend {
server 127.0.0.1:8080; # 后端服务器地址
keepalive 32; # 设置与后端服务器的 keep-alive 连接数
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 5s; # 设置连接后端服务器的超时时间
proxy_send_timeout 60s; # 设置发送给后端服务器的超时时间
proxy_read_timeout 60s; # 设置从后端服务器读取数据的超时时间
}
}
}
- Linux 内核参数优化:
修改 /etc/sysctl.conf 文件,并执行 sysctl -p 命令使配置生效:
net.ipv4.tcp_syncookies = 1 # 开启 SYN Cookies,防止 SYN Flood 攻击
net.ipv4.tcp_tw_reuse = 1 # 允许将 TIME_WAIT 状态的连接用于新的 TCP 连接
net.ipv4.tcp_tw_recycle = 1 # 快速回收 TIME_WAIT 状态的连接(已废弃,不建议使用)
net.ipv4.tcp_fin_timeout = 30 # 缩短 FIN_WAIT_2 状态的超时时间
net.ipv4.tcp_keepalive_time = 1200 # 设置 TCP keep-alive 的探测时间
net.ipv4.ip_local_port_range = 1024 65535 # 增加可用端口范围
net.core.somaxconn = 65535 # 增加 listen backlog 的大小
net.core.wmem_default = 8388608 # 增加 TCP 写缓冲区大小
net.core.rmem_default = 8388608 # 增加 TCP 读缓冲区大小
net.core.wmem_max = 16777216 # 增加 TCP 写缓冲区最大值
net.core.rmem_max = 16777216 # 增加 TCP 读缓冲区最大值
- 优化后端服务:
检查后端服务的性能瓶颈,例如数据库查询优化、缓存使用等。可以使用 APM 工具(例如 SkyWalking、CAT)来监控后端服务的性能。
实战避坑经验总结
- 监控先行:在进行性能优化之前,一定要先进行监控,了解服务器的性能瓶颈在哪里。可以使用 Prometheus + Grafana 搭建监控系统。
- 逐步调整:不要一次性修改大量的配置,应该逐步调整,并观察服务器的性能变化。
- 回滚策略:在修改配置之前,一定要备份配置文件,以便出现问题时可以快速回滚。
- 压力测试:在上线之前,一定要进行压力测试,模拟大流量场景,验证优化效果。
- 宝塔面板的坑:如果使用宝塔面板,要注意宝塔面板可能会覆盖你手动修改的 Nginx 配置文件,所以每次修改后都要检查是否生效。
通过以上的优化措施,成功解决了第十八周周报中遇到的 Nginx 高并发瓶颈问题,服务器的吞吐量得到了显著提升,响应延迟也得到了有效降低。希望这些经验能够帮助到大家。
冠军资讯
键盘上的咸鱼