ngx_http_userid_module通过时间戳、进程ID、随机数及可选server_id拼接后MD5哈希生成32位十六进制UID,确保每秒内高唯一性;复用已有有效Cookie,支持多server部署且不依赖外部存储。

nginx 的 ngx_http_userid_module 模块用于为客户端生成并维护一个持久、唯一的标识(uid),通常以 Cookie 形式下发(如 __utma 类似),支持服务端做基础的用户追踪。其核心不依赖外部存储,而是通过时间戳、随机数和可选的 server ID 等字段组合,经 MD5 哈希生成 16 字节(32 位十六进制)的字符串作为 uid。下面从源码角度拆解它的唯一性保障机制与关键实现逻辑。
UID 的构成字段:时间 + 随机数 + 可选 server_id
该模块生成 uid 的原始数据(即 hash 输入)并非纯随机,而是结构化拼接:
-
4 字节 Unix 时间戳(秒级):取自
ngx_time(),保证每秒内生成的 uid 具有时间维度差异; -
4 字节进程 ID(pid):来自
ngx_pid,区分同一台机器上多个 worker 进程; -
4 字节随机数(rand):调用
ngx_random()生成,每次请求独立刷新,是防碰撞的关键扰动项; -
可选的 4 字节 server_id(若配置了 userid_domain):由
userid_domain指令指定的域名经ngx_crc32_long()计算得出,用于多 server 场景下避免 uid 冲突。
这 16 字节原始数据(或 20 字节含 server_id)被送入 MD5 计算,输出 128 位哈希值,再转为小写十六进制字符串(32 字符),作为最终的 uid 值(如 00000000000000000000000000000000)。
Cookie 的生成与写入时机
模块在 ngx_http_userid_filter_handler 中介入响应过滤链(content phase 后、log phase 前):
- 若请求中已携带合法 uid Cookie(且未过期、格式正确),则直接复用,不重新生成;
- 若无有效 uid,则调用
ngx_http_userid_set_uid构造新 uid,并通过ngx_http_set_cookie写入响应头Set-Cookie; - Cookie 属性(
Domain、Path、Expires、Max-Age、Secure、HttpOnly)均由userid_*系列指令控制,例如userid_expires决定有效期,userid_p3p控制 P3P 头。
唯一性保障的关键细节
看似简单的拼接+MD5,实际隐含几层设计考量:
-
时间戳仅秒级,但结合 rand + pid,极大降低同秒内重复概率:即使两个请求在同一秒到达同一 worker,
ngx_random()的 32 位空间使碰撞概率低于 2⁻³²; - server_id 不是全局唯一,而是基于域名 CRC,轻量且可预测:避免引入配置中心或共享存储,适合无状态部署;
- MD5 输出固定长度、均匀分布,适合作为 ID 字符串:虽然密码学意义上已不推荐,但此处仅用于标识而非安全认证,性能与兼容性更受重视;
- uid 本身不加密也不签名,完全依赖传输层(HTTPS)保护:模块不处理敏感信息,只负责生成和透传。
常见配置与调试提示
启用该模块需确认 nginx 编译时包含 --with-http_userid_module(默认不开启)。典型配置如下:
userid on; userid_name __utma; userid_domain example.com; userid_expires max; userid_p3p 'CP="CURa ADMa DEVa TAIa PSAa PSDo OUR BUS COM NAV INT"';
调试时可通过 error_log debug; 查看模块内部日志(需开启 debug 日志级别),重点关注 userid: set uid 和 userid: found uid 等行,验证 uid 是否正常生成与复用。










