使用 SkyWalking 监控 Nginx

SkyWalking 9.7 引入了新的 Nginx 监控面板,本文将演示该监控面板的使用。

By 魏翔 | Saturday, December 23, 2023 原文

背景介绍

在前面的 Blog 使用 LAL 收集并分析 Nginx access log 中,我们以 Nginx access log 为切入点, 演示了 SkyWalking LAL 的日志分析能力。

为了实现对 Nginx 更全面的监控能力,我们在 SkyWalking 9.7 中引入了 Nginx 监控面板,本文将演示该监控面板的使用,并介绍相关指标的含义。

监控面板接入

Metric 定义与采集

由于使用了 nginx-lua-prometheus 来定义及暴露指标, 我们需要为 Nginx 安装 lua_nginx_module, 或者直接使用OpenResty。

下面的例子中,我们通过 nginx-lua-prometheus 定义了四个指标,并通过 ip:9145/metrics 暴露指标接口:

  • histogram: nginx_http_latency,监控 http 延时
  • gauge: nginx_http_connections,监控 http 连接数
  • counter: nginx_http_size_bytes,监控 http 请求和响应大小
  • counter: nginx_http_requests_total,监控 http 请求次数
dart 复制代码
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    lua_shared_dict prometheus_metrics 10M;
    # lua_package_path "/path/to/nginx-lua-prometheus/?.lua;;";

    init_worker_by_lua_block {
      prometheus = require("prometheus").init("prometheus_metrics")

      metric_bytes = prometheus:counter(
        "nginx_http_size_bytes", "Total size of HTTP", {"type", "route"})
      metric_requests = prometheus:counter(
        "nginx_http_requests_total", "Number of HTTP requests", {"status", "route"})
      metric_latency = prometheus:histogram(
        "nginx_http_latency", "HTTP request latency", {"route"})
      metric_connections = prometheus:gauge(
        "nginx_http_connections", "Number of HTTP connections", {"state"})
    }

    server {
        listen 8080;

        location /test {
          default_type application/json;
          return 200  '{"code": 200, "message": "success"}';

          log_by_lua_block {
            metric_bytes:inc(tonumber(ngx.var.request_length), {"request", "/test/**"})
            metric_bytes:inc(tonumber(ngx.var.bytes_send), {"response", "/test/**"})
            metric_requests:inc(1, {ngx.var.status, "/test/**"})
            metric_latency:observe(tonumber(ngx.var.request_time), {"/test/**"})
          }
        }
    }

    server {
      listen 9145;
      location /metrics {
        content_by_lua_block {
          metric_connections:set(ngx.var.connections_reading, {"reading"})
          metric_connections:set(ngx.var.connections_waiting, {"waiting"})
          metric_connections:set(ngx.var.connections_writing, {"writing"})
          prometheus:collect()
        }
      }
    }
}

上面的例子中,我们暴露了 route 级别的指标,你也可以根据监控粒度的需要,选择暴露 host 指标:

css 复制代码
http {
  log_by_lua_block {
      metric_bytes:inc(tonumber(ngx.var.request_length), {"request", ngx.var.host})
      metric_bytes:inc(tonumber(ngx.var.bytes_send), {"response", ngx.var.host})
      metric_requests:inc(1, {ngx.var.status, ngx.var.host})
      metric_latency:observe(tonumber(ngx.var.request_time), {ngx.var.host})
  }
}

或者 upstream 指标:

css 复制代码
upstream backend {
  server ip:port;
}

server {
  
  location /test_upstream {
  
    proxy_pass http://backend;
  
    log_by_lua_block {
      metric_bytes:inc(tonumber(ngx.var.request_length), {"request", "upstream/backend"})
      metric_bytes:inc(tonumber(ngx.var.bytes_send), {"response", "upstream/backend"})
      metric_requests:inc(1, {ngx.var.status, "upstream/backend"})
      metric_latency:observe(tonumber(ngx.var.request_time), {"upstream/backend"})
    }
  }
}

完成指标定义后,我们启动 nginx 和 opentelemetry-collector,将指标采集到 SkyWalking 后端进行分析和存储。

请确保job_name: 'nginx-monitoring',否则上报的数据将被 SkyWalking 忽略。如果你有多个 Nginx 实例,你可以通过service及service_instance_id这两个 label 进行区分:

yaml 复制代码
receivers:
  prometheus:
    config:
      scrape_configs:
        - job_name: 'nginx-monitoring'
          scrape_interval: 5s
          metrics_path: "/metrics"
          static_configs:
            - targets: ['nginx:9145']
              labels:
                service: nginx
                service_instance_id: nginx-instance
processors:
  batch:

exporters:
  otlp:
    endpoint: oap:11800
    tls:
      insecure: true
service:
  pipelines:
    metrics:
      receivers:
        - prometheus
      processors:
        - batch
      exporters:
        - otlp

如果一切顺利,你将在 skywalking-ui 的网关菜单下看到 nginx 上报的指标数据:

Access & Error Log 采集

SkyWalking Nginx 监控提供了日志采集及错误日志统计功能,我们可以借助 fluent-bit 采集并上报 access log、error log 给 SkyWalking 分析存储。

下面 fluent-bit 配置定义了日志采集目录为/var/log/nginx/,access 和 error log 经过 rewrite_access_log 和 rewrite_error_log 处理后会通过 oap 12800 端口进行上报:

csharp 复制代码
[SERVICE]
    Flush          5
    Daemon         Off
    Log_Level      warn
[INPUT]
    Name           tail
    Tag            access
    Path           /var/log/nginx/access.log
[INPUT]
    Name           tail
    Tag            error
    Path           /var/log/nginx/error.log
[FILTER]
    Name           lua
    Match          access
    Script         fluent-bit-script.lua
    Call           rewrite_access_log
[FILTER]
    Name           lua
    Match          error
    Script         fluent-bit-script.lua
    Call           rewrite_error_log
[OUTPUT]
    Name            stdout
    Match           *
    Format          json
[OUTPUT]
    Name            http
    Match           *
    Host            oap
    Port            12800
    URI             /v3/logs
    Format          json

在 fluent-bit-script.lua 中,我们通过 LOG_KIND 来区分 access log 和 error log。

为了能够关联上文采集的 metric,请确保 service 和 serviceInstance 值与上文中指标采集定义一致。

lua 复制代码
function rewrite_access_log(tag, timestamp, record)
    local newRecord = {}
    newRecord["layer"] = "NGINX"
    newRecord["service"] = "nginx::nginx"
    newRecord["serviceInstance"] = "nginx-instance"
    newRecord["body"] = { text = { text = record.log } }
    newRecord["tags"] = { data = {{ key = "LOG_KIND", value = "NGINX_ACCESS_LOG"}}}
    return 1, timestamp, newRecord
end

function rewrite_error_log(tag, timestamp, record)
    local newRecord = {}
    newRecord["layer"] = "NGINX"
    newRecord["service"] = "nginx::nginx"
    newRecord["serviceInstance"] = "nginx-instance"
    newRecord["body"] = { text = { text = record.log } }
    newRecord["tags"] = { data = {{ key = "LOG_KIND", value = "NGINX_ERROR_LOG" }}}
    return 1, timestamp, newRecord
end

启动 fluent-it 后,我们便可以在监控面板的 Log tab 看到采集到的日志信息:

面板指标含义

面板名称 单位 指标含义 数据源
HTTP Request Trend 每秒钟平均请求数 nginx-lua-prometheus
HTTP Latency ms 平均响应延时 nginx-lua-prometheus
HTTP Bandwidth KB 请求响应流量 nginx-lua-prometheus
HTTP Connections nginx http 连接数 nginx-lua-prometheus
HTTP Status Trend % 每分钟 http 状态码统计 nginx-lua-prometheus
HTTP Status 4xx Percent % 4xx状态码比例 nginx-lua-prometheus
HTTP Status 5xx Percent % 5xx状态码比例 nginx-lua-prometheus
Error Log Count 每分钟错误日志数统计 fluent-bit

参考文档

相关推荐
分布式存储与RustFS2 小时前
群晖 NAS 被 C3RB3R 锁了:本地备份一起被加密,RustFS 对象锁为什么删不掉
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
真好啊又活了一天3 小时前
服务器和虚机配置IPV6
运维·服务器·github
zixu_star3 小时前
定时任务是什么?从日常自动化到 AI 应用,软件如何自动执行任务?
运维·人工智能·自动化
AR-26710-3 小时前
Linux Day33——定时任务+lvm
linux·运维
润滑卫士4 小时前
液压系统工作粘度窗口等级选型:泵允许粘度范围与油温-粘度匹配计算
运维
每月一号准时摆烂7 小时前
服务器运维笔记(一)——使用shell编写实时查看BMC功率的脚本
运维·服务器·笔记
时间售卖铺7 小时前
Chrony与SSH实战:精准时间同步与安全远程登录
运维·安全·云原生·ssh
微订校园外卖系统8 小时前
校园代取快递系统选型:现成系统与定制开发的技术核对项
大数据·运维·人工智能·外卖系统·本地生活·微订
QXWZ_IA8 小时前
管道GIS测绘如何实现自动化成图:三种成图方式怎么选
运维·人工智能·安全·自动化
一条破秋裤8 小时前
【1112】Linux中断【整理】
linux·运维·服务器