首页 系统教程 操作系统 微服务架构之Nginx链路追踪

微服务架构之Nginx链路追踪

Aug 06, 2024 pm 04:34 PM
linux linux教程 红帽 linux系统 linux命令 linux认证 红帽linux linux视频

微服务架构之Nginx链路追踪

在大部分的微服务架构中,Nginx基本是常用的接入层设施,所以我们希望请求ID从Nginx层进行校验填充,并且打印在Nginx的请求日志中。

阅读提示:本文不提供链路追踪的完整解决方案,只提供Nginx层对链路追踪的支持方案!

1 背景介绍

微服务的诞生,解决了传统单体应用的很多问题,如可维护性差、扩展性差和灵活性差等问题(粗粒比较)。微服务架构虽好,但同时也带来了很多挑战,其中 故障排查 就是其需要解决的挑战之一。那么,如何在很多个应用和实例中找到故障发生的根源呢?

基于以上需求,我们可以将每一笔交易在各个应用中产生的所有日志,进行集中式收集与展示(但前提是你得有:日志中心)。这样就可以很快看出交易是在哪一步出的故障。如果做得好,还可以直接进行二次开发与数据分析,将收集的日志和出现的故障进行分析后,用图形界面很直观的进行展示。

比如,可以展示出微服务调用的拓扑图,使用颜色进行区分故障(如常用红:表示异常、绿:正常、黄:警告)。接着可以将常出现的故障或异常进行分类后做出友好型的展示(说白了就不用直接上堆栈),如:NullPointerException:则界面直接友好型的提示哪一行代码抛了空指针,输入参数是什么……(这不是该篇的重点哈,废话不多说了,后续有机会再详细介绍)。

要做整个微服务架构的链路追踪,肯定是希望从交易进入微服务中心的第一个点就开始有一个全局的交易ID来关联所有日志(链路追踪,这么一个ID肯定是不够的,但这里只介绍这个哈)。当然最理想的肯定是希望把前端的日志(如操作日志、数据流等)也规划进行。

2 Nginx

在大部分的微服务架构中,Nginx基本是常用的接入层设施,所以我们希望请求ID从Nginx层进行校验填充,并且打印在Nginx的请求日志中。这里只提供三种方式来实现Nginx层的交易ID生产方式。

2.1 方案二:基于内置变量拼接

在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:当前时间,即此变量获取的时间,包含秒、毫秒数(中间以.分割)
2.2 方案三:基于LUA脚本实现

利用系统/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
登录后复制
2.3 方案一:基于  $request_id  实现

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>
登录后复制
3 最佳实践

生成交易ID的方式有很多种,但希望使用者结合自身实际情况进行合理取舍,而不要盲目的追求ID的唯一性、可读性和时序性等等。

比如,ID具有时序性虽然有一定的好处,但实际的架构根本没有去使用该时序性,则没必要花大量的精力和做出大量的开发,去实现一个有时序性的交易ID。又比如,觉得UUID可读性太差,从而花了很多成本去开发一个具有一定含义的交易ID(如前几位表示什么意思,多少位到多少位又表示什么意思之类的),开发出来后,实际架构根本没有去解读该ID的地方,则浪费了成本。

但也不是所有人都直接使用UUID就能满足的,比如我需要考虑日志的容量,则可以考虑适当缩减ID的长度(每个ID缩减10个字符串,每笔交易就可能少几百或几千个字符串,再往上规划,还是可以减少一些日志容量的)。

最后,如果有考虑想收集前端的日志的童鞋,建议交易ID就不要使用Long型,因为前端可能会有损失精度的问题。同时也建议使用 $request_id  来填充交易ID。

以上是微服务架构之Nginx链路追踪的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Linux体系结构:揭示5个基本组件 Linux体系结构:揭示5个基本组件 Apr 20, 2025 am 12:04 AM

Linux系统的五个基本组件是:1.内核,2.系统库,3.系统实用程序,4.图形用户界面,5.应用程序。内核管理硬件资源,系统库提供预编译函数,系统实用程序用于系统管理,GUI提供可视化交互,应用程序利用这些组件实现功能。

vscode终端使用教程 vscode终端使用教程 Apr 15, 2025 pm 10:09 PM

vscode 内置终端是一个开发工具,允许在编辑器内运行命令和脚本,以简化开发流程。如何使用 vscode 终端:通过快捷键 (Ctrl/Cmd ) 打开终端。输入命令或运行脚本。使用热键 (如 Ctrl L 清除终端)。更改工作目录 (如 cd 命令)。高级功能包括调试模式、代码片段自动补全和交互式命令历史。

git怎么查看仓库地址 git怎么查看仓库地址 Apr 17, 2025 pm 01:54 PM

要查看 Git 仓库地址,请执行以下步骤:1. 打开命令行并导航到仓库目录;2. 运行 "git remote -v" 命令;3. 查看输出中的仓库名称及其相应的地址。

vscode在哪写代码 vscode在哪写代码 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中编写代码简单易行,只需安装 VSCode、创建项目、选择语言、创建文件、编写代码、保存并运行即可。VSCode 的优点包括跨平台、免费开源、强大功能、扩展丰富,以及轻量快速。

notepad怎么运行java代码 notepad怎么运行java代码 Apr 16, 2025 pm 07:39 PM

虽然 Notepad 无法直接运行 Java 代码,但可以通过借助其他工具实现:使用命令行编译器 (javac) 编译代码,生成字节码文件 (filename.class)。使用 Java 解释器 (java) 解释字节码,执行代码并输出结果。

Linux的主要目的是什么? Linux的主要目的是什么? Apr 16, 2025 am 12:19 AM

Linux的主要用途包括:1.服务器操作系统,2.嵌入式系统,3.桌面操作系统,4.开发和测试环境。Linux在这些领域表现出色,提供了稳定性、安全性和高效的开发工具。

sublime写好代码后如何运行 sublime写好代码后如何运行 Apr 16, 2025 am 08:51 AM

在 Sublime 中运行代码的方法有六种:通过热键、菜单、构建系统、命令行、设置默认构建系统和自定义构建命令,并可通过右键单击项目/文件运行单个文件/项目,构建系统可用性取决于 Sublime Text 的安装情况。

vscode终端命令不能用 vscode终端命令不能用 Apr 15, 2025 pm 10:03 PM

VS Code 终端命令无法使用的原因及解决办法:未安装必要的工具(Windows:WSL;macOS:Xcode 命令行工具)路径配置错误(添加可执行文件到 PATH 环境变量中)权限问题(以管理员身份运行 VS Code)防火墙或代理限制(检查设置,解除限制)终端设置不正确(启用使用外部终端)VS Code 安装损坏(重新安装或更新)终端配置不兼容(尝试不同的终端类型或命令)特定环境变量缺失(设置必要的环境变量)

See all articles