在大部分的微服务架构中,Nginx基本是常用的接入层设施,所以我们希望请求ID从Nginx层进行校验填充,并且打印在Nginx的请求日志中。
阅读提示:本文不提供链路追踪的完整解决方案,只提供Nginx层对链路追踪的支持方案!
微服务的诞生,解决了传统单体应用的很多问题,如可维护性差、扩展性差和灵活性差等问题(粗粒比较)。微服务架构虽好,但同时也带来了很多挑战,其中 故障排查 就是其需要解决的挑战之一。那么,如何在很多个应用和实例中找到故障发生的根源呢?
基于以上需求,我们可以将每一笔交易在各个应用中产生的所有日志,进行集中式收集与展示(但前提是你得有:日志中心)。这样就可以很快看出交易是在哪一步出的故障。如果做得好,还可以直接进行二次开发与数据分析,将收集的日志和出现的故障进行分析后,用图形界面很直观的进行展示。
比如,可以展示出微服务调用的拓扑图,使用颜色进行区分故障(如常用红:表示异常、绿:正常、黄:警告)。接着可以将常出现的故障或异常进行分类后做出友好型的展示(说白了就不用直接上堆栈),如:NullPointerException:则界面直接友好型的提示哪一行代码抛了空指针,输入参数是什么……(这不是该篇的重点哈,废话不多说了,后续有机会再详细介绍)。
要做整个微服务架构的链路追踪,肯定是希望从交易进入微服务中心的第一个点就开始有一个全局的交易ID来关联所有日志(链路追踪,这么一个ID肯定是不够的,但这里只介绍这个哈)。当然最理想的肯定是希望把前端的日志(如操作日志、数据流等)也规划进行。
在大部分的微服务架构中,Nginx基本是常用的接入层设施,所以我们希望请求ID从Nginx层进行校验填充,并且打印在Nginx的请求日志中。这里只提供三种方式来实现Nginx层的交易ID生产方式。
在1.11.0之前的版本,我们可以采用拼接的方式来组装请求ID。参考配置如下:
<span class="hljs-section">server</span> { <span class="hljs-comment"># 定义$request_trace_id的值,在1.11.0之前,我们可以使用类似的方式声明</span> <span class="hljs-comment"># 只要能确保其值出现重复的可能性尽可能的小即可。 </span> <span class="hljs-attribute">set</span> <span class="hljs-variable">$request_trace_id</span> trace-id-<span class="hljs-variable">$pid</span>-<span class="hljs-variable">$connection</span>-<span class="hljs-variable">$bytes_sent</span>-<span class="hljs-variable">$msec</span>; <span class="hljs-attribute">location</span> / { <span class="hljs-comment"># ……</span> <span class="hljs-comment"># 将此trace_id传递给后端的server,通过header方式,此后我们既可以在环境中获取此header </span> <span class="hljs-attribute">proxy_set_header</span> X-Request-Id <span class="hljs-variable">$request_trace_id</span>; } }
参数说明:
- $pid:nginx worker进程号
- $connection:与upstream server链接id数
- $bytes_sent:发送字节数
- $msec:当前时间,即此变量获取的时间,包含秒、毫秒数(中间以.分割)
利用系统/dev/urandom 生成的随机 UUID 。参考脚本如下:
<span class="hljs-comment">---</span> <span class="hljs-comment">--- UUID</span> <span class="hljs-comment">--- Created by lry.</span> <span class="hljs-comment">--- DateTime: 2018/2/25 下午7:38</span> <span class="hljs-comment">--- Describe: 用系统/dev/urandom生成的随机uuid</span> <span class="hljs-comment">---</span> <span class="hljs-keyword">local</span> template =<span class="hljs-string">"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"</span> <span class="hljs-keyword">local</span> d = <span class="hljs-built_in">io</span>.open(<span class="hljs-string">"/dev/urandom"</span>, <span class="hljs-string">"r"</span>):read(<span class="hljs-number">4</span>) <span class="hljs-built_in">math</span>.randomseed(<span class="hljs-built_in">os</span>.time() + d:byte(<span class="hljs-number">1</span>) + (d:byte(<span class="hljs-number">2</span>) * <span class="hljs-number">256</span>) + (d:byte(<span class="hljs-number">3</span>) * <span class="hljs-number">65536</span>) + (d:byte(<span class="hljs-number">4</span>) * <span class="hljs-number">4294967296</span>)) <span class="hljs-keyword">local</span> uuid=<span class="hljs-built_in">string</span>.gsub(template, <span class="hljs-string">"x"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(c)</span></span> <span class="hljs-keyword">local</span> v = (c == <span class="hljs-string">"x"</span>) <span class="hljs-keyword">and</span> <span class="hljs-built_in">math</span>.random(<span class="hljs-number">0</span>, <span class="hljs-number">0xf</span>) <span class="hljs-keyword">or</span> <span class="hljs-built_in">math</span>.random(<span class="hljs-number">8</span>, <span class="hljs-number">0xb</span>) <span class="hljs-keyword">return</span> <span class="hljs-built_in">string</span>.format(<span class="hljs-string">"%x"</span>, v) <span class="hljs-keyword">end</span>) <span class="hljs-keyword">return</span> uuid
Nginx在 1.11.0版本中就提供了内置变量 $request_id ,其原理就是生成32位的随机字符串,虽不能比拟UUID的概率,但32位的随机字符串的重复概率也是微不足道了,所以一般可视为UUID来使用即可。参考配置如下:
<span class="hljs-comment"># Nnginx代理默认会把header中参数的 "_" 下划线去掉,所以后台服务器后就获取不到带"_"线的参数名</span> <span class="hljs-attribute">underscores_<span class="hljs-keyword">in</span>_headers</span> <span class="hljs-literal">on</span>; <span class="hljs-comment"># 设定日志格式</span> <span class="hljs-attribute"><span class="hljs-built_in">log</span>_format</span> main \<span class="hljs-string">'<span class="hljs-variable">$remote_addr</span> - <span class="hljs-variable">$remote_user</span> [<span class="hljs-variable">$time_local</span>] "<span class="hljs-variable">$request</span>" \' \'<span class="hljs-variable">$status</span> <span class="hljs-variable">$body_bytes_sent</span> "<span class="hljs-variable">$http_referer</span>" <span class="hljs-variable">$upstream_http_request_id</span> \' \'"<span class="hljs-variable">$http_user_agent</span>" "<span class="hljs-variable">$http_x_forwarded_for</span>"\'; server { location / { <span class="hljs-comment"># 如果请求头中已有该参数,则获取即可;如果没有,则使用</span><span class="hljs-variable"><span class="hljs-comment">$request_id</span></span><span class="hljs-comment">进行填充</span> <span class="hljs-built_in">set</span> <span class="hljs-variable">$temp_request_id</span> <span class="hljs-variable">$http_x_request_id</span>; <span class="hljs-keyword">if</span> (<span class="hljs-variable">$temp_request_id</span> = "") { <span class="hljs-built_in">set</span> <span class="hljs-variable">$temp_request_id</span> <span class="hljs-variable">$request_id</span>; } <span class="hljs-comment"># 屏蔽掉原来的请求头参数</span> proxy_<span class="hljs-built_in">set</span>_header x_request_id ""; <span class="hljs-comment"># 设置向后转发的请求头参数</span> proxy_<span class="hljs-built_in">set</span>_header X-Request-Id <span class="hljs-variable">$temp_request_id</span>; } } </span>
生成交易ID的方式有很多种,但希望使用者结合自身实际情况进行合理取舍,而不要盲目的追求ID的唯一性、可读性和时序性等等。
比如,ID具有时序性虽然有一定的好处,但实际的架构根本没有去使用该时序性,则没必要花大量的精力和做出大量的开发,去实现一个有时序性的交易ID。又比如,觉得UUID可读性太差,从而花了很多成本去开发一个具有一定含义的交易ID(如前几位表示什么意思,多少位到多少位又表示什么意思之类的),开发出来后,实际架构根本没有去解读该ID的地方,则浪费了成本。
但也不是所有人都直接使用UUID就能满足的,比如我需要考虑日志的容量,则可以考虑适当缩减ID的长度(每个ID缩减10个字符串,每笔交易就可能少几百或几千个字符串,再往上规划,还是可以减少一些日志容量的)。
最后,如果有考虑想收集前端的日志的童鞋,建议交易ID就不要使用Long型,因为前端可能会有损失精度的问题。同时也建议使用 $request_id 来填充交易ID。
以上是微服务架构之Nginx链路追踪的详细内容。更多信息请关注PHP中文网其他相关文章!

互联网运行不依赖单一操作系统,但Linux在其中扮演重要角色。Linux广泛应用于服务器和网络设备,因其稳定性、安全性和可扩展性受欢迎。

Linux操作系统的核心是其命令行界面,通过命令行可以执行各种操作。1.文件和目录操作使用ls、cd、mkdir、rm等命令管理文件和目录。2.用户和权限管理通过useradd、passwd、chmod等命令确保系统安全和资源分配。3.进程管理使用ps、kill等命令监控和控制系统进程。4.网络操作包括ping、ifconfig、ssh等命令配置和管理网络连接。5.系统监控和维护通过top、df、du等命令了解系统运行状态和资源使用情况。

介绍 Linux是一个强大的操作系统,由于其灵活性和效率,开发人员,系统管理员和电源用户都喜欢。但是,经常使用长而复杂的命令可能是乏味的

Linux适用于服务器、开发环境和嵌入式系统。1.作为服务器操作系统,Linux稳定高效,常用于部署高并发应用。2.作为开发环境,Linux提供高效的命令行工具和包管理系统,提升开发效率。3.在嵌入式系统中,Linux轻量且可定制,适合资源有限的环境。

简介:通过基于Linux的道德黑客攻击数字边界 在我们越来越相互联系的世界中,网络安全至关重要。 道德黑客入侵和渗透测试对于主动识别和减轻脆弱性至关重要

Linux基础学习从零开始的方法包括:1.了解文件系统和命令行界面,2.掌握基本命令如ls、cd、mkdir,3.学习文件操作,如创建和编辑文件,4.探索高级用法如管道和grep命令,5.掌握调试技巧和性能优化,6.通过实践和探索不断提升技能。

Linux在服务器、嵌入式系统和桌面环境中的应用广泛。1)在服务器领域,Linux因其稳定性和安全性成为托管网站、数据库和应用的理想选择。2)在嵌入式系统中,Linux因其高度定制性和高效性而受欢迎。3)在桌面环境中,Linux提供了多种桌面环境,满足不同用户需求。

Linux的缺点包括用户体验、软件兼容性、硬件支持和学习曲线。1.用户体验不如Windows或macOS友好,依赖命令行界面。2.软件兼容性不如其他系统,缺乏许多商业软件的原生版本。3.硬件支持不如Windows全面,可能需要手动编译驱动程序。4.学习曲线较陡峭,掌握命令行操作需要时间和耐心。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

SublimeText3汉化版
中文版,非常好用

Atom编辑器mac版下载
最流行的的开源编辑器

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

禅工作室 13.0.1
功能强大的PHP集成开发环境

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中