Nginx连接数监控与性能调优实战指南

发布时间:2026/8/6 11:18:01
Nginx连接数监控与性能调优实战指南 1. 从一次线上告警说起为什么连接数监控如此重要那天下午我正在处理一个需求突然钉钉群里连续弹出了几条告警信息“服务器TCP连接数超过阈值”。点开监控图表一看其中一台Nginx服务器的连接数曲线像坐了火箭一样从平时的几百个瞬间飙到了接近两万并且还在持续增长。整个团队的神经立刻紧绷了起来因为这通常意味着两种可能要么是迎来了意想不到的业务洪峰要么就是服务出现了异常比如连接泄漏、慢请求堆积甚至是遭受了攻击。我第一时间登录服务器习惯性地想用netstat或ss命令看一眼概况但转念一想作为流量入口的Nginx它自己统计的连接数才是最直接、最准确的“第一现场”数据。Nginx的连接数不仅仅是一个数字它背后是活跃连接Active Connections、读取请求头Reading、处理请求Writing和保持连接Waiting这四个状态的动态组合。理解这几个数字就像医生看化验单能快速判断出系统是“健康繁忙”还是“病态阻塞”。比如如果Writing状态连接数异常高可能意味着后端应用响应缓慢如果Waiting连接数占比过高则可能跟keepalive_timeout配置有关。掌握查看Nginx连接数的方法是每一个运维、开发和架构师的必备技能。这不仅是事后排查问题的“手术刀”更是事前发现隐患、进行容量规划和性能调优的“听诊器”。今天我就结合那次真实的排查经历和日常实践为你系统梳理几种核心的查看方法从最简单的状态页到深入内核的统计让你不仅能看懂数字更能理解数字背后的故事。2. 核心方法一活用Nginx内置状态页stub_status这是最经典、最直接也是信息最丰富的方法。它不需要额外安装第三方模块但需要在Nginx配置中显式开启一个用于暴露状态信息的接口。2.1 配置启用stub_status模块首先你需要确认编译安装的Nginx包含了--with-http_stub_status_module模块。可以通过运行nginx -V命令来查看编译参数。绝大多数主流发行版的预编译包都会包含此模块。启用它的配置非常简单。在你的Nginx配置文件通常是nginx.conf或sites-available/下的某个配置文件中在一个合适的server块内添加一个locationserver { listen 80; server_name status.yourdomain.com; # 建议使用独立的域名或IP端口 location /nginx_status { stub_status on; access_log off; # 状态页访问通常不需要记录日志 allow 192.168.1.0/24; # 非常重要限制可访问的IP段切勿公开暴露 allow 127.0.0.1; deny all; # 如果部署在云上可能需要结合安全组和该配置共同限制 } }注意安全是重中之重。stub_status接口会暴露服务器的连接信息必须通过allow/deny指令或防火墙策略将其访问权限严格限制在内网或管理IP范围内绝对不允许公网无限制访问。配置完成后执行nginx -t测试配置无误然后通过nginx -s reload平滑重载配置。2.2 解读状态页的输出信息访问你配置的地址如http://status.yourdomain.com/nginx_status你会看到类似下面的纯文本输出Active connections: 291 server accepts handled requests 16630948 16630948 31070465 Reading: 6 Writing: 3 Waiting: 282我们来逐行拆解这些数字的含义Active connections当前所有活跃的客户端连接总数。这是最宏观的指标。accepts自Nginx启动以来已经接受的客户端连接总数量。handled自Nginx启动以来已经处理完成的连接总数量。正常情况下这个数字应该和accepts非常接近。如果两者差距持续变大说明有些连接被Nginx接受后因为某种原因如系统资源不足未能正常处理是潜在的风险信号。requests自Nginx启动以来总共处理过的客户端请求总数量。由于HTTP Keep-Alive特性一个连接上可以发送多个请求所以这个数通常远大于handled。Reading当前正在读取客户端请求头或请求体的连接数量。如果这个值长时间较高可能意味着客户端网络较慢或正在上传大文件。Writing当前正在向客户端发送响应数据的连接数量。这是排查后端性能问题的关键指标。如果Writing数持续很高通常表明后端应用处理请求耗时过长Nginx在“等待”后端的同时需要保持与客户端的连接以便回传数据。Waiting当前处于空闲状态正在等待下一次请求的持久连接Keep-Alive数量。这部分连接不消耗什么CPU资源但会占用文件描述符。其数量主要受keepalive_timeout和客户端行为影响。实战心得在一次大促前的压测中我们发现Writing连接数随着压测流量上升而线性增长但Reading和Waiting变化不大。这立刻将怀疑指向了后端应用服务。通过进一步追踪发现是某个数据库查询未用索引导致单个请求处理时间从50ms恶化到2秒大量请求堆积在Nginx的Writing状态。修复SQL后Writing连接数迅速下降系统吞吐量得到本质提升。所以stub_status不仅是监控工具更是性能瓶颈定位的“指南针”。3. 核心方法二使用系统级网络工具netstat/ss当你想从操作系统层面以更全局的视角查看所有与Nginx进程相关的网络连接时netstat和它的现代替代品ss就派上用场了。这对于分析连接来源、目标端口、状态分布特别有用。3.1 使用ss命令推荐ss命令比传统的netstat更快信息也更详细。它是现在排查网络问题的首选工具。查看所有与Nginx工作进程相关的连接ss -tlnp | grep nginx-t仅显示TCP连接。-l仅显示监听Listening的套接字。-n以数字形式显示地址和端口不进行域名解析更快。-p显示占用该套接字的进程信息。grep nginx过滤出Nginx进程。这条命令的输出能让你看到Nginx都在哪些端口上监听如80, 443以及每个监听套接字对应的进程PID。查看Nginx建立的所有活动连接包括非监听状态ss -tan | grep ESTAB | grep -E ‘:80|:443’ | wc -l-a显示所有套接字包括监听和非监听。-tTCP。-n数字格式。grep ESTAB过滤出已建立ESTABLISHED的连接。grep -E ‘:80|:443’过滤出目标或源端口是80或443的连接假设你的Nginx服务在这两个端口。wc -l统计行数即连接数。这个命令的结果理论上应该与stub_status中的Active connections接近但它包含了所有TCP层连接而Nginx自身统计的Active connections是应用层HTTP的活动连接在连接刚建立或处于其他阶段时两者可能会有细微差别。3.2 深入分析连接状态分布ss更强大的地方在于可以详细分析连接的状态。TCP连接有多种状态对于Nginx这样的服务器我们最关心的是ESTABLISHED已建立、TIME_WAIT、CLOSE_WAIT等。ss -tan state established | grep -E ‘:80|:443’ | wc -l ss -tan state time-wait | grep -E ‘:80|:443’ | wc -l ss -tan state close-wait | grep -E ‘:80|:443’ | wc -lTIME_WAIT过多这是TCP协议四次挥手后主动关闭方进入的状态会持续2MSL通常为60秒。如果短时间内有大量短连接会产生大量TIME_WAIT。可以通过调整内核参数net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle注意tcp_tw_recycle在NAT环境下可能有问题Linux 4.12已移除或优化应用使用长连接来缓解。CLOSE_WAIT过多这通常意味着你的服务器Nginx或其后端没有主动关闭连接可能是代码bug导致连接泄漏。这是一个非常危险的信号需要立即排查。踩坑记录有一次告警显示某台服务器连接数缓慢增长ss查看发现CLOSE_WAIT状态的连接有上千个。通过lsof -p nginx_worker_pid发现大量连接到同一个后端服务的socket。最终定位到是后端某个服务实例因为Full GC卡死无法发送FIN包来关闭连接导致Nginx这边积累了大量的CLOSE_WAIT。重启问题后端实例后CLOSE_WAIT连接被操作系统回收问题解决。所以定期用ss查看连接状态分布是预防连接泄漏的重要手段。4. 核心方法三解析Nginx日志中的连接信息Nginx的访问日志access log和错误日志error log是宝藏里面蕴含着每个连接的详细故事。通过分析日志我们可以进行更精细化的统计和回溯。4.1 在日志格式中嵌入连接标识Nginx默认的日志格式可能不包含连接级别的唯一标识。为了更好的追踪我们可以自定义日志格式加入$connection变量它表示连接序列号或者使用$connection_requests变量表示该连接上已经处理过的请求数。http { log_format detailed ‘$remote_addr - $remote_user [$time_local] “$request” ‘ ‘$status $body_bytes_sent “$http_referer” ‘ ‘“$http_user_agent” “$http_x_forwarded_for” ‘ ‘“$connection” “$connection_requests”’; access_log /var/log/nginx/access.log detailed; }配置后日志中会多出两个字段例如“1256” “3”表示这个请求发生在第1256号连接上并且是该连接上的第3个请求。这对于分析Keep-Alive的使用情况非常有用。4.2 使用命令行工具进行实时统计与分析有了日志我们就可以利用强大的Linux文本处理工具进行即时分析。实时统计每秒的请求数QPStail -f /var/log/nginx/access.log | awk ‘{print $4}’ | cut -d[ -f2 | uniq -c这个命令会动态输出每秒的请求数量是观察流量波动的利器。统计当前最活跃的客户端IP用于排查疑似攻击tail -n 10000 /var/log/nginx/access.log | awk ‘{print $1}’ | sort | uniq -c | sort -nr | head -20这个命令分析最近1万条日志统计出访问最频繁的前20个IP地址。查找响应时间过长的请求用于排查慢请求假设你的日志格式包含了$request_time变量表示请求处理总时间。awk ‘($(NF) 5){print $0}’ /var/log/nginx/access.log | head -20这个命令会找出处理时间超过5秒的请求日志并打印前20条。$(NF)代表最后一列这里假设$request_time是最后一列。实战技巧线上曾遇到间歇性的接口超时告警。通过stub_status发现Writing连接数在告警时刻飙升。我们立刻去翻查对应时间段的错误日志error_log发现了大量的upstream timed out记录。同时分析同一时间段的访问日志用上述命令筛选出响应时间大于10秒的请求发现它们都指向同一个上游服务接口。结合两者迅速将问题范围缩小到特定的后端服务后续的排查就有的放矢了。日志不是事后才看的“病历本”而是实时诊断的“CT机”。5. 核心方法四利用第三方监控模块与API对于生产环境我们往往需要将Nginx的连接数指标集成到统一的监控告警平台如Prometheus、Zabbix中实现自动化、可视化的监控。这就需要用到功能更强大的第三方模块。5.1 Nginx Plus 商业版状态APINginx Plus提供了功能丰富的RESTful JSON API可以获取远比stub_status详细的信息包括连接数、请求率、上游服务器健康状态等并且天然适合被监控系统抓取。当然这是付费功能。5.2 开源方案nginx-module-vts 与 nginx-lua-prometheus对于开源Nginx社区有优秀的替代方案。nginx-module-vts (nginx virtual host traffic status module)这是一个非常流行的第三方模块它提供了按虚拟主机server、按上游upstream分组统计的详细数据包括连接数、请求数、流量、响应码分布等并以JSON格式通过HTTP接口暴露。编译安装此模块后配置类似stub_status你能获得一个信息量巨大的监控面板。Prometheus可以通过nginx-vts-exporter来抓取这些指标。使用nginx-lua-prometheus自行暴露指标这是一个更灵活的方案。它利用Nginx的Lua模块需要安装ngx_http_lua_module允许你在Nginx配置中直接使用Lua脚本定义和更新Prometheus格式的指标。http { lua_shared_dict prometheus_metrics 10M; init_worker_by_lua_block { prometheus require(“prometheus”).init(“prometheus_metrics”) metric_connections prometheus:gauge(“nginx_connections”, “Number of current connections”, {“state”}) } log_by_lua_block { -- 这里可以从ngx.var.connections_*等变量中获取值更新metric_connections -- 但注意获取全局连接数需要在单独的定时任务或特定location中log_by_lua阶段可能不准确 } server { location /metrics { content_by_lua_block { metric_connections:set(ngx.var.connections_active, {“active”}) metric_connections:set(ngx.var.connections_reading, {“reading”}) metric_connections:set(ngx.var.connections_writing, {“writing”}) metric_connections:set(ngx.var.connections_waiting, {“waiting”}) prometheus:collect() } } } }这种方式高度定制化你可以暴露任何你关心的指标并与现有的Prometheus Grafana监控栈无缝集成。5.3 系统级监控集成除了Nginx自身的指标系统级的资源监控也至关重要。连接数最终会消耗系统资源主要是文件描述符File Descriptor。监控进程打开文件数使用ls -l /proc/nginx_worker_pid/fd | wc -l可以查看单个Nginx工作进程当前打开的文件描述符数量。确保其远低于系统或进程级别的限制通过ulimit -n查看。监控系统总连接数使用cat /proc/net/sockstat或ss -s可以查看系统级别的TCP socket统计信息包括总使用量。这是防范连接耗尽导致系统瘫痪的最后一道防线。配置建议在生产环境中我通常会采用组合方案nginx-module-vts提供详细的Nginx内部指标通过Prometheus抓取node_exporter抓取系统级指标包括从/proc读取的TCP连接统计再配置一套基础的stub_status作为备用和快速命令行检查。这样无论是在Grafana仪表盘上纵观全局还是在服务器上快速执行命令诊断都能得心应手。6. 连接数异常场景的排查思路与实战案例掌握了查看方法最终是为了解决问题。当连接数出现异常时如何快速定位根因下面分享一个典型的排查流程和案例。6.1 系统性排查流程图面对连接数飙升一个清晰的排查思路能节省大量时间确认现象通过stub_status或监控图表确认连接数增长的类型是Active总体增长还是Writing/Waiting某一项激增。定位源头如果是Writing激增重点排查后端应用性能数据库、缓存、RPC调用。如果是Reading激增重点排查客户端网络或上传行为。如果是Waiting激增检查keepalive_timeout配置和客户端行为。如果Active总体增长使用ss或netstat结合tcpdump分析连接来源IP和端口判断是正常业务流量还是异常攻击。深入分析查看Nginx错误日志error_log寻找报错如connect() failed,upstream timed out分析访问日志access_log寻找慢请求、高频IP或特定URL。资源检查检查系统资源CPU、内存、磁盘IO特别是文件描述符使用量是否接近上限。联动下游如果指向后端问题使用相应工具如Arthas for Java, pprof for Go深入分析应用内部状态。6.2 实战案例TIME_WAIT连接数过多导致端口耗尽现象某活动页面上线后监控发现服务器连接数缓慢上升最终导致新用户无法访问错误日志中出现connect() failed (99: Cannot assign requested address)。排查过程stub_status显示Active connections正常但ss -s显示TIME-WAIT数量极高接近3万。ss -tan state time-wait | grep :443 | wc -l确认大部分TIME_WAIT确实来自Nginx的443端口。分析业务该活动页面由大量前端AJAX短请求构成且未启用HTTP Keep-Alive或配置超时过短。检查内核参数net.ipv4.ip_local_port_range范围是32768 60999可用端口约2.8万个。Nginx作为客户端向后端服务请求时每个短连接都会消耗一个本地临时端口并在关闭后进入TIME_WAIT状态持续60秒。当瞬时并发高时可用端口很快被耗尽。解决方案短期应急扩大本地端口范围sysctl -w net.ipv4.ip_local_port_range“1024 65000”并启用端口快速复用sysctl -w net.ipv4.tcp_tw_reuse1。根本解决优化应用启用并合理配置Nginx与后端服务之间的HTTP Keep-Alive连接将多个请求复用在一个TCP连接上从根本上减少短连接数量。同时调整Nginx与后端服务的keepalive配置。upstream backend { server 10.0.0.1:8080; keepalive 32; # 每个Worker进程与上游服务器保持的最大空闲连接数 } server { location /api/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection “”; # 启用HTTP/1.1长连接 } }这个案例告诉我们连接数问题有时不是Nginx本身的问题而是其作为客户端时的行为与系统配置共同作用的结果。理解整个TCP/IP协议栈和Nginx在其中的角色是进行深度排查的基础。7. 性能调优与配置建议监控和排查的终极目的是为了优化和预防。以下是一些与连接数相关的关键配置项和调优建议它们直接影响着Nginx的连接处理能力和资源消耗。7.1 关键配置参数解析worker_connections每个Nginx工作进程可以同时处理的最大连接数包括客户端连接和到上游服务器的连接。这个值直接限制了Nginx的并发处理能力。设置原则是worker_connections * worker_processes应该大于系统最大文件描述符限制并且能满足业务峰值并发需求。通常设置为65535或10240。events { worker_connections 10240; }keepalive_timeout客户端连接在关闭前服务器端将保持打开状态的最长时间。设置太短会增加连接建立的开销设置太长会占用过多的Waiting连接和文件描述符。需要根据业务特性权衡。对于API服务器可以设置短一些如10-30秒对于包含大量静态资源、需要多请求加载的网页可以设置长一些如60秒。http { keepalive_timeout 30s; # 客户端连接保持时间 keepalive_requests 100; # 一个连接上最多服务的请求数达到后连接被关闭 }multi_accept在events块中配置。如果设置为on每个工作进程可以一次性接受所有的新连接。在高并发场景下开启可能有助于性能但可能增加负载不均衡的风险。events { multi_accept on; }use在events块中指定事件模型。在Linux 2.6系统上epoll是最高效的选择。events { use epoll; }7.2 系统级参数调优Nginx的性能也受限于操作系统。以下是一些关键的内核参数建议在/etc/sysctl.conf中修改后执行sysctl -p生效net.core.somaxconn定义了系统中每一个端口最大的监听队列长度。Nginx中listen指令的backlog参数受此值限制。对于高并发服务建议增大。net.core.somaxconn 65535在Nginx配置中对应listen 80 backlog65535;net.ipv4.tcp_max_syn_backlog记录尚未收到客户端确认信息的连接请求的最大值。用于防御SYN Flood攻击也应适当调高。net.ipv4.tcp_max_syn_backlog 65535net.ipv4.tcp_tw_reuse / net.ipv4.tcp_tw_recycle关于TIME_WAIT的回收重用。tcp_tw_reuse相对安全允许将TIME_WAIT连接重新用于新的出站连接在客户端角色如Nginx代理请求到上游时很有用。tcp_tw_recycle在NAT网络下有问题已不推荐使用。文件描述符限制确保系统级别/etc/security/limits.conf和Nginx进程级别worker_rlimit_nofile的文件描述符限制足够大。user www-data; worker_processes auto; worker_rlimit_nofile 65535; # 每个worker进程能打开的文件数上限个人经验调优没有银弹。最好的做法是在模拟生产环境的压测中进行。使用工具如wrk,jmeter逐步增加并发连接数同时观察stub_status的各项指标、系统负载和错误日志。你会找到适合你业务场景的最佳配置组合。记住一个原则先理解后调整。盲目复制网上的“最优配置”可能会引入新的问题。