Nginx $msec 仅支持毫秒级精度,需结合 Lua 模块在 log_by_lua_block 中调用 ngx.now() 获取纳秒级时间并截取微秒部分(如 456789),再通过自定义变量 $lua_usec 写入日志,与 $msec 拼接实现微秒级绝对时间戳,支撑网关安全路径各环节耗时精准比对。

Nginx 的 $msec 变量本身只提供毫秒级精度(小数点后三位),无法直接输出微秒级时间戳。要实现微秒级高精度绝对时间戳用于网关层安全路径请求的损耗比对,需结合系统时间、Nginx 配置与日志格式定制,并注意时钟源一致性。
理解 $msec 的局限性与替代方案
$msec 是 Nginx 内置变量,值为当前时间的秒数 + 毫秒小数(如 1718234567.123),底层调用 gettimeofday() 或 clock_gettime(CLOCK_MONOTONIC),但 Nginx 日志模块默认仅保留毫秒位,不支持原生微秒输出。真正微秒级时间需:
- 启用
log_format中的$msec并配合log_subrequest on确保子请求(如 auth_request)也记录时间 - 在编译 Nginx 时启用高精度时钟支持(如
--with-cc-opt="-DNGX_HAVE_CLOCK_MONOTONIC"),但即便如此,$msec仍不输出微秒位 - 更可行的方式是:使用
$time_iso8601或$time_local配合$msec拆解拼接,或借助 Lua 模块注入微秒值
通过 Lua 模块注入微秒级时间戳(推荐)
若已部署 nginx-lua-module(OpenResty),可在 log_by_lua_block 中获取纳秒级时间并截取微秒部分,写入自定义变量供日志使用:
- 在
http块中定义 log_format,预留占位符:log_format trace_log '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time $upstream_response_time $msec $lua_usec'; - 在
server或location中添加:set $lua_usec "-";<br> log_by_lua_block {<br> local t = ngx.now()<br> local sec, nsec = math.modf(t)<br> local usec = math.floor(nsec * 1000000) % 1000000<br> ngx.var.lua_usec = string.format("%06d", usec)<br> } - 最终日志行示例:
10.1.2.3 - - [12/Jul/2024:15:23:45 +0000] "GET /api/auth/check HTTP/1.1" 200 123 "-" "curl/7.68" 0.002 0.001 1718234567.123 456789
其中456789即微秒部分,与$msec的1718234567.123组合可还原为1718234567.123456
安全路径损耗比对的关键实践
针对网关层安全校验(如 JWT 解析、RBAC 权限检查、WAF 规则匹配)的耗时分析,需确保时间采集点覆盖完整链路:
- 在
access_by_lua_block开始前记录入口时间(如ngx.ctx.start_ts = ngx.now()) - 在
auth_request子请求返回后、主请求继续前,用$upstream_response_time获取认证服务耗时 - 在
log_by_lua_block中计算各阶段差值:local auth_cost = ngx.var.upstream_response_time or 0<br> local total_cost = ngx.now() - ngx.ctx.start_ts<br> ngx.var.log_auth_cost = string.format("%.6f", auth_cost)<br> ngx.var.log_total_cost = string.format("%.6f", total_cost) - 将这些变量写入日志,配合微秒时间戳,即可精确比对「请求到达网关 → 安全校验完成 → 转发上游」各环节损耗
注意事项与精度保障
微秒级时间戳的价值依赖于系统环境与配置协同:
- 确保 Nginx 进程运行在启用
CLOCK_MONOTONIC的内核上(Linux ≥ 2.6.28),避免时钟回拨干扰 - 禁用 NTP 步进式校正(使用
ntpd -x或chronyd -s),改用平滑调整,防止时间跳变 - 若未使用 Lua,可用
$msec+$request_time粗略估算:例如$msec记录入口时间,$request_time是总耗时,二者相加得出口近似时间(误差在毫秒级) - 日志采集端(如 Filebeat / Fluentd)需关闭时间解析覆盖,直接透传原始时间字段,避免二次转换损失精度


















