答案是:用 curl 抓取 Nginx stub_status 的 Active connections 数值,结合短时变化率(如 t₂ > t₁×1.8 且 t₂ > t₀×3)判断突增,通过预设 limit_req 规则配合 map 动态切换限流强度,并用 flock 防重入、标记文件防重复触发。

怎么用 shell 脚本实时获取 Nginx 当前活跃连接数
关键不是看 netstat 或 ss 的所有连接,而是抓 Nginx 自身暴露的实时指标。前提是已启用 stub_status 模块(主流发行版默认编译进去了),并在 Nginx 配置里加了类似这段:
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}然后用 curl -s http://127.0.0.1/nginx_status 就能拿到三行文本,其中第一行形如 Active connections: 127。提取数字最稳的方式是:
curl -s http://127.0.0.1/nginx_status 2>/dev/null | grep 'Active connections' | awk '{print $3}'注意:如果返回空,先确认 curl 能通、stub_status 开启且没被防火墙/访问控制拦住;别用 netstat -ant | grep :80 | wc -l 替代——它统计的是 TCP 连接数,包含 TIME_WAIT、半开连接,和 Nginx 实际处理的请求量偏差很大。
怎么判断“暴增”而不是单纯高负载
固定阈值(比如 >1000 就限流)容易误触发:大促时连接数本来就会持续高位,但未必异常;而凌晨一次爬虫突袭可能从 50 瞬间飙到 800,这才是真暴增。推荐用「短时变化率」判断:
- 每 5 秒采一次,连续记录最近 3 个点(t₀, t₁, t₂)
- 当
t₂ > t₁ * 1.8 && t₂ > t₀ * 3时认为异常突增(系数可调) - 避免只比上一秒——网络抖动或单次慢请求就可能拉高瞬时值
脚本里可用一个临时文件存历史值,例如 /tmp/nginx_conn_history,每轮追加时间戳和数值,用 tail -n 3 读最新三条。别用内存变量——脚本重启就丢状态。
怎么通过 Nginx 原生方式启动限流(不重启服务)
不能改配置再 nginx -s reload,太重且有风险。应该用运行时生效的限流机制:
- 提前在
http块定义limit_req_zone $binary_remote_addr zone=burst:10m rate=10r/s - 在要保护的
server或location里加limit_req zone=burst burst=20 nodelay(此为默认策略) - 暴增时,用
sed动态注释/取消注释该行,再执行nginx -s reload——虽然 reload 快,但仍有毫秒级请求丢失风险 - 更稳妥的做法:预设两套
limit_req规则(正常版 + 严控版),用map指令绑定开关变量,再用curl向一个内部location发请求来切换变量值(需配合ngx_http_map_module和自定义 upstream)
简单场景直接用第一种;生产环境建议第二种,reload 是最后手段。
怎么防止脚本自身被反复触发或漏判
监控脚本跑成死循环很容易出问题:
- 用
flock -n /tmp/nginx_monitor.lock包裹主逻辑,避免多个实例并发执行 - 检测到暴增后,写一个标记文件(如
/tmp/nginx_rate_limited)并设 5 分钟过期,期间不再重复限流 - 恢复判断不能只等连接数回落——得加「稳定观察期」:连续 3 次采样都低于阈值才解除限流
- 所有 curl、awk、sed 操作必须加超时和错误检查,例如
curl -m 2 -f,否则卡死会导致整个监控停摆
真正的难点不在取数或限流,而在状态同步和边界控制:Nginx 不告诉你当前是否已在限流,脚本得自己记、自己验、自己清理残留。这点最容易被忽略。


















