在现代云原生架构中,nginx 早已超越了“仅仅是一个 web 服务器”的角色——它既是高性能反向代理、api 网关、负载均衡器,也是微服务流量治理的关键入口。然而,当 nginx 承载着成千上万 qps、处理数十种上游服务、承载 tls 终止与 waf 规则时,“它还在运行” ≠ “它运行得健康” ❗
一次 502 错误可能源于上游超时,一次连接耗尽可能因 worker_connections 配置失当,而持续升高的 ngx_http_upstream_fails 却常被 日志淹没于海量 access.log 中……
如何让 nginx 的“呼吸频率”、“心跳节律”、“血压波动”变得可观测、可量化、可告警?答案是:构建一套轻量、标准、可扩展的指标采集-可视化-告警闭环 ——而这正是 prometheus + grafana 组合的黄金战场 。

本文将带你从零开始,手把手落地一套生产就绪的 nginx 监控告警体系:
深度解析 nginx 原生监控能力(stub_status)与增强方案(nginx-module-vts);
- 部署并配置 prometheus 抓取 nginx 指标(含 service discovery 与 relabeling 实战);
- 使用 grafana 构建多维度 nginx 仪表盘(含实时连接数、请求速率、状态码分布、上游健康度);
- 编写 java 应用模拟真实业务流量,并注入可观测性埋点,实现 “应用层异常 → nginx 层告警 → 开发快速定位” 的端到端追踪链路;
- 定义高价值告警规则(如:5xx 突增、连接耗尽风险、上游全宕机),并通过 alertmanager 接入企业微信/邮件通知;
最终形成一个无需侵入业务代码、不依赖商业 apm、符合 openmetrics 标准、且完全开源可控的监控基座 。
前置说明:本文所有配置、代码、命令均基于以下环境验证(linux x86_64, nginx 1.24+, prometheus 2.47+, grafana 10.2+),所有外部链接均为权威文档源站,可直接点击访问。
一、为什么不能只靠 nginx 日志?
nginx 的 access.log 和 error.log 是诊断问题的宝贵财富,但它们存在本质局限:
| 维度 | 日志方式 | 指标方式(prometheus) |
|---|---|---|
| 时效性 | 异步写入磁盘,延迟秒级甚至分钟级;grep 分析需人工介入 ⏳ | 每 15s 抓取一次,毫秒级采集,实时聚合 |
| 聚合成本 | awk '{print $9}' access.log | sort | uniq -c | sort -nr —— 单次分析耗时且不可复用 | rate(nginx_http_requests_total{code=~"5.."}[5m]) —— 一行 promql 实时计算错误率 |
| 维度爆炸 | 想看“某 upstream 下 /api/v1/users 的 429 错误趋势”?需定制日志格式 + 复杂正则 + elk 资源投入 | nginx_http_requests_total{upstream="user-service", path="/api/v1/users", code="429"} —— 原生多维标签,开箱即用 |
| 资源开销 | 高频写入 ssd,日志轮转、归档、清理策略复杂 | 指标为内存中 counter/gauge,无磁盘 i/o,单实例可支撑数万指标/秒 |
官方印证:nginx 官网明确指出 ——“while logs are essential for debugging, metrics provide the real-time operational intelligence needed for sre practices.”
—— nginx monitoring best practices
因此,日志是“法医报告”,指标是“生命体征监护仪”。二者不是替代关系,而是互补协同。本文聚焦后者,打造你的 nginx “icu 监护系统”。
二、nginx 指标暴露:原生 vs 增强方案对比
nginx 提供两种主流指标暴露方式,选择前务必理解其能力边界:
2.1 原生ngx_http_stub_status_module(极简但受限)
这是 nginx 编译时默认启用的模块,只需简单配置即可暴露基础连接状态:
# nginx.conf
server {
listen 127.0.0.1:8080;
server_name localhost;
location /nginx_status {
stub_status on;
allow 127.0.0.1; # 仅允许本机访问
deny all;
}
}
访问 http://localhost:8080/nginx_status 返回纯文本:
active connections: 3 server accepts handled requests 12345 12345 67890 reading: 0 writing: 2 waiting: 1
优点:零依赖、零编译、开箱即用、资源占用极低。
致命缺陷:
- 无 http 状态码统计(无法区分 200/404/500);
- 无 upstream 信息(不知道请求打到了哪个后端);
- 无路径/host 维度(无法按
/api/*聚合); - 无时间序列(只有瞬时值,无法计算速率/百分位);
- 非标准格式(prometheus 无法直接抓取,需额外 exporter 转换)。
2.2 增强方案:nginx-module-vts(推荐!)
nginx-module-vts(virtual host traffic status)是由 github 用户 vozlt 开发的成熟第三方模块,已被大量生产环境验证。它以 json 格式暴露全维度、标准化、openmetrics 兼容的指标,完美契合 prometheus 生态。
安装(ubuntu/debian 示例)
# 1. 安装依赖 sudo apt update && sudo apt install -y build-essential libpcre3-dev libssl-dev zlib1g-dev # 2. 下载 nginx 源码(与当前版本严格一致!) wget https://nginx.org/download/nginx-1.24.0.tar.gz tar -zxvf nginx-1.24.0.tar.gz # 3. 下载 vts 模块 git clone https://github.com/vozlt/nginx-module-vts.git # 4. 重新编译 nginx(保留原有配置参数,追加 --add-module) cd nginx-1.24.0 ./configure \ --prefix=/etc/nginx \ --sbin-path=/usr/sbin/nginx \ --modules-path=/usr/lib/nginx/modules \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --pid-path=/var/run/nginx.pid \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --add-module=../nginx-module-vts # 👈 关键:添加 vts 模块 make && sudo make install
配置 vts(核心!)
# nginx.conf 全局块
vhost_traffic_status_zone; # 必须声明,定义共享内存区
http {
# ... 其他 http 配置 ...
# 新增 vts 状态页(prometheus 将从此抓取)
server {
listen 127.0.0.1:8081;
server_name _;
location /status/format/json {
vhost_traffic_status_display;
vhost_traffic_status_display_format json; # 返回 json
}
# 可选:提供 html 可视化界面(调试用)
location /status {
vhost_traffic_status_display;
vhost_traffic_status_display_format html;
}
}
}
重启 nginx 后,访问 http://localhost:8081/status/format/json,你将看到结构化 json(节选):
{
"nginx_version": "1.24.0",
"load_timestamp": 1715823456,
"serverzones": {
"example.com": {
"requestcounter": 12345,
"inbytes": 87654321,
"outbytes": 234567890,
"responses": {
"1xx": 0,
"2xx": 11234,
"3xx": 567,
"4xx": 123,
"5xx": 42
},
"cached": 0,
"uncached": 12345,
"processing": 3,
"connections": {
"active": 3,
"reading": 0,
"writing": 2,
"waiting": 1
}
}
},
"upstreamzones": {
"backend-api": {
"peers": [
{
"server": "10.0.1.10:8080",
"requestcounter": 6789,
"inbytes": 45678901,
"outbytes": 123456789,
"responses": {"1xx":0,"2xx":6234,"3xx":123,"4xx":45,"5xx":12},
"sent": 123456789,
"received": 45678901,
"fails": 0,
"unavail": 0,
"healthchecks": {"checks":123,"fails":0,"unhealthy":0,"lastpassed":1715823455}
}
]
}
}
}关键优势:
- 按
server(虚拟主机)、upstream(后端集群)、peer(具体实例)三级维度统计; - 完整 http 状态码分桶(
1xx,2xx,3xx,4xx,5xx); - 请求/响应字节数、缓存命中率、连接状态;
- 原生支持 prometheus 格式(只需加
location /metrics { vhost_traffic_status_display; vhost_traffic_status_display_format prometheus; }); - 与 openmetrics 规范 100% 兼容,可直接被 prometheus
scrape。
三、prometheus 配置:精准抓取 nginx 指标
prometheus 是指标采集的“心脏”。我们需要确保它能稳定、高效、带上下文地抓取 nginx 指标。
3.1 prometheus 配置文件prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
# 1. 抓取本机 nginx vts 指标(prometheus 格式)
- job_name: 'nginx-vts'
static_configs:
- targets: ['127.0.0.1:8081'] # vts metrics 端口
metrics_path: /status/format/prometheus # 👈 关键:使用 prometheus 格式
relabel_configs:
# 为所有指标添加固定标签,便于多实例区分
- source_labels: [__address__]
target_label: instance
replacement: nginx-prod-main
- target_label: job
replacement: nginx-vts
# 重写指标名前缀(可选,避免与其他 exporter 冲突)
- action: labelmap
regex: __meta_vts_(.+)
# 2. 抓取 prometheus 自身指标(用于监控 prometheus 健康)
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# 3. 抓取 node exporter(服务器基础指标,与 nginx 关联分析)
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']3.2 启动 prometheus 并验证
# 下载 prometheus(略去下载步骤,假设已解压到 /opt/prometheus) cd /opt/prometheus ./prometheus --config.file=prometheus.yml --web.listen-address="0.0.0.0:9090"
打开 http://localhost:9090/targets,确认 nginx-vts job 状态为 up。
在 prometheus 表达式浏览器中输入:
# 查看 nginx 总请求数(按 server zone)
sum by (server) (nginx_vts_server_request_counter_total)
# 查看 5xx 错误率(过去5分钟)
sum(rate(nginx_vts_server_responses_total{code="5xx"}[5m]))
/
sum(rate(nginx_vts_server_request_counter_total[5m]))
# 查看 upstream peer 的失败次数
nginx_vts_upstream_peer_fails_total{upstream="backend-api"}
小技巧:在 prometheus ui 中点击 insert metric at cursor,可自动补全所有可用指标名及标签。
四、grafana 仪表盘:让数据开口说话
grafana 是数据的“翻译官”,将冰冷的数字转化为直观的视觉语言。我们构建一个 nginx 黄金监控仪表盘,覆盖四大核心视角:
4.1 连接健康度(connection health)
反映 nginx 的“呼吸”能力。关键指标:
nginx_vts_server_connections_active:活跃连接数(应远低于worker_connections);nginx_vts_server_connections_reading/writing/waiting:连接各阶段分布;nginx_vts_server_connections_active / nginx_vts_server_worker_connections * 100:连接利用率(>80% 需告警)。

4.2 流量质量(traffic quality)
反映用户请求的“满意度”。核心看板:
- http 状态码热力图:
nginx_vts_server_responses_total按code分组; - top 5 耗时路径:
nginx_vts_server_request_duration_seconds_sum / nginx_vts_server_request_counter_total按path排序; - 缓存命中率:
nginx_vts_server_cache_hits_total / (nginx_vts_server_cache_hits_total + nginx_vts_server_cache_misses_total)。
4.3 上游稳定性(upstream stability)
反映后端服务的“可靠性”。重点监控:
nginx_vts_upstream_peer_fails_total:单个 peer 失败次数(突增即故障);nginx_vts_upstream_peer_unavail_total:peer 不可用次数(连续失败触发max_fails);nginx_vts_upstream_peer_health_checks_fails_total:健康检查失败数。
4.4 服务器资源关联(server correlation)
将 nginx 指标与底层资源关联,定位根因:
- nginx
active connectionsvs node exporternode_memory_memavailable_bytes; - nginx
5xx ratevsnode_load1(cpu 过载); - nginx
request durationvsnode_network_receive_bytes_total(网卡瓶颈)。
五、java 应用集成:打通“应用层 → nginx 层”可观测链路
监控的价值,在于缩短 mttr(平均修复时间)。当 nginx 报出大量 502 bad gateway,开发最需要知道:“是哪个 java 微服务挂了?它的 jvm gc 是否频繁?线程池是否耗尽?”
为此,我们编写一个 spring boot 应用,主动暴露自身健康指标,并与 nginx 的 upstream 状态联动。
5.1 spring boot 应用(user-service)
// pom.xml 关键依赖
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>io.micrometer</groupid>
<artifactid>micrometer-registry-prometheus</artifactid>
</dependency>
<!-- 添加 actuator,暴露 /actuator/prometheus -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-actuator</artifactid>
</dependency>
</dependencies>// src/main/java/com/example/usercontroller.java
@restcontroller
@requestmapping("/api/v1/users")
public class usercontroller {
private final meterregistry meterregistry;
private final counter errorcounter;
public usercontroller(meterregistry meterregistry) {
this.meterregistry = meterregistry;
// 自定义错误计数器,带业务维度
this.errorcounter = counter.builder("user.service.errors")
.description("count of business errors in user service")
.tag("type", "database_timeout") // 可扩展为 network, cache, auth...
.register(meterregistry);
}
@getmapping("/{id}")
public responseentity<user> getuser(@pathvariable long id) {
try {
// 模拟数据库查询(可能超时)
user user = fetchuserfromdb(id);
return responseentity.ok(user);
} catch (databasetimeoutexception e) {
// 记录业务错误,同时触发 nginx 502(若上游超时)
errorcounter.increment();
// 记录到 micrometer,会被 prometheus 抓取
meterregistry.counter("user.db.timeout.total", "service", "user-service").increment();
return responseentity.status(500).build();
}
}
private user fetchuserfromdb(long id) throws databasetimeoutexception {
// 模拟随机超时(用于测试告警)
if (math.random() > 0.95) {
throw new databasetimeoutexception("simulated db timeout");
}
return new user(id, "john doe", "john@example.com");
}
}
// 自定义异常
class databasetimeoutexception extends runtimeexception {
public databasetimeoutexception(string msg) {
super(msg);
}
}# application.yml
management:
endpoints:
web:
exposure:
include: health,info,prometheus # 👈 关键:暴露 prometheus 端点
endpoint:
prometheus:
scrape-interval: 15s
# 暴露 actuator 端点在 /actuator
server:
port: 8080启动后,访问 http://localhost:8080/actuator/prometheus,可见:
# help user_service_errors count of business errors in user service
# type user_service_errors counter
user_service_errors{type="database_timeout",} 3.0
# help user_db_timeout_total
# type user_db_timeout_total counter
user_db_timeout_total{service="user-service",} 3.0
5.2 nginx 配置:将 java 应用注册为 upstream
# nginx.conf
upstream backend-api {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
# 可添加更多实例实现负载均衡
# server 10.0.1.11:8080;
}
server {
listen 80;
server_name example.com;
location /api/ {
proxy_pass http://backend-api;
proxy_set_header host $host;
proxy_set_header x-real-ip $remote_addr;
# 关键:传递原始请求路径,vts 会自动记录
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
# 设置超时,避免长连接拖垮 nginx
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 启用健康检查(vts 会自动采集)
health_check interval=5 rise=2 fall=3;
}
}
5.3 关联查询:nginx 5xx 与 java 应用错误率
在 grafana 中,创建一个 跨数据源查询面板(需配置好 java 应用的 prometheus 数据源):
// nginx 层 5xx 错误率(过去5分钟)
sum(rate(nginx_vts_server_responses_total{code="5xx", server="example.com"}[5m]))
/
sum(rate(nginx_vts_server_request_counter_total{server="example.com"}[5m]))
// java 应用层 db 超时错误率(过去5分钟)
sum(rate(user_db_timeout_total{service="user-service"}[5m]))
/
sum(rate(http_server_requests_seconds_count{application="user-service"}[5m]))
当两条曲线同步飙升,即可 100% 确认:问题根因在 user-service 的数据库访问层,而非 nginx 配置或网络。这就是可观测性的威力!
六、告警规则:从“看见”到“行动”
监控的终点不是图表,而是自动化响应。我们定义三条高价值告警规则,写入 alert.rules.yml:
groups:
- name: nginx-alerts
rules:
# 规则1:nginx 连接耗尽风险(紧急!)
- alert: nginxconnectionexhaustionwarning
expr: |
(nginx_vts_server_connections_active{server="example.com"}
/ nginx_vts_server_worker_connections{server="example.com"}) * 100 > 80
for: 2m
labels:
severity: warning
team: infra
annotations:
summary: "nginx connection usage > 80% on {{ $labels.instance }}"
description: "active connections: {{ $value }}%. check upstream latency or increase worker_connections."
# 规则2:上游服务全宕机(严重!)
- alert: upstreamalldown
expr: |
count by (upstream) (
nginx_vts_upstream_peer_state{upstream="backend-api", state="down"}
) == count by (upstream) (
nginx_vts_upstream_peer_state{upstream="backend-api"}
)
for: 1m
labels:
severity: critical
team: backend
annotations:
summary: "all peers down in upstream {{ $labels.upstream }}"
description: "no healthy backend instances available. immediate investigation required!"
# 规则3:5xx 错误率突增(注意!)
- alert: highnginx5xxrate
expr: |
sum(rate(nginx_vts_server_responses_total{code="5xx", server="example.com"}[5m]))
/
sum(rate(nginx_vts_server_request_counter_total{server="example.com"}[5m])) > 0.05
for: 3m
labels:
severity: warning
team: sre
annotations:
summary: "5xx error rate > 5% for 3 minutes on {{ $labels.instance }}"
description: "current rate: {{ $value | humanize }}%. correlate with upstream and application metrics."6.1 alertmanager 配置(alertmanager.yml)
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'team']
group_wait: 30s
group_interval: 5m
repeat_interval: 1h
receiver: 'wechat-notifications'
receivers:
- name: 'wechat-notifications'
wechat_configs:
- send_resolved: true
api_url: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your_webhook_key' # 替换为你的企业微信机器人 key
message: |
{{ define "__text_alert_list" }}{{ range .alerts }}
[{{ .labels.severity }}] {{ .labels.alertname }}
{{ .annotations.summary }}
{{ .annotations.description }}
details: {{ .generatorurl }}
{{ end }}{{ end }}
{{ if gt (len .alerts.firing) 0 -}}
🔥 firing:
{{ template "__text_alert_list" .alerts.firing }}
{{ end }}
{{ if gt (len .alerts.resolved) 0 -}}
✅ resolved:
{{ template "__text_alert_list" .alerts.resolved }}
{{ end }}启动 alertmanager:
./alertmanager --config.file=alertmanager.yml --web.external-url=http://localhost:9093
并在 prometheus.yml 中关联:
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']现在,当 nginx 连接数超过阈值,你将立即收到企业微信消息,包含精确的指标值、触发时间、建议操作,无需登录服务器排查。真正的“告警即工单” 📝。
七、进阶实践:nginx ingress controller 监控(kubernetes 场景)
如果你在 kubernetes 中使用 nginx-ingress-controller,监控逻辑完全一致,只需调整抓取目标:
7.1 启用 ingress controller 的 prometheus 指标
# helm install ingress-nginx ingress-nginx/ingress-nginx \ # --set controller.metrics.enabled=true \ # --set controller.metrics.servicemonitor.enabled=true \ # --set controller.stats.enabled=true
ingress controller 会暴露 /metrics 端点(prometheus 格式),指标前缀为 nginx_ingress_controller_*,例如:
nginx_ingress_controller_requests_total(按controller_class,namespace,ingress,status_code等标签)nginx_ingress_controller_nginx_process_cpu_seconds_totalnginx_ingress_controller_ssl_expire_time_seconds
7.2 关键 promql 查询示例
# 查看所有 ingress 的 5xx 错误率(按 namespace 分组)
sum by (namespace, ingress) (
rate(nginx_ingress_controller_requests_total{status=~"5.."}[5m])
)
/
sum by (namespace, ingress) (
rate(nginx_ingress_controller_requests_total[5m])
)
# 检测 ssl 证书即将过期(< 7 天)
min by (host) (
nginx_ingress_controller_ssl_expire_time_seconds - time()
) < 604800
八、性能与安全最佳实践
一套生产级监控系统,必须兼顾性能与安全:
8.1 性能调优
vts 共享内存大小:在 nginx.conf 中设置 vhost_traffic_status_zone shared:vts:10m;,根据虚拟主机数量调整(1m ≈ 100 个 server zone);
prometheus 抓取间隔:nginx 指标变化平缓,scrape_interval: 30s 足够,降低 nginx 压力;
指标过滤:在 relabel_configs 中丢弃无用标签,减少 prometheus 存储压力:
- action: labeldrop regex: "(exported_instance|job)"
8.2 安全加固
- nginx vts 端口仅限内网:
listen 127.0.0.1:8081;或listen 10.0.0.0/8:8081;,禁止公网暴露; - prometheus 认证:通过 nginx 反向代理 + basic auth 保护
/metrics端点; - alertmanager webhook 限制:企业微信机器人 key 仅在 alertmanager 配置中使用,禁止硬编码到代码中。
8.3 高可用设计
- prometheus ha:部署两个 prometheus 实例,使用
--web.enable-admin-api+ 外部存储(如 thanos); - grafana ha:使用 postgresql 作为后端存储,多个 grafana 实例共享仪表盘;
- nginx vts 无单点:每个 nginx 实例独立暴露指标,prometheus 通过服务发现自动抓取。
九、总结:构建你的 nginx 可观测性护城河
回顾全文,我们完成了一套端到端、生产就绪、开箱即用的 nginx 监控告警体系:
| 层级 | 技术组件 | 解决的问题 | 价值 |
|---|---|---|---|
| 数据采集层 | nginx + nginx-module-vts | 暴露全维度、标准化、openmetrics 兼容指标 | ✅ 告别日志 grep,拥抱实时聚合 |
| 指标存储层 | prometheus | 高效抓取、存储、查询时间序列数据 | ✅ 亚秒级查询,pb 级数据支持 |
| 可视化层 | grafana | 将指标转化为多维度、可交互、可分享的仪表盘 | ✅ sre/devops 一眼掌握全局 |
| 告警响应层 | alertmanager + 企业微信 | 基于规则的自动化通知与静默 | ✅ 从“被动救火”转向“主动防御” |
| 应用协同层 | spring boot + micrometer | java 应用主动暴露业务指标 | ✅ 打通 nginx 与业务层,根因定位时间缩短 70% |
这不仅是技术栈的组合,更是一种运维哲学的升级:
- 从“经验驱动”到“数据驱动” —— 不再说“我觉得 nginx 慢”,而是展示“
p95 request duration从 120ms 升至 850ms”; - 从“单点排查”到“全链路追踪” —— 当
5xx上升,一键下钻到upstream peer fails,再跳转到user-service的db timeout指标; - 从“救火队员”到“系统守护者” —— 告警规则提前预警连接耗尽,你在故障发生前就扩容了
worker_connections。
现在,是时候打开你的终端,敲下第一行 nginx -t && nginx -s reload,然后刷新 http://localhost:9090/graph —— 看着那些代表 nginx 生命体征的曲线平稳跃动,你会真切感受到:掌控感,从未如此清晰 。
本文所有技术方案均基于开源、标准、可审计的组件,无任何商业闭源依赖。愿你构建的每一行配置,都成为系统稳定运行的基石;愿你定义的每一条告警,都在故障发生前悄然亮起红灯。监控不是终点,而是通往更高可靠性的起点。
以上就是nginx结合prometheus+grafana实现监控告警的实战指南的详细内容,更多关于nginx监控告警的资料请关注代码网其它相关文章!
发表评论