背景
我们想要从Nginx接受请求开始,生成一个Unique Tracing ID,不仅记录在Nginx的日志中,也要贯穿到整个后台的服务,从而利用这个ID方便问题的排查。
方案一
利用Nginx丰富的内置变量,拼接出一个“unique enough id”。这里使用了五个变量:
- $pid: Nginx worker process id
- $msec: timestamp in millisecond
- $remote_addr: client address
- $connection: TCP connection serial number
- $connection_requests: current number of requests made through a connection
实现步骤
1.在nginx.conf的location模块里:
1 | location / { |
2.在http模块的 log_format 里加上 $req_id,至此Nginx的日志中将包含这个ID
1 | log_format trace '... $req_id'; |
3.在后台服务中可以通过下面的方式获取$req_id
1 | class MainHandler(tornado.web.RequestHandler): |
4.重启Nginx
1 | nginx -s reload |
问题
格式混乱,信息冗余,生成的效果如下:
1 | 97372.1493211301.686.127.0.0.1.471.32 |
方案二
使用Nginx内置的变量 $request_id
这是最直接的办法,使用Nginx自带的一个$request_id,一个16位比特的随机数,用32位的16进制数表示。
1 | proxy_set_header X-Request-Id $request_id; |
问题
这Nginx 1.11.0 版本新增加的feature,使用Nginx旧版本,或者依赖某些二次开发的Nginx版本,例如 Tengine 继承的是Nginx 1.8.1 版本,都面临着升级Nginx的问题。
方案三
使用 Lua 生成一个uuid.
利用Lua轻量小巧的特性,嵌入到Nginx的配置文件当中,然后生成一个uuid.
实现步骤
1.在 http 模块里加入:
1 | map $host $uuid { |
2.在server模块里加入:
1 | set_by_lua $uuid ' |
3.在location模块里加入:
1 | proxy_set_header X-Request-Id $uuid; |
4.uuid4.lua
引用自 第三方库
1 | --[[ |
问题
Lua的这个模块太长,担心性能问题,需要进行性能评估。
方案四
还是利用Lua脚本,使用时间戳加随机数的方式
关键步骤:
1 | set_by_lua $rdm_number ' |
问题
os.time()的精确度在1秒,os.clock()的精确度在0.01秒,这样处理之后,总的精度在10毫秒,没有达到要求。
Lua有一个 Luasocket 模块,可以达到毫秒级别的精度,但是需要安装。
方案五
结合Nginx的 $msec 变量和 Lua 的随机数
关键配置
1 | server { |
终记
最终确定方案五,简单,方便,影响最小。
在方案选择、测试过程中,还遇到了环境搭建相关的问题,将记录在下篇文章中,敬请期待!
参考
1.http://stackoverflow.com/questions/17748735/setting-a-trace-id-in-nginx-load-balancer
2.https://blog.ryandlane.com/2014/12/11/using-lua-in-nginx-for-unique-request-ids-and-millisecond-times-in-logs/
3.http://www.jb51.net/article/82167.htm
4.http://nginx.org/en/docs/http/ngx_http_core_module.html#.24args
5.http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_id