先讲一个我实际遇到过的场景。
某天业务方反馈“接口变慢了”,我们在 Zabbix 上看 Nginx 所在主机,CPU 不高、内存不高、连接数也不高,主机可用性一直是绿色。但真实情况是,后端 upstream 里的一个节点已经挂了,Nginx 进程还活着,却在反复等待这个不可达节点超时。那台机器的监控图上,你几乎看不到任何异常,因为当时我们只监控了“进程存活”和“系统资源”,没有采集任何 Nginx 自身的状态数据。
这件事过后,我最大的体会是:监控 Nginx 的核心从来不是“agent 装没装上”,而是你有没有把 Nginx 的状态数据可靠地采出来,并且让它成为能辅助判断的依据。agent 只是通道,真正有价值的是通道里跑的指标,以及围绕这些指标建立的阈值、图形和告警。
这篇文章我从实际落地角度,把 Zabbix 监控 Nginx 时涉及的安装、配置、agent 接线、模板对接、排障链路和长期使用建议完整梳理一遍。你会发现,单次跑通不难,难的是让这套监控真正稳定可用。
1. 监控 Nginx 不等于 agent 跑起来,先定义你要采的四个维度
很多人接到“把 Nginx 监控起来”这个需求时,第一反应是给机器装上 zabbix-agent,然后在 Zabbix Server 前端添加主机、链接模板。看起来链路通了,但过几天复盘时会发现,监控数据并没能回答任何业务问题。
原因很简单:**Nginx 监控不是“有没有装 agent”,而是“有没有把该采的状态数据采到”。**如果采样层是空的,后面所有图形和告警都是空转。
1.1 进程存活只是“没宕机”,不是“在正常服务”
Zabbix 默认的主机可用性监控,只能告诉你这台机器网络通不通、agent 有没有响应。它不能告诉你 Nginx 是否在接受新连接,也不能告诉你当前请求是不是堆积在处理队列里。
在生产环境里,进程活着和业务正常是两码事。Nginx 可能因为 worker 连接数打满、upstream 后端全部不可用、共享内存耗尽等原因,出现“进程还活着但服务已经劣化”的状态。只看进程存活,等于监控了个寂寞。
所以第一步,先把监控维度从“主机可用性”提升到“Nginx 运行状态”。这通常依赖 Nginx 自带的 stub_status 模块,或者更强的 vts、prometheus exporter 方案。
1.2 Nginx 自带状态页:stub_status 与更现代的替代方案
stub_status 是 Nginx 官方内置模块,编译时加--with-http_stub_status_module就能启用。如果你用的是发行版自带的 Nginx,很多发行版默认也编译了这个模块。启用后访问指定 URL,会得到这么一段输出:
Active connections: 6 server accepts handled requests 10 10 125 Reading: 0 Writing: 2 Waiting: 4这段信息量比你以为的大得多:
Active connections:当前活跃连接数,包括正在处理的和等待中的。accepts:Nginx 启动以来累计接受的客户端连接数。handled:成功处理的连接数。正常情况下它应该等于或接近 accepts。requests:累计处理的请求数。Reading:正在读取请求头的连接数。Writing:正在写响应给客户端的连接数。Waiting:空闲 keepalive 连接数。
如果只是追求简单,stub_status 完全够用。它的问题是信息维度偏“连接层”,看不到状态码分布、upstream 延迟、缓存命中率这些更高层指标。
在社区实践里,后续演进通常有两个方向:一个是 Nginx 的 vts 模块,能输出更丰富的 JSON 数据,但要重新编译 Nginx;另一个是引入 prometheus nginx-exporter,走 Prometheus 生态,再想办法接入 Zabbix。对绝大多数团队来说,先把 stub_status 这条链路跑通,已经能解决 80% 的监控需求。
1.3 一个最小可落地的监控指标清单
我建议第一次做 Nginx 监控时,不要贪多。先采这 7 个指标,稳定运行一个月,再考虑状态码、延迟和自定义业务探活:
| 指标 | 含义 | 主要用途 |
|---|---|---|
| nginx.active | 当前活跃连接数 | 看瞬时压力 |
| nginx.accepts | 累计接受连接数 | 看流量的绝对值 |
| nginx.handled | 累计处理连接数 | 对比 accepts,发现握手异常 |
| nginx.requests | 累计请求数 | 看请求趋势,容量预估 |
| nginx.reading | 读请求头的连接数 | 偏低时通常正常,持续高说明读请求慢 |
| nginx.writing | 写响应连接数 | 持续高说明响应写不出去 |
| nginx.waiting | 空闲 keepalive 连接数 | 偏低说明连接很快被回收 |
这里要注意,accepts、handled、requests 是累计值。Zabbix 里要用“变化率”或者依赖 Zabbix 自带预处理做差值,否则你看到的是一条一直往上的增长曲线,而不是每秒速率。这个细节很多人第一次配置时都会漏掉。
2. 安装与接线:Zabbix Server、Agent 与 Nginx 的三方关系
Zabbix 监控 Nginx 的场景里,看起来是“Zabbix 监控 Nginx”,实际上涉及三个角色:Zabbix Server、Zabbix Agent、Nginx 服务。三者关系不搞清,配置时很容易配错方向。
2.1 版本选择:Zabbix 7.0 LTS 还是 6.x,Docker 还是包安装
当前讨论里 Zabbix 7.0 LTS 和 Zabbix 6.0 LTS 的呼声都比较高。我的倾向是:
- 新环境直接上 Zabbix 7.0 LTS,它是官方长期支持版本,前端体验、模板管理、预处理能力都有增强。
- 存量环境如果已经在 6.x 稳定跑着,不必为了追新而升级。监控系统的第一原则是稳定,不是新功能。
- 如果只是学习和小规模验证,用 Docker 部署 Zabbix Server 可以快速看到效果。官方提供了现成的容器编排文件,MySQL/PostgreSQL + Zabbix Server + Zabbix Web 的组合能几分钟起一套。
- 生产环境我建议用包安装或者离线包。原因很朴素:包安装的升级路径更清晰,日志目录更常规,出问题时更容易用系统服务工具调试。Docker 部署在生产里不是不行,只是你需要把数据卷、备份、版本升级这些问题提前想清楚。
2.2 Agent 是被动采集还是主动上报
Zabbix Agent 有两种工作模式:
- 被动模式:Zabbix Server 主动连 Agent 的 10050 端口,发起 key 查询。
- 主动模式:Agent 按配置的 ServerActive 地址,主动连 Zabbix Server 的 10051 端口上报数据。
对于监控 Nginx 这个场景,我建议第一台机器先用被动模式跑通。原因是排查链路短:server 侧的 zabbix_get 命令可以直接验证 key 能不能取到值,问题更容易定位。等主机数量多了,比如几十上百台,再切主动模式,分摊 Server 的轮询压力。
还有一个容易踩的点:主动模式下,Agent 端配置的Hostname必须和前端创建主机时填写的“主机名称”完全一致,否则上报数据会失败。被动机则主要看前端配置的 agent 接口 IP 和端口对不对。
2.3 主机组、主机与模板:先建立最小联通
在 Zabbix Server 前端操作时,通常按这个顺序:
- 创建主机组,例如
Nginx-Servers。 - “数据采集 -> 主机 -> 创建主机”,填写主机名、可见名、选择主机组。
- 配置 agent 接口,填写被监控机 IP 和端口,默认 10050。
- 链接模板。如果还没有现成模板,先不要链接任何模板,直接手动添加一个监控项试试。
这里强调“先手动添加一个监控项”,是想让你先排除模板干扰。很多同学一开始就链接模板,结果数据没出来,分不清是 agent 配置问题、模板 key 和 agent 对不上,还是前端配置问题。先把一条 key 跑通,再套模板,整个流程会清晰很多。
3. 把状态数据接到 Agent:UserParameter 的真实工作过程
这是整篇文章最核心的一章。前面那些准备工作,最终都要通过 UserParameter 把 Nginx 状态数据变成 Zabbix Agent 能返回的 key。
3.1 先让 Nginx 暴露状态页,并限制访问来源
在 Nginx 配置里加一个 location。假设你的 Nginx 和 Zabbix Agent 在同一台主机上,最简单的配置是这样:
location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; }然后 reload 配置:
nginx -s reload用 curl 验证一下能不能拿到状态页:
curl http://127.0.0.1/nginx_status这一步是命门。如果 curl 都拿不到输出,后面所有配置都是空中楼阁。常见的失败原因包括:Nginx 编译时没带 stub_status 模块、location 写错了、allow/deny 顺序错导致本机也被拒绝。
如果你的 Agent 和 Nginx 不在同一台主机,那就不能只 allow 127.0.0.1,而要把 Agent 所在机器的内网 IP 加入 allow。不过我更建议把 agent 和 Nginx 放在同一台机器,既减少网络暴露面,也减少排查链路。
3.2 用一条命令验证解析结果,再写 UserParameter
拿到状态页输出后,先用命令行把要采集的字段解析出来。比如要采集活跃连接数:
curl -s http://127.0.0.1/nginx_status | awk '/Active connections/{print $3}'要采集累计请求数:
curl -s http://127.0.0.1/nginx_status | sed -n '3p' | awk '{print $3}'注意,不同 Nginx 版本的 status 输出格式偶尔会有差异。所以不要凭记忆写解析命令,先手工执行一遍,确认输出正确,再写进配置文件。
然后创建 UserParameter 配置文件。常见路径是/etc/zabbix/zabbix_agentd.d/nginx_status.conf:
UserParameter=nginx.active,curl -s http://127.0.0.1/nginx_status | awk '/Active connections/{print $3}' UserParameter=nginx.accepts,curl -s http://127.0.0.1/nginx_status | sed -n '3p' | awk '{print $1}' UserParameter=nginx.handled,curl -s http://127.0.0.1/nginx_status | sed -n '3p' | awk '{print $2}' UserParameter=nginx.requests,curl -s http://127.0.0.1/nginx_status | sed -n '3p' | awk '{print $3}' UserParameter=nginx.reading,curl -s http://127.0.0.1/nginx_status | awk '/Reading:/{print $2}' UserParameter=nginx.writing,curl -s http://127.0.0.1/nginx_status | awk '/Writing:/{print $4}' UserParameter=nginx.waiting,curl -s http://127.0.0.1/nginx_status | awk '/Waiting:/{print $6}'这里有两个隐蔽问题。
第一,curl命令此时是 Zabbix Agent 进程执行的,Agent 默认以zabbix用户运行。如果zabbix用户的环境变量 PATH 里没有 curl,命令会失败。稳妥做法是在配置里写 curl 的绝对路径,比如/usr/bin/curl。先执行which curl确定路径。
第二,Agent 配置里有Timeout参数,默认一般 3 秒或 5 秒。如果这条命令执行超过超时时间,Zabbix Server 会显示采集失败。curl 访问本机 Nginx 状态页通常毫秒级返回,如果你的机器负载很高导致命令超时,那首先要解决的是系统层面的问题,而不是盲目调大 Timeout。
改完配置后,重启 agent:
systemctl restart zabbix-agent然后可以用 agent 自带的自检命令确认 key 是否可用:
zabbix_agentd -t nginx.active如果返回ZBX_NOTSUPPORTED,说明 key 没注册上或者命令解析报错。如果返回数值,说明 agent 侧这一层已经通了。
3.3 模板里的 key 和 agent 端的 key 必须严格对得上
这里是最容易被忽略的一环。
你在前端导入官方 Nginx 模板后,模板里的监控项会定义一批 key。比如官方模板可能用nginx.connections.active,而你手写的 UserParameter 是nginx.active。两边对不上,Zabbix Server 去 agent 取数据时,agent 根本不知道nginx.connections.active是什么。
正确的做法是:
- 在前端“模板 -> 监控项”里,找到模板定义的 key 列表。
- 到 agent 端 UserParameter 配置里,把 key 名改成和模板一致的。
- 改完重启 agent,再用
zabbix_agentd -t <模板key>测试。
很多人在这一步反复折腾,其实问题就一个:模板 key 和 agent key 的名字没有对上。没有哪个神级模板能自动识别你的自定义 UserParameter,模板只是一个定义层,采集层必须手动对齐。
3.4 超时、权限和 curl 路径:三个最容易踩的隐形坑
把最容易踩的三个坑单独列出来,每个都值得记一下:
- 权限问题:Agent 以
zabbix用户运行,如果 Nginx 状态页做成了基于文件的 socket 访问,或者有限制系统用户的目录权限,命令就会失败。 - curl 路径问题:写相对
curl命令时,系统服务进程的 PATH 比你登录 shell 的 PATH 短很多。这是初学者最容易遇到的“命令行明明能跑,agent 一调就失败”的经典原因。 - 变量和引号问题:UserParameter 值里如果包含管道、引号,建议先用单引号或双引号包裹完整命令,避免被 Agent 配置解析器误切。
4. 前端配置与图形化:怎么知道数据是真的进来了
Agent 侧配置完后,回到 Zabbix Server 前端,把这批数据变成可见的监控项和图形。
4.1 监控项、历史存储、预处理和单位
如果你没有链接任何模板,就需要手动创建监控项。在前端“数据采集 -> 监控项 -> 创建监控项”里,关键字段是:
- 名称:写清楚,比如
Nginx Active Connections。 - 类型:默认 Zabbix agent。
- 键值:填 agent 端定义的 key,比如
nginx.active。 - 主机接口:选择 agent 接口。
- 数据类型:一般是数字,无符号。
- 单位:连接数可以留空,请求数如果要展示为速率,需要用预处理或者 Zabbix 的差值算法。
关于单位,有个容易出问题的小知识:如果填了单位B,Zabbix 会按字节格式显示数值;如果填s,可能会把你的数字当成秒来显示。对连接数这种无量纲指标,建议单位留空。
如果是累计值指标,比如 accepts、requests,我建议在监控项里只存原始累计值,然后在图形里用 Zabbix 的函数做变化率展示。这样数据源完整,后续想按天、按小时看累计量也能算。
历史数据保留周期和趋势数据保留周期,建议保持默认。除非你的磁盘特别紧张,否则不要为了省空间把历史周期压得太短,否则排查问题时你会发现图表里全是“毛刺”没有细节。
4.2 图形和数据展示的常见偏差
配置完监控项后,先去“检测中 -> 最新数据”页看有没有数值进来。这一步能直接判断整条链路是否通了。
如果最新数据里能看到值,接下来创建图形:
- 进入“数据采集 -> 图形 -> 创建图形”。
- 选择刚才创建的几个监控项。
- 图形类型默认“正常”即可。
- 刷新图形页面,看到曲线开始波动,说明可视化层已经 OK。
这里常见的偏差是:数值永远是一个固定值,比如requests一直是一条横线。这往往不是你采集失败了,而是你把这几个累计值直接当成“速率”画出来了。真正的速率曲线需要在图形里配置监控项时勾选函数,比如用change()、rate()或者min()配合时间周期。
4.3 从单个 host 到多 host 批量接入
单台主机跑通后,再做批量接入。
推荐思路:把这批自定义 UserParameter 文件通过配置管理工具下发到所有 Nginx 机器,然后在 Zabbix 前端把模板链接到新主机。如果不同 Nginx 实例的 status 路径或端口不一致,可以用宏来解决,比如在模板里把 key 定义成带参数的形式,再把 URL 作为用户宏维护。简单场景下,先用统一路径http://127.0.0.1/nginx_status是最省事的。
模板的价值不是让你不用写 UserParameter,而是把“监控项定义、图形、触发器”统一成可复制资产。真正到多主机场景,你还是需要确认每一台机器上的 UserParameter 是一致的。
5. 数据不到时的排查链路:从现象到根因
监控系统最耗时的不是配置,而是排障。下面这条排查链路是基于同类问题反复实操总结出来的,遇到 Nginx 监控数据出不来时可以按顺序走一遍。
5.1 按“本地命令 → Agent → Server → 前端”的顺序排查
我一般按照这个顺序,从底层往上层查:
本地命令:在被监控机上,手动执行 UserParameter 里那条命令,确认 curl 能访问、awk/sed 解析正确。
Agent 侧:执行
zabbix_agentd -t <key>,确认 agent 能返回数值。这一步能隔离大部分配置和权限问题。Server 侧:在 Zabbix Server 机器上用
zabbix_get主动拉一次 key:zabbix_get -s <被监控机IP> -p 10050 -k nginx.active如果能返回数值,说明 server 和 agent 之间的网络和协议都正常。
前端侧:检查“最新数据”里监控项有没有报错,比如
Not supported或Timeout。
这四步做完,80% 的问题都能定位到具体层。
5.2 常见的五类根因和对应处理
结合实操经验,最常遇到的是这五类问题:
| 现象 | 根因 | 处理方式 |
|---|---|---|
zabbix_agentd -t返回 Not supported | UserParameter key 没注册或命令写错 | 检查配置文件路径、语法,重启 agent |
| 手动命令正常,agent 调用失败 | PATH 里没有 curl 或权限不足 | 写绝对路径/usr/bin/curl,检查 zabbix 用户权限 |
zabbix_get拉不到值 | 防火墙挡了 10050,或前端主机 IP 配置错 | 放通端口,核对 agent 接口配置 |
| 前端显示 Not supported | 模板 key 与 agent key 不一致 | 对齐模板里的 key 名和 UserParameter 里的 key 名 |
| 数据有但图形断断续续 | Agent Timeout 太短或服务器压力大 | 先查负载,再考虑调 Timeout |
5.3 版本变化与新特性带来的兼容注意点
Zabbix Agent 和 Zabbix Server 之间是存在兼容性边界。老版本 Server 配新版本 Agent,或者反过来,都可能在加密、协议字段上出问题。
所以版本策略要保守一点:要么 Server 和 Agent 用同一大版本的主流小版本,要么先在一台测试机上验证兼容性再铺开。生产环境最怕的就是“监控系统本身成了新的不稳定因素”。
另外,Zabbix 7.0 之后,模板体系更强调独立模板和宏的使用。如果之前已经在老版本上手动建过一套 Nginx 监控项,升级后不一定能无缝迁移,要在测试环境里先跑一遍模板导入导出,确认 key 和图形不丢。
6. 监控有价值,关键在于阈值、聚合和长期维护
最后一步,也是很多团队最缺的一步:数据采集上来了,怎么让它真正成为决策依据。
6.1 先积累数据,再定告警阈值
我强烈不建议第一天就给连接数设死一个告警阈值,比如“大于 2000 就告警”。正确的做法是:
- 先采集至少一周到一个月的数据。
- 在图形里看这组指标的日常基线。
- 找到峰值区间,再根据 P95 或 P99 设定告警阈值。
阈值一定得基于你自己的业务。有的业务高峰期 active connections 到 2 万也没事,有的业务 2000 就扛不住了。不看自己的数据分布就设阈值,不是监控,是碰运气。
6.2 连接数、请求数不够,配合日志和 upstream 才能定位容量问题
回到文章开头那个场景:Nginx 进程活着,但服务变慢。如果你只监控了 active connections 和 requests,你可能还是看不到问题,因为 Nginx 自己并不慢,慢的是它背后的 upstream。
stub_status 提供的信息有限。要更深入排查容量和质量问题,至少还需要:
- access log 里的状态码分布:4xx 和 5xx 比例突增,往往是业务或依赖出问题的信号。
- upstream_response_time:这是反向代理场景最重要的指标之一,能直接看出后端响应耗时。
- Nginx 错误日志:连接超时、上游主动断开、worker_connections 不够、文件描述符耗尽,都会在 error log 里留下线索。
这些不是 Zabbix 一个模板能完整覆盖的。更常见的工程化方案是:Zabbix 监控主机层和进程层指标,再搭配 Nginx 日志的集中采集分析,或者引入 vts/prometheus exporter。每一层解决每一层的问题,不要指望一个 agent 全包。
6.3 把这个场景沉淀成一套可复用的监控落地流程
如果你只记住一件事,就记住这个顺序:**先固定指标,再打通通道,再做可视化,最后才做告警。**顺序反了,告警只会成为另一个噪声源。
一个可复用的落地框架大概是:
- 先定义要采的指标。从 stub_status 的 7 个基础指标开始,不要一上来加状态码、延迟。
- 再让数据能采到。开 Nginx 状态页,写 UserParameter,用
zabbix_agentd -t验证。 - 然后接前端。创建监控项、图形,确认最新数据有值,图形有曲线。
- 等数据积累到能看出趋势后,再写触发器。告警先用 Info/Warning 级别试运行,避免直接 High 刷屏。
- 最后考虑扩展。从单台到批量,从连接数到状态码到 upstream 延迟,按需逐步加。
这套流程适用面不只有 Nginx。任何用 Zabbix 监控中间件、数据库、应用服务的场景,底层思路都是相通的:先确认要采什么,再确认采集命令能跑通,最后把数据变成图形和告警,而不是反着来。
Nginx 的 stub_status 看起来简单,但它背后那条链路,足够让你把 Zabbix 的 agent、UserParameter、模板、监控项、触发器整套机制完整摸一遍。跑通它,你会发现 Zabbix 监控其他中间件,路径也差不远。