拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Zabbix监控Nginx全攻略:从status模块到告警配置与排坑指南

在监控体系里Nginx 的监控经常被做成半拉子工程——页面装了、Zabbix 也跑着但一问你的 Nginx 连接数多少、QPS 多少、最近有没有异常流量回答往往是沉默。我遇到过不少同学上来就导模板结果 Zabbix 里一堆 item 全是红色 unsupported连问题出在哪都说不清。先把结论放前面Zabbix 监控 Nginx 这件事百分之八十的坑不在 Zabbix而在前面两步——Nginx 自己有没有把监控数据暴露出来以及 Agent 这边有没有把数据翻译成 Zabbix 认识的 key。模板只是最后一层包装纸。这篇文章我会从最底层的 status 模块讲起一路讲到模板、触发器、告警最后把我踩过的坑挨个复盘一遍。适合有 Zabbix 基础、正准备接 Nginx 监控或者已经被 unsupported 折磨了一天的朋友参考。1. 先撕开 Nginx 的 status 口子想监控它得先让它开口说话很多新手会疑惑为什么监控 MySQL、Redis 的时候装个 agent 就有数据到了 Nginx 这里就什么都取不到原因很简单Nginx 本身没有内置一个指标端点它默认不对外输出任何运行状态。不像 Redis 有 INFO 命令Nginx 想要暴露连接数、请求数必须让它在编译时带上--with-http_stub_status_module模块然后手动配置一个 location。这一步不做后面 Zabbix 的一切操作都是白费。1.1 开启 stub_status 的完整配置在 nginx.conf 的 server 块里加上这样一段location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; allow 192.168.1.0/24; deny all; }配置完以后nginx -t检查语法然后 reloadnginx -t nginx -s reload用 curl 验证一下curl http://127.0.0.1/nginx_status如果一切正常你会看到类似这样的输出Active connections: 12 server accepts handled requests 33031 33031 39083 Reading: 0 Writing: 3 Waiting: 9这些数据就是后面 Zabbix 要抓的原始素材。你需要确认你的 Nginx 确实是编译了 stub_status 模块的。如果不确定执行nginx -V 21 | grep stub_status如果没有任何输出说明这个 Nginx 是精简发行版或者没带模块后面我会专门讲怎么办。1.2 status 页面每个字段到底代表什么别小看这几行文本每个数字背后都是一个运维信号字段含义需要关注的原因Active connections当前活跃连接数含正在处理的请求直接反映当前压力水平暴增通常意味着流量异常或并发集中server accepts handled requests三个累计值接受的连接数、处理过的连接数、处理的请求数accepts 与 handled 长期不一致说明有连接被丢弃Reading正在读取请求头的连接数持续高位且伴随 QPS 上升说明带宽或 SSL 握手压力大Writing正在写响应的连接数和上游响应速度强相关接口慢时这里能看出来Waiting空闲 keep-alive 连接数等待请求的空闲连接Waiting 高说明长连接策略执行正常这三个累计值是单调递增的Zabbix 模板里一般会用 Change per second 这种预处理把它们换算成每秒新增连接数/每秒请求数这才是真正有用的指标。1.3 开 status 之前的三个安全顾虑第一绝对不要把 status 页面暴露到公网。它虽然只有几行数字但等于把你当前在线人数、请求速率都摊开了给人看对攻击者来说是很好的情报。所以生产环境务必用allow/deny限定来源 IP最安全的做法是只允许监控服务器和本机访问。第二采集频率不要太疯狂。stub_status 页面本身也会消耗一点 CPU虽然单次开销微乎其微但如果 Zabbix 里配了十个八个 item 全指向这个页面还都用 10 秒间隔采集在高并发生产环境就有点伤筋动骨了。我一般建议采集间隔不低于 30 秒。第三如果你是刚接手一个老项目先检查 Nginx 版本。1.7.5 之前的版本对 stub_status 的格式略有差异一些老脚本的正则可能直接失效。关于版本差异的具体坑我在第 5 部分会展开说。2. Zabbix Agent 侧配置用 UserParameter 把指标翻译给 ZabbixNginx 把数据吐出来了接下来就是 Zabbix Agent 的工作。这里有个常见的认知误区很多人以为 Zabbix 能直接读那个 status 页面其实不能。Zabbix Agent 默认只认识自己的 key你要把抓取 Nginx status 页面并提取某个字段的逻辑写成一段脚本或者一条命令然后用UserParameter注册成一个自定义 key。Agent 执行这条命令拿到结果Zabbix Server 才能把它记录为监控项数据。2.1 一段能直接抄的脚本配置我习惯把自定义配置放在独立的文件里方便维护。在 Zabbix Agent 的配置目录下新建一个文件vim /etc/zabbix/zabbix_agentd.d/nginx.conf写入如下内容UserParameternginx.active,curl -s http://127.0.0.1/nginx_status | awk NR1{print $3} UserParameternginx.accepts,curl -s http://127.0.0.1/nginx_status | awk NR3{print $1} UserParameternginx.handled,curl -s http://127.0.0.1/nginx_status | awk NR3{print $2} UserParameternginx.requests,curl -s http://127.0.0.1/nginx_status | awk NR3{print $3} UserParameternginx.reading,curl -s http://127.0.0.1/nginx_status | awk NR4{print $2} UserParameternginx.writing,curl -s http://127.0.0.1/nginx_status | awk NR4{print $4} UserParameternginx.waiting,curl -s http://127.0.0.1/nginx_status | awk NR4{print $6}这里每一个 key 后面都是一条完整的 shell。awk NR1{print $3}的意思是取第一行的第三个字段也就是 Active connections 后面的那个数字。第三行对应accepts handled requests的累计值第四行取 Reading/Writing/Waiting 后面的数字。配置完成后重启 agentsystemctl restart zabbix-agent注意如果 Agent 和 Nginx 不在同一台机器上这里的127.0.0.1要改成 Nginx 所在机器的实际 IP同时要确保 Nginx 的 allow 规则放行了 Agent 所在机器的 IP。很多老运维会告诉你把所有指标合成一个 JSON 用一次 curl 取回来更高效但那是进阶玩法。新手阶段一条命令对应一个 key排查问题最直观哪条 red 了一眼就能看出来。2.2 被动检查还是主动检查这不是个单选题Zabbix Agent 有两种上报模式被动passive和主动active。被动模式下Zabbix Server 主动连 Agent 的 10050 端口拉取数据。这种模式最常用配置简单大部分模板都默认走这个通道。但如果你的监控服务器数量上百Server 要挨个去连网络连接数会很高而且 Agent 如果被防火墙挡着数据就断了。主动模式下Agent 自己定期连 Server 的 10051 端口批量上报数据。这种方式对服务端压力小很多也更适合跨网段的场景。启用主动模式需要两步# zabbix_agentd.conf 中指定 ServerActive ServerActivezabbix.server.ip # 监控项类型选择 Zabbix agent (active)我个人的建议是单机少量指标用被动服务器集群或者跨机房采集用主动。很多人在一个 Agent 上同时开两种模式也没问题但要注意 key 的检查类型必须和 Agent 的实际模式对应否则 item 状态就会是红色 unsupported。关于这个坑我在第 5 章会专门讲一个具体案例。2.3 三分钟命令行自测配置完以后别急着去 Zabbix Web 界面创建监控项。在 Server 端先把数据测通这样能快速定位问题出在 Agent 还是 Zabbix。Zabbix Server 上一般自带zabbix_get工具zabbix_get -s 192.168.1.10 -k nginx.active如果能正确返回数字说明 Agent 和 Nginx 这条链是通的。如果报ZBX_NOTSUPPORTED多半是 curl 命令执行失败、脚本权限不够或者是 Agent 的配置没重载。再补充一个容易忽略的点Zabbix Agent 默认以zabbix用户运行如果/tmp下有一些严格的目录权限限制或者系统装了 SELinux 且没有放行curl 执行时可能连不上本机端口。遇到这样的情况可以先手动用zabbix用户跑一遍那条 UserParameter 命令su -s /bin/bash zabbix -c curl -s http://127.0.0.1/nginx_status手动跑不通的Agent 里一定跑不通手动能跑通Zabbix 里还报错那就去看 Agent 日志。3. 模板导入不是终点监控项、预处理和宏的对应关系链路通了、数据能取了下一步是让 Zabbix 认识这些数据。这里又是一个分岔路口——用官方自带模板还是用社区模板3.1 官方模板与第三方模板的差异Zabbix 5.0 之后的版本自带了一个叫Nginx by HTTP的模板这个模板不需要 Agent 端自定义脚本直接由 Zabbix Server 通过 HTTP 请求去抓 status 页面。使用它只需要在宏里填好 URL、路径、端口然后给主机链接模板就行。另外一类老牌的社区模板比如网上流传的Template App Nginx走的是 Agent 自定义 key 路线依赖第 2 章配置的那些 UserParameter。两者的核心区别可以看这张表对比维度Nginx by HTTP官方Template App Nginx社区/自定义数据采集者Zabbix Server 直接 HTTP 请求Zabbix Agent 执行命令后上报客户端是否要装 Agent不需要 Agent 的 UserParameter需要配置脚本并重启 Agent支持 Nginx 多实例通过宏区分不同 URL简单需要为不同实例配置不同 key对网络要求Server 到 Nginx 必须通Agent 到 Nginx 必须通灵活性受限于模板内置的采集逻辑可以随便扩展自己的监控项我见过不少生产环境两个都有——官方模板用来兜底自定义的 UserParameter 用来补充一些模板里没有的字段比如上游后端健康状态、CPU 占用等。如果刚开始做优先用官方 Nginx by HTTP少配一段脚本少一些权限检查排查问题轻松很多。3.2 预处理Preprocessing是隐藏的精华官方模板里最容易被忽略的是预处理这一块。Nginx 的 status 页面是一个多行文本Zabbix 凭什么能提取出单个数字靠的就是预处理。在 Zabbix 的监控项配置里官方模板对采集到的原始数据做了正则提取。例如对nginx.stub_status.requests这类监控项预处理步骤可能包含步骤1: Prometheus pattern? 或 步骤2: Regular expression - 提取 requests 后面的数字 步骤3: Change per second - 把累计值换成每秒速率理解这层逻辑非常重要。当你发现某个监控项有数据但数值明显是累计量而不是每秒速率时多半是预处理里的 Change per second 没生效或者你手工创建的监控项漏掉了这一步。预处理的设计初衷是让 Zabbix 承担一部分数据清洗工作而不是每改一个提取逻辑就去改一次脚本。我自己后来接新服务的监控几乎都会优先考虑能不能在预处理里用正则解决而不是给 Agent 再加一段脚本维护成本完全不是一个量级。3.3 宏Macro的优先级同一台主机要盯两个 Nginx 实例怎么办官方模板定义了一组宏用来告诉 Zabbix Server 该去哪个地址抓取宏默认值含义{$NGINX.STUB_STATUS.SCHEME}http请求协议如果 Nginx 开了 HTTPS 要改成 https{$NGINX.STUB_STATUS.HOST}当前主机 IPNginx 所在地址{$NGINX.STUB_STATUS.PORT}80Nginx 监听端口{$NGINX.STUB_STATUS.PATH}/nginx_status状态页面的 URL 路径宏的优先级从高到低是主机级宏 模板级宏 全局宏。同一台主机如果跑了两个 Nginx 实例比如一个是 8080 端口一个是 8081 端口你可以复制一套官方模板在模板级把第二个实例的 PORT 宏改成 8081然后给主机链接两份模板。这样一份数据源都不用改一张主机上就能看两个实例的对比曲线非常方便。这个思路同样适用于通过 HTTPS 暴露 status 页面的场景。你只需要在主机级宏里把 SCHEME 改成 https同时确认证书能被 Zabbix Server 信任或者关闭证书校验其他的都交给模板。4. 数据有了告警才是灵魂触发器阈值与告警路由调优监控系统存在的前提是能在故障发生时通知人。如果只采集数据、画曲线而没有告警那这套系统充其量是个历史记录器。Nginx 监控里触发器Trigger的配置和人的因素是强相关的这里值得花点心思。4.1 值得盯的几个核心指标我的取舍标准是告警数量少而准宁可漏掉不痛不痒的也不能一天几十条刷屏。基于这个原则Nginx 侧我目前保留了这几个触发器第一Active connections 过高。这个值和机器处理能力、业务模型强相关没有通用阈值。我的建议是先采集一周看曲线毛刺正常情况下连接数应该有明显的波峰波谷把波峰向上浮动 30% 作为告警阈值。第二每秒请求数骤降/骤增。骤降往往意味着 Nginx 挂了、上游全挂或者有人改了配置导致请求没进来骤增则可能是爬虫、CC 攻击。用 Change per second 处理后的 requests 监控项触发器可以写成last(/Nginx by HTTP/nginx.stub_status.requests.change) 500这个表达式的意思是如果每秒请求数在采集间隔内的变化量超过 500就触发告警。具体数字需要根据你自己的业务 QPS 来调整。第三Reading 持续偏高。Reading 表示正在读取请求头的连接数正常情况下应该很低。如果 Reading 长时间挂在高位很有可能是客户端建立了大量连接但请求头发送得很慢——典型的慢速攻击特征。这个指标一旦出现异动优先级比连接数高得多因为它直接指向安全事件。4.2 阈值不要拍脑袋先用一周建立基线很多人拿到模板的第一反应是改触发器阈值把模板自带的连接数大于 100改成大于 500然后问我要一个标准的推荐值——但 Nginx 监控没有推荐值。不同业务的 Nginx 配置、后端响应时间、静态资源占比都会导致指标差异巨大。我自己的操作流程是新接入一台 Nginx 时触发器全部先禁用掉只保留数据采集和历史记录。跑一周以后打开 Zabbix 的 Latest data 看那一周的最小值、最大值、平均值找一个正常业务波动范围再按这个范围设阈值。比如某台机器的 Active connections 平时在 20-80 之间波动峰值偶尔到 150那我就会把告警阈值设到 250 左右。这个值既不会在正常高峰误报又能在真正出问题时及时响应。至于模板自带的100 就告警对这台机器来说纯粹是噪音。4.3 告警分级和责任人别让一个人扛所有 Nginx团队协作时最忌讳的是所有告警都发给群里的运维大群结果真正懂 Nginx 的人被消息淹没。Zabbix 的告警媒介可以按用户和用户组来发我的建议是P3 级别信息类连接数短暂波动等发给 Nginx 专项负责人走企业微信或钉钉机器人不页面轰炸。P2 级别严重每秒请求数归零、Reading 长时间异常除了发负责人还要同时发到值班群。P1 级别紧急Agent 失联、服务不可达。平台型告警系统要介入同时给负责人打电话或者发短信。这些其实不用搞太复杂Zabbix 自带的告警等级和动作Action就能实现核心是条件里设置触发器严重级别就行。如果你已经接入了 Grafana 或者第三方告警平台把 Nginx 的告警事件推送过去再联动值班表又是另外一套玩法了。5. 大坑复盘监控 Nginx 时会踩的五类故障排查链路这章是全文含金量最高的部分。以下每一个坑我都实际遇到过有的在网上搜了半天也没找到像样的排查思路最后是自己一步步试出来的。我按现象 - 排查链路 - 根因的结构写你照着流程走一遍基本能定位。5.1 status 页面手动访问正常Zabbix 却显示 404这个现象很有意思用浏览器访问http://server/nginx_status明明是好的但 Zabbix 模板里配置的监控项全部返回 404。排查链路在 Zabbix Server 上先手动 curl 试试curl http://nginx_ip/nginx_status如果这里也是 404问题就明确了——是来源 IP 被拒。检查 Nginx 的 allow/deny 配置你会发现你放行的 IP 只有127.0.0.1和某几个内网地址而 Zabbix Server 的 IP 不在里面。因为浏览器访问时来源 IP 是本机或者你在局域网内的电脑而 Zabbix Server 发起请求时来源 IP 是 Zabbix Server 自己的地址。如果你用的是官方 Nginx by HTTP 模板allow 列表里必须放行 Zabbix Server 的 IP如果你用 Agent 的 UserParameter 方式allow 列表里放行 Agent 所在机器的 IP 即可。顺手补充很多发行版的 Nginx 配置文件里自带一个默认 server 块location/nginx_status如果写在默认 server 里而实际访问的域名匹配到了另一个 server 块也会出现配置了但访问 404的问题。检查时务必确认你修改的是不是实际生效的那个 server。5.2 item 全部 unsupported先从这几条入手Zabbix 监控项显示红色 unsupported是最常见也最让人头大的问题。排查链路按从内到外的顺序在 Server 端用zabbix_get手工取一下 key看返回什么。zabbix_get -s 192.168.1.20 -k nginx.active如果返回ZBX_NOTSUPPORTED说明 Agent 执行这条命令失败了。看 Agent 的日志。默认路径是/var/log/zabbix/zabbix_agentd.log里面会有not supported的详细原因。比如找不到 curl、脚本没有执行权限、命令超时等。检查命令里的路径。如果脚本里的curl写的是绝对路径/usr/bin/curl有些系统装在/usr/local/bin/curl那 Agent 执行时找不到命令就直接 unsupported。建议先which curl看看实际路径必要时候写成绝对路径更稳。检查 UserParameter 配置文件是否被 include。Zabbix Agent 配置里必须有Include/etc/zabbix/zabbix_agentd.d/*.conf这一行否则你新建的 nginx.conf 根本没有被读取。最坑的一种情况是Agent 的日志明明显示命令执行成功但 Server 端始终 unsupported。这种大概率是被动/主动模式不匹配——监控项在 Web 界面上选的是 Zabbix agent被动但 Agent 进程只配置了 ServerActive主动上报被动端口 10050 都没在监听。检查一下netstat -lntp | grep 10050没有输出说明 Agent 根本没开被动模式改监控项类型或者补配被动模式都行。5.3 配置了允许某个 IPAgent 还是取不到数据现象Agent 和 Nginx 在同一台机器用zabbix_get从 Zabbix Server 上取数据时填入 Nginx 的 URL 是http://127.0.0.1/nginx_status脚本手动执行正常但一旦是 Zabbix Server 去取日志里就报连接失败。这里有个隐蔽的点zabbix_get -s agent主机IP -k nginx.active它执行的是 Agent 本地的 curl 命令请求的 URL 是脚本里写的地址。如果你的脚本写的是http://127.0.0.1/nginx_status那它请求的是Agent 本机的回环地址而不是 Nginx 所在机器的回环地址。换句话说只要 Agent 和 Nginx 在同一台机器这个写法其实是安全的也是我推荐的做法。真正容易出问题的是另一种场景Agent 和 Nginx 不在同一台比如 Agent 装在独立监控机上Nginx 在另一台。此时脚本里的 curl 目标必须写成 Nginx 的真实 IP而且这个 IP 必须出现在 Nginx 的 allow 配置里。很多同学会把 Agent 上的脚本里留着的127.0.0.1忘掉结果 Agent 一直在请求自己本机的 80 端口当然什么都取不到。记住脚本里的地址是谁在 curl就代表调用者的视角。5.4 Active 检查项数据延迟严重曲线像锯齿如果你用的是主动模式会发现有时候数据点缺得厉害或者历史曲线出现明显的锯齿。这不是 Nginx 的问题而是主动模式的上报间隔和数据刷新之间的错位。主动模式下Agent 在配置的获取间隔比如 30 秒到 Server 上拉取任务然后马上执行命令并回传结果。但 Server 侧默认还有一个历史数据保存的配置如果你的 item 类型是 Zabbix agent (active)而 Server 端的缓存刷新周期没调好就可能出现数据到了 Server 但还没写入数据库的情况。排查链路确认 Agent 配置里ServerActive指向的是正确的 Zabbix Server 地址。在 Zabbix Server 上执行zabbix_sender -z zabbix.server.ip -s 主机名 -k nginx.active -o 123手工推一条测试数据看 Web 界面能不能在 Latest data 里看到。检查 Server 端的CacheSize配置是否太小如果监控项非常多而 CacheSize 默认只有 8M数据可能有积压。实际经验是能走被动尽量走被动主动模式适合大批量主机但调试成本高不少。如果你只有十几台机器用被动模式能省掉一半的抓狂时间。5.5 换了一台 Nginx 服务器模板却取不到数据这个坑通常出现在你从 CentOS 换了 Ubuntu 或者用了某些云厂商的预装镜像之后。现象是老的服务器上监控一切正常新服务器同样的配置、同样的模板但 status 页面访问直接被拒绝或者请求始终返回 404。排查链路nginx -V 21 | grep stub_status看看现有二进制到底有没有编译这个模块。如果没有输出说明你的 Nginx 是精简版或者没有编译该模块。这时候有两个选择一是用系统包管理器安装标准的 nginx一般自带二是重新编译 Nginx加上--with-http_stub_status_module参数。重新编译前记得备份原来的nginx.conf和站点配置文件。很多运维新人一上来就重新编译 Nginx其实先确认nginx -V的输出列表里有没有这个模块是最省事的一步。云镜像里很多 nginx 是不带这个模块的但也不排除它已经通过动态模块方式加载了 stub_status这时nginx -V里可能看不到需要nginx -m或者nginx -T确认。还有一个反向的坑某些定制版 Nginx 输出 status 页面的字段顺序和标准版不一样。比如要求输出里第三行是accepts handled requests但定制版可能多了一行或者其他字段。模板里的正则提取就会失效。遇到这种先curl看原始输出再用模板的正则去匹配不要想当然。6. 让数据流动起来监控大屏和后续的扩展玩法监控系统做到能采集、能告警只是及格数据用起来的标志是你能快速回答昨晚 10 点的 QPS 是多少最近一周 Nginx 的连接数有没有异常增长这类问题。这里给你两个实用方向。6.1 用聚合图形快速搭一张 Nginx 监控视图Zabbix 自带的数据可视化虽然不花哨但足够实用。在 Monitoring - Hosts - Graphs 里点击 Create graph把nginx.requests注意要选 Change per second 预处理之后的那一项、nginx.active、nginx.writing都拉到一个图形里一张简单的 Nginx 运行状态图就完成了。如果你分别给多个 Nginx 实例链接了模板还可以在 Screens 里创建一个聚合屏把不同主机的曲线放到一块看方便对比。6.2 把监控数据接入 Grafana 大屏如果你所在团队已经有 Grafana强烈建议把 Zabbix 数据源接进去。Grafana 有官方的 Zabbix 数据源插件配置非常简单插件装完后填 Zabbix API 地址、用户名、密码然后导入一个 Zabbix 仪表盘模板几分钟就能看到比 Zabbix 原生更漂亮的图。Grafana 大屏的好处不只是好看它可以把 Nginx、MySQL、系统负载这些监控数据放到同一张图上。比如告警说连接数暴增你切到 Grafana 看同一时段的 MySQL 慢查询曲线、系统负载曲线往往能一眼看出是不是上游数据库拖慢了后端进而导致 Nginx 连接堆积。这种跨组件联查的能力是 Zabbix 原生的图形界面很难做到的。6.3 再往前走一步监控 upstream 和后端健康状态如果你想在 Nginx 监控上做得更深一层光是 stub_status 那些连接数就不够了。可以写一个小的 shell 脚本定期探测 Nginx 配置的上游服务器端口连通性然后用 UserParameter 上报给 Zabbix。这样你不仅能知道 Nginx 自己忙不忙还能知道它背后的应用服务器是不是有节点挂了。我自己实际用过的一个简化版本是用curl -s -o /dev/null -w %{http_code}去请求后端健康检查接口如果返回码不是 200就记一个 1这样 Zabbix 里就能对每个 upstream 节点单独设置告警。这个方案不复杂但能把 Nginx 的监控从边缘层推进到业务层对排查问题帮助很大。最后再分享一个我个人的小习惯每次在 Zabbix 里给某个服务建完监控我都会在电脑上开一个随时能打开的监控家底清单记录这台服务器上装了哪些 agent、用了哪些模板、采集间隔多少、告警阈值是多少。Nginx 这种核心组件的监控配置并不复杂但参数一旦乱了排查起来非常啰嗦。把初始设计意图写清楚三个月之后再回来调阈值时你会感谢当时的自己。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门