$msec 是 Nginx 内置毫秒级时间变量,格式为秒.毫秒,基于单调时钟实现,精度1ms、无系统调用开销,适用于高频交易低延迟日志;需确保宿主机时间同步、禁用NTP step,并通过JSON或TSV结构化记录,绑定$request_id实现端到端链路追踪。

$msec 是 Nginx 内置的毫秒级时间变量,格式为 秒.毫秒(例如 1715823496.123),它在每次请求处理时动态生成,精度达 1 毫秒,且无系统调用开销,非常适合高频交易场景下的低延迟日志打点。
确保 $msec 精度与稳定性
Nginx 默认启用 $msec,但需注意:它基于 clock_gettime(CLOCK_MONOTONIC, ...)(Linux)或等效高精度时钟,不受系统时间回拨影响。若部署在虚拟机中,应确认宿主机启用了 host time synchronization 并禁用 NTP step 调整,避免 guest clock 漂移导致 $msec 跳变。可通过以下方式验证:
- 在 access_log 中添加
$msec $request_time $upstream_response_time,压测时观察相邻日志的 $msec 差值是否稳定趋近于 1ms - 检查
nginx -V输出是否含--with-clock-gettime(较新版本默认支持)
在 access_log 中结构化记录毫秒时间戳
避免直接拼接字符串造成解析困难,推荐使用 JSON 格式或固定分隔字段:
- JSON 方式(便于 ELK / Splunk 解析):
log_format trading_json '{"ts":$msec,"req_id":"$request_id","method":"$request_method","path":"$uri","status":$status,"rt":$request_time,"urt":$upstream_response_time}'; - TSV 方式(适合 Spark / Presto 批处理):
log_format trading_tsv '$msec\t$request_id\t$request_method\t$uri\t$status\t$request_time\t$upstream_response_time';
注意:$msec 本身不含引号,写入 JSON 时需手动包裹为数字(非字符串),否则下游解析为浮点数会丢失精度 —— 实际使用中建议保留为数字类型,前端或分析层再转为 ISO 时间(如 new Date(Math.floor($msec * 1000)))。
结合 $request_id 实现端到端链路追踪
高频交易要求请求从接入层→风控→撮合→清算的每跳延迟可对齐。需统一注入 X-Request-ID 并透传:
- 在入口 Nginx 生成唯一 ID:
map $request_id $reqid { "" $request_id; }set $request_id $reqid;(配合random或secure_random模块增强唯一性) - 将 $msec 与 $request_id 绑定写入日志后,可在 Flink / Kafka Streams 中按 request_id 分组,计算各环节 $msec 差值,精准识别撮合延迟突增、风控超时等异常模式
规避常见精度陷阱
$msec 是“请求开始时”的时间戳,不是日志写入时刻。在超高并发下,日志缓冲和磁盘 I/O 可能引入几毫秒偏移。若需写入时刻精度:
- 不依赖 access_log,改用 Nginx 的
lua-resty-logger-socket模块,在 Lua handler 中调用ngx.now()(返回同 $msec 精度)并立即发送至本地 UDP 日志收集器 - 或启用
buffered_logs on+flush_timeout 10ms(Nginx 1.21.6+),减少日志缓冲累积延迟 - 禁止使用 $time_iso8601 或 $time_local —— 它们仅精确到秒,毫秒位恒为 000

















