• 背景
  • 方案一
    • 实现步骤
    • 问题
  • 方案二
    • 问题
  • 方案三
    • 实现步骤
    • 问题
  • 方案四
    • 问题
  • 方案五
  • 终记
  • 参考

背景

我们想要从Nginx接受请求开始,生成一个Unique Tracing ID,不仅记录在Nginx的日志中,也要贯穿到整个后台的服务,从而利用这个ID方便问题的排查。

方案一

利用Nginx丰富的内置变量,拼接出一个“unique enough id”。这里使用了五个变量:
* pid:Nginxworkerprocessid∗pid:Nginxworkerprocessid∗pid: Nginx worker process id * msec: timestamp in millisecond
* remoteaddr:clientaddress∗remoteaddr:clientaddress∗remote_addr: client address * connection: TCP connection serial number
* $connection_requests: current number of requests made through a connection

实现步骤

1.在nginx.conf的location模块里:

location / {proxy_pass http://upstream;set $req_id $pid.$msec.$remote_addr.$connection.$connection_requests;proxy_set_header X-Request-Id $req_id;
}

2.在http模块的 log_format 里加上 $req_id,至此Nginx的日志中将包含这个ID

log_format trace '... $req_id';

3.在后台服务中可以通过下面的方式获取$req_id

class MainHandler(tornado.web.RequestHandler):def get(self):self.write(self.request.headers["X-Request-Id"])

4.重启Nginx

nginx -s reload

问题

格式混乱,信息冗余,生成的效果如下:

97372.1493211301.686.127.0.0.1.471.32

方案二

使用Nginx内置的变量 requestid这是最直接的办法,使用Nginx自带的一个requestid这是最直接的办法,使用Nginx自带的一个request_id 这是最直接的办法,使用Nginx自带的一个request_id,一个16位比特的随机数,用32位的16进制数表示。

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 模块里加入:

    map $host $uuid {default '';}lua_package_path '/path/to/uuid4.lua';init_by_lua 'uuid4 = require "uuid4"math = require "math"';

2.在server模块里加入:

    set_by_lua $uuid 'return uuid4.getUUID()';

3.在location模块里加入:

    proxy_set_header X-Request-Id $uuid;

4.uuid4.lua
引用自 第三方库

--[[
The MIT License (MIT)
Copyright (c) 2012 Toby Jennings
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--]]local M = {}
-----
math.randomseed( os.time() )
math.random()
-----
local function num2bs(num)local _mod = math.fmod or math.modlocal _floor = math.floor--local result = ""if(num == 0) then return "0" endwhile(num  > 0) doresult = _mod(num,2) .. resultnum = _floor(num*0.5)endreturn result
end
--
local function bs2num(num)local _sub = string.sublocal index, result = 0, 0if(num == "0") then return 0; endfor p=#num,1,-1 dolocal this_val = _sub( num, p,p )if this_val == "1" thenresult = result + ( 2^index )endindex=index+1endreturn result
end
--
local function padbits(num,bits)if #num == bits then return num endif #num > bits then print("too many bits") endlocal pad = bits - #numfor i=1,pad donum = "0" .. numendreturn num
end
--
local function getUUID()local _rnd = math.randomlocal _fmt = string.format--_rnd()--local time_low_a = _rnd(0, 65535)local time_low_b = _rnd(0, 65535)--local time_mid = _rnd(0, 65535)--local time_hi = _rnd(0, 4095 )time_hi = padbits( num2bs(time_hi), 12 )local time_hi_and_version = bs2num( "0100" .. time_hi )--local clock_seq_hi_res = _rnd(0,63)clock_seq_hi_res = padbits( num2bs(clock_seq_hi_res), 6 )clock_seq_hi_res = "10" .. clock_seq_hi_res--local clock_seq_low = _rnd(0,255)clock_seq_low = padbits( num2bs(clock_seq_low), 8 )--local clock_seq = bs2num(clock_seq_hi_res .. clock_seq_low)--local node = {}for i=1,6 donode[i] = _rnd(0,255)end--local guid = ""guid = guid .. padbits(_fmt("%X",time_low_a), 4)guid = guid .. padbits(_fmt("%X",time_low_b), 4)guid = guid .. padbits(_fmt("%X",time_mid), 4)guid = guid .. padbits(_fmt("%X",time_hi_and_version), 4)guid = guid .. padbits(_fmt("%X",clock_seq), 4)--for i=1,6 doguid = guid .. padbits(_fmt("%X",node[i]), 2)end--return guid
end
--
M.getUUID = getUUID
return M

问题

Lua的这个模块太长,担心性能问题,需要进行性能评估。

方案四

还是利用Lua脚本,使用时间戳加随机数的方式
关键步骤:

    set_by_lua $rdm_number 'return os.time() .. os.clock()*100 .. math.random(1000000000, os.time())';

问题

os.time()的精确度在1秒,os.clock()的精确度在0.01秒,这样处理之后,总的精度在10毫秒,没有达到要求。
Lua有一个 Luasocket 模块,可以达到毫秒级别的精度,但是需要安装。

方案五

结合Nginx的 $msec 变量和 Lua 的随机数
关键配置

server {...set_by_lua $rdm_number 'return math.random(1000000000, os.time())';location / {...set $req_id $msec$rdm_number;proxy_set_header X-Request-Id $req_id;}
}

终记

最终确定方案五,简单,方便,影响最小。
在方案选择、测试过程中,还遇到了环境搭建相关的问题,将记录在下篇文章中,敬请期待!


参考

  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

Nginx Unique Tracing ID相关推荐

  1. STM32唯一ID(Unique Device ID)的读取方法

    每一个STM32微控制器都自带一个96位的唯一ID,也就是Unique Device ID或称为UID,这个唯一ID在任何情况下都是唯一的且不允许修改.     在开发过程中,可能需要用到这个UID, ...

  2. 读取STM32F207/40x的CPU唯一ID(Unique Device ID)号方法

    在网上看到有很多的读取STM32F103系列MCU的CPU ID号,但是拿来在STM32F207上面是读取不到ID号的(按照STM32F103的地址读出来都是0XFFFFFFFF),原因是STM32F ...

  3. sql 关联使用id还是code_使用sh格式化nginx访问日志并存入mysql

    概述 说明:记录的日志格式(字段有:ip,time,method,uri,http,code,datasize,head,postdata) 步骤: 1.设置nginx日志格式 2.使用sh脚本格式化 ...

  4. STM32获取唯一身份标识unique ID

    96位的产品唯一身份标识所提供的参考号码对任意一个STM32微控制器,在任何情况下都是唯一的.用户在何种情况下,都不能修改这个身份标识. 在HAL库中有现成API接口可以调用. 以下为STM32F41 ...

  5. Loki 收集Nginx日志以 grafana 可视化展示

    背景 通常用ELK来收集Nginx日志的,对于服务器较少的用elk则显得太重了,可以用loki+Promtail+grafana 代替. Loki类似elasticsearch,用于存储:Promta ...

  6. nginx源码编译、负载均衡及模块的扩展

    1.nginx源码编译 实验环境: iptables和selinux关闭 redhat6.5 nginx:test1: 172.25.1.11 [root@test1 ~]# ls nginx-1.1 ...

  7. 关于android设备唯一区分device id的取得

    2019独角兽企业重金招聘Python工程师标准>>> 有些apk为了区分唯一设备,需要用到一个device id. 1. 取得设备的MAC address    如果用户没有通过w ...

  8. Nginx+keepalived 实现高可用,防盗链及动静分离配置

    一.Nginx Rewrite 规则 1. Nginx rewrite规则 Rewrite规则含义就是某个URL重写成特定的URL(类似于Redirect),从某种意义上说为了美观或者对搜索引擎友好, ...

  9. 千言万句,Nginx从入门到精通,看这一篇足矣

    本文是一个 Nginx 极简教程,目的在于帮助新手快速入门 Nginx. Nginx 简介 什么是 Nginx? Nginx(engine x)是一款轻量级的 Web 服务器 .反向代理服务器及电子邮 ...

最新文章

  1. 老板扣了我1000,因为我没记住阿里巴巴开发手册的这条规则。
  2. Wine 1.0 RC2
  3. c语言里变量列表,嵌入式C语言里的土豪们之变量类型
  4. 【转】Java中字符串中子串的查找共有四种方法(indexof())
  5. 江苏省教育厅与阿里云合作变革“智慧教育”
  6. 【Redis】17.Cluster集群结构搭建
  7. Visula Basic程序设计理论与实践pdf
  8. 几种jvm OOM问题
  9. 加载elementor时出现问题_不锈钢管在焊接时出现问题要怎么解决?
  10. 番石榴15 –新功能
  11. [EOJ]2019 ECNU XCPC March Selection #1 F
  12. SignalR与自托管Windows服务
  13. 第十三周编程总结--助教
  14. java练习题-求int类型N值的阶乘
  15. LOJ2361「NOIP2016」组合数问题
  16. 从hive上下载文件
  17. 股票大作手回忆录投机感悟
  18. POJ 1436 Horizontally Visible Segments(线段树区间修改)
  19. 操作系统与网络协议晦涩难懂,华为18级工程师神级文档助你过关
  20. 使用JavaScript克隆元素

热门文章

  1. 欢迎使用CSDN-markdown编辑器顶顶顶顶顶顶顶顶顶顶
  2. [附源码]java毕业设计图书馆自习室管理系统
  3. 20230603-周六随笔
  4. 蓝桥杯-----世纪末的星期
  5. 重塑人机共识与应对信任危机
  6. 严格凸函数充分必要条件_关于凸函数的两个充分必要条件
  7. 监控宝 mysql_监控宝服务性能监控配置(完整版)
  8. 8招提升海报设计的招式
  9. UCloud叶理灯:内外部容器云平台构建的思考!
  10. vue打包上线移除 console