使用 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 实例,你可以通过serviceservice_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_logrewrite_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

参考文档

相关推荐
来鸟 鸣间8 小时前
Linux下3个so库之间的关系
linux·运维
释怀不想释怀8 小时前
Linux文件上传(rz)和下载(sz)压缩(tar.gz)和解压(zip)
linux·运维·服务器
IOsetting8 小时前
金山云主机添加开机路由
运维·服务器·开发语言·网络·php
酉鬼女又兒8 小时前
零基础入门Linux指南:每天一个Linux命令_sed
linux·运维·服务器
-dcr8 小时前
58.DevOps进阶
运维·devops
猫头虎8 小时前
如何使用Docker部署OpenClaw汉化中文版?
运维·人工智能·docker·容器·langchain·开源·aigc
XiaoMu_0018 小时前
自动化漏洞扫描与预警平台
运维·网络·自动化
醉风塘8 小时前
Linux进程管理:深度解析ps -ef命令及其高级应用
linux·运维·服务器
会周易的程序员9 小时前
openplc runtimev4 Docker 部署
运维·c++·物联网·docker·容器·软件工程·iot
陈桴浮海9 小时前
【Linux&Ansible】学习笔记合集三
linux·运维·云原生·ansible