动态会话日志记录 ngx_stream_log_module

一、引言

在使用 NGINX Stream 模块处理 TCP/UDP 会话时,我们常常需要记录每次连接的关键指标(如客户端 IP、会话时长、收发字节数等),便于后续的审计、监控和故障排查。ngx_stream_log_module 就是专门为此设计的,它允许你以自定义格式记录 TCP/UDP 会话日志,并提供了缓冲写入文件描述符缓存等多种优化手段。

本文将以零基础、一步步的方式,带你从环境准备、模块验证,到配置示例、测试验证,再到常见故障排查,全面掌握 ngx_stream_log_module

二、模块概览

  • 模块名称ngx_stream_log_module

  • 首次引入:NGINX 1.11.4

  • 作用:为 Stream(TCP/UDP)会话写入日志,支持自定义格式、日志缓冲、压缩及条件记录。

  • 核心指令

    • log_format:定义日志格式
    • access_log:开启会话日志并指定格式、路径、缓冲、压缩、条件等
    • open_log_file_cache:为带变量的日志路径缓存文件描述符

三、典型场景

  1. 数据库代理审计
    记录来自各客户端 IP 的 MySQL/TCP 连接时长和流量,用于安全审计。
  2. 实时流量监控
    对 Redis、Kafka 等服务的 TCP 会话进行统计,监测异常流量突增。
  3. 故障定位
    当下游服务异常时,通过 $status$session_time 等指标快速定位问题来源。

四、先决条件

  1. NGINX 支持 Stream 模块
    请确保在编译或安装时包含了 --with-stream 参数。

  2. 确认已编译或加载 ngx_stream_log_module

    nginx -V 2>&1 | grep --color stream_log
    
  3. 日志目录准备
    为防止权限问题,建议提前创建并设置好目录权限:

    sudo mkdir -p /spool/logs
    sudo chown nginx:nginx /spool/logs
    

五、指令详解

1. log_format

log_format name [escape=default|json|none] string ...;
  • name:日志格式名称,用于 access_log 引用。
  • escape:可选 default(转义控制字符)、json(JSON 专用转义)、none(不转义)。
  • string:日志模板,支持内嵌多个变量,如 $remote_addr$session_time 等。

内置变量示例

变量含义
$remote_addr客户端 IP 地址
$time_local本地时间(日志记录时刻)
$protocol会话使用的协议(如 TCP/UDP)
$status连接结束状态码(0 表示正常)
$bytes_sent发送给客户端的总字节数
$bytes_received从客户端接收的总字节数
$session_time会话时长,单位秒(带毫秒精度)

2. access_log

access_log path format 
           [buffer=size] 
           [gzip[=level]] 
           [flush=time] 
           [if=condition];
access_log off;
  • path:日志文件路径,可写死也可包含变量(见 open_log_file_cache)。
  • format:引用 log_format 定义的格式名。
  • buffer:启用缓冲写入,单位字节(如 32k);不超过系统原子写入大小。
  • gzip:启用压缩写入,可选 =1..9 压缩级别;需编译时链接 zlib。
  • flush:最大刷新间隔(如 5m),超时或缓冲满后写盘。
  • if:条件表达式;当条件为“0”或空字符串时,跳过本次日志记录。

3. open_log_file_cache

open_log_file_cache max=N 
                    [inactive=time] 
                    [min_uses=N] 
                    [valid=time];
open_log_file_cache off;
  • max:缓存的最大文件描述符数量(LRU 关闭最少使用的)。
  • inactive:若某文件在此时长内未被访问,则关闭描述符(默认 10s)。
  • min_uses:在 inactive 时间内最少使用次数,低于则不缓存(默认 1)。
  • valid:每隔该时长检查文件名是否仍指向同一文件(默认 60s)。

六、配置示例(一步一步)

以下示例演示如何在 Stream 模块中记录会话日志,并对日志性能进行优化。

  1. stream { ... } 块外全局定义文件描述符缓存

    stream {
        # 缓存最多 1000 个文件描述符,20s 不活跃则关闭,文件存在校验 1m,至少访问 2 次才缓存
        open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
        …
    }
    
  2. 定义日志格式

    stream {
        log_format basic '$remote_addr [$time_local] '
                         '$protocol $status $bytes_sent $bytes_received '
                         '$session_time';
        …
    }
    
  3. 开启会话日志

    stream {
        # 将日志缓冲到 32KB,5 分钟或满缓冲时写盘
        access_log /spool/logs/nginx-access.log basic buffer=32k flush=5m;
        …
    }
    
  4. 启用压缩(可选)

    stream {
        # 以 gzip 压缩(级别 2),缓冲同上
        access_log /spool/logs/nginx-access.log.gz basic gzip=2 buffer=64k flush=5m;
        …
    }
    
  5. 条件日志(可选)

    stream {
        # 仅记录时长超过 10 秒的会话
        access_log /spool/logs/long-sessions.log basic if=$session_time\>10;
        …
    }
    

完整示例整合:

stream {
    # 1. 文件描述符缓存
    open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;

    # 2. 日志格式
    log_format basic '$remote_addr [$time_local] '
                     '$protocol $status $bytes_sent $bytes_received '
                     '$session_time';

    # 3. 普通日志:32k 缓冲,5m 刷新
    access_log /spool/logs/nginx-access.log basic buffer=32k flush=5m;

    # 4. 压缩日志:64k 缓冲,gzip 2,5m 刷新
    access_log /spool/logs/nginx-access.log.gz basic gzip=2 buffer=64k flush=5m;

    # 5. 仅记录长会话(>10s)
    access_log /spool/logs/long-sessions.log basic if=$session_time\>10;

    server {
        listen     3306;      # 例如:MySQL 代理
        proxy_pass backend:3306;
    }
}

七、测试与验证

  1. 重载配置

    sudo nginx -t && sudo systemctl reload nginx
    
  2. 模拟 TCP 会话
    使用 openssl s_clientnc 建立连接并发送少量数据:

    # 简单测试:连接后等待 2 秒再关闭
    { echo -n ''; sleep 2; } | nc example.com 3306
    
  3. 查看日志

    tail -n20 /spool/logs/nginx-access.log
    

    应看到类似:

    192.168.1.10 [12/May/2025:10:30:00 +0000] tcp 0 0 2.001
    

    表示 IP、协议、状态、字节数与时长。

八、常见问题与排查

问题排查思路
日志不生成- 确认 access_log 是否在 streamserver 上下文中
- 检查 NGINX error.log
缓冲后长时间未写盘- 检查 flush 设置是否过大
- 缓冲区是否未满
- 触发重载时会主动写盘
gzip 日志无法解压- 确认 NGINX 编译时已链接 zlib
- 使用 zcatgunzip -t 测试
带变量路径日志无缓存(频繁打开/关闭)- open_log_file_cache 是否已配置
- min_usesinactive 参数是否合理

九、最佳实践

  1. 预分配缓冲:根据日志量合理设置 buffer,避免频繁写盘。
  2. 压缩归档:对历史日志使用 gzip,节省磁盘空间,并可随时通过 zcat 查看。
  3. 文件描述符缓存:当日志路径含变量时,务必开启 open_log_file_cache,减少系统调用开销。
  4. 条件记录:对关键会话(如长连接、大流量)单独出日志,便于聚焦排查。
  5. 定期清理:通过外部脚本或 logrotate 管理日志文件,避免目录爆满。

十、总结

ngx_stream_log_module 为 NGINX Stream 模块提供了灵活、高性能的会话日志能力。

  • 格式定义日志输出缓冲与压缩、到 文件描述符缓存,覆盖了日志记录的全生命周期。
  • 通过 条件记录压缩归档 等功能,兼顾了性能与可用性。

掌握本篇内容后,你即可在 TCP/UDP 代理、数据库中间件、微服务网关等各类场景中,轻松实现精准、可扩展的会话日志记录。祝部署顺利,运维轻松!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello.Reader

请我喝杯咖啡吧😊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值