$upstream_bytes_received 在 stream 模块中不可用,因其仅存在于 http 模块;stream 模块应使用 $bytes_sent 统计后端返回客户端的下行流量,配合 $bytes_received 获取上行数据,二者共同构成四层代理流量监控基础。

在四层(L4)Stream 模块中,$upstream_bytes_received 并不可用 —— 这是关键前提。它仅存在于 HTTP 模块的 upstream 变量中,而 Stream 模块不支持该变量,也不解析应用层协议,因此无法直接获取后端返回的字节数。
为什么 $upstream_bytes_received 在 Stream 中无效
NGINX Stream 模块工作在 TCP/UDP 层,不解析内容,不维护 HTTP 语义,所有 upstream 变量如 $upstream_bytes_received、$upstream_response_time 等均未定义。尝试使用会导致空值或启动报错(如 “unknown variable”)。
若配置中出现:
log_format stream_log "bytes_up: $bytes_sent bytes_down: $upstream_bytes_received";其中 $upstream_bytes_received 始终为空或 0,无法用于统计数据库下行流量。
替代方案:用 $bytes_received 统计客户端发给 NGINX 的数据量
Stream 模块提供真实可用的变量:
-
$bytes_received:客户端发送到 NGINX 的字节数(即“上行”,含 SQL 请求等) -
$bytes_sent:NGINX 发送给客户端的字节数(即“下行”,含查询结果集)
对数据库集群而言,$bytes_sent 就是你能可靠获取的“下行流量”近似值——它代表从后端数据库经 NGINX 返回给客户端的数据总量,正是你要统计的目标。
示例日志格式:
log_format db_stream 'time:$time_iso8601 client:$remote_addr db:$upstream_addr sent:$bytes_sent received:$bytes_received';精确统计后端真实下行流量的进阶方法
若需严格区分“NGINX→客户端”与“后端→NGINX”的字节(例如排除 NGINX 自身开销或做 per-backend 聚合),需借助外部工具或改造链路:
-
TCP 抓包 + 流量标记:在数据库服务器出口抓包(如
tcpdump -i eth0 port 3306 -w db_out.pcap),用tshark过滤并统计 server→proxy 方向的 payload 字节数 -
数据库侧主动上报:MySQL 可开启 performance_schema 或使用慢日志 +
Rows_examined/Bytes_sent;PostgreSQL 启用log_line_prefix加%b(backend start time)配合自定义日志解析 - 旁路镜像 + 流量分析系统:将 Stream 的 upstream 流量镜像到流量分析器(如 Zeek/Bro、nfdump),按连接五元组聚合后端响应字节数
注意事项与常见误判
避免把 $bytes_sent 当作后端网卡出向流量的完全等价——它包含 NGINX 内部缓冲、TLS 开销(若启用了 ssl_preread)、以及可能的协议封装字节(如 MySQL 协议头)。实际偏差通常
另外注意:
- Stream 日志默认只在连接关闭时写入,若需实时性,启用
flush=1s - 确保
log_format定义在stream{}块内,且access_log指向有效路径 - 数据库长连接会延迟日志输出,统计周期建议以分钟级聚合,而非单次请求











