前段时间接到一个需求,希望可以监控 Nginx 的运行状态。
我们都知道 Nginx 作为一个流行的 Web 服务器提供了多种能力,包括反向代理、负载均衡;也支持了许多协议,包括:
gRPC
http
WebSocket 等 作为一个流量入口的中间件,对其的监控就显得至关重要了。
市面上也有一些现成的产品可以监控 Nginx,比如知名的监控服务商 datadog
也提供了 Nginx 的监控。

但是我这是一个内网服务,并不能使用这些外部的云厂商,所有就只能在内部搭建 Nginx 的监控服务了。
不过 Nginx 默认情况下并没有提供 /metrics
的 endpoint,但好在它提供了一个额外的模块:stub_status
可以用于获取监控数据。
server {
listen 80;
server_name _;
location /status {
stub_status on;
access_log off;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
这样访问
http://127.0.0.1:80/status
就可以拿到一些基本的运行数据。
但这个格式明显不是 Prometheus 所支持的 metrics 格式,无法直接将数据采集到 Prometheus 中然后通过 Grafana 进行查看。
所以还得需要一个中间层来将这些数据转换为 Prometheus 可以接收的 metrics 数据。
nginx-prometheus-exporter
好在社区已经提供了类似的工具:nginx-prometheus-exporter 它读取刚才 status endpoint 所暴露的数据,然后转换为 Prometheus 格式,并对外提供了一个 /metrics
的 endpoint 供 Prometheus 来采集。
转换数据
我们在启动这个 nginx-exporter
时需要传入刚才 Nginx
暴露的 /status
endpoint。
docker run -p 9113:9113 nginx/nginx-prometheus-exporter:1.1.0 --nginx.scrape-uri=http://<nginx>:8080/stub_status
const templateMetrics string = `Active connections: %d
server accepts handled requests
%d %d %d
Reading: %d Writing: %d Waiting: %d
`
// 读取 Nginx status 数据
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read the response body: %w", err)
}
r := bytes.NewReader(body)
stats, err := parseStubStats(r)
if err != nil {
return nil, fmt.Errorf("failed to parse response body %q: %w", string(body), err)
}
// 解析 Nginx status 数据
func parseStubStats(r io.Reader) (*StubStats, error) {
var s StubStats
if _, err := fmt.Fscanf(r, templateMetrics,
&s.Connections.Active,
&s.Connections.Accepted,
&s.Connections.Handled,
&s.Requests,
&s.Connections.Reading,
&s.Connections.Writing,
&s.Connections.Waiting); err != nil {
return nil, fmt.Errorf("failed to scan template metrics: %w", err)
}
return &s, nil
}
最后会把刚才解析到的数据生成 metrics:
ch <- prometheus.MustNewConstMetric(c.metrics["con