当前位置: 首页 > news >正文

为什么在容器中 1 号进程挂不上 arthas?

作者:卜比

本文是《容器中的 Java》系列文章之 4/n ,欢迎关注后续连载 😃 。

系列1:JVM 如何获取当前容器的资源限制?

系列2:Java Agent 踩坑之

appendToSystemClassLoaderSearch 问题

系列3:让 Java Agent 在 Dragonwell 上更好用

最近在容器环境中,发现在 Java 进程是 1 号进程的情况下,无法使用 arthas。

提示 AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread。具体操作和报错如下:

# java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.5.6
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 1 com.alibabacloud.mse.demo.ZuulApplication
1
[INFO] arthas home: /home/admin/.opt/ArmsAgent/arthas
[INFO] Try to attach process 1
[ERROR] Start arthas failed, exception stack trace:
com.sun.tools.attach.AttachNotSupportedException: Unable to get pid of LinuxThreads manager threadat sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:86)at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:117)at com.taobao.arthas.core.Arthas.<init>(Arthas.java:27)at com.taobao.arthas.core.Arthas.main(Arthas.java:166)
[INFO] Attach process 1 success.

之前也遇到过,总是调整了下镜像,让 Java 进程不是 1 号进程就可以了。但这个不是长久之计,还是要抽时间看下这个问题。

复现问题

我们创建如下项目,来复现这个问题:

public class Main {public static void main(String args[]) throws Exception {while (true) {System.out.println("hello!");Thread.sleep(30 * 1000);}}
}
FROM openjdk:8u212-jdk-alpine
COPY ./ /app
WORKDIR /app/src/main/java/
RUN javac Main.java
CMD ["java", "Main"]

然后正常启动应用,并尝试用 arthas,或者 jstack:

$ # 构建镜像
$ docker build . -t example-attach
$ # 启动容器
$ docker run --name example-attach --rm example-attach$ # 在另一个终端进入容器,执行jstack
$ docker exec -it example-attach sh
/app/src/main/java # jstack 1
1: Unable to get pid of LinuxThreads manager thread

成功复现问题!接下来开始分析。

正常的 attach 流程是什么样子的?

如下是在排查问题中,梳理出来的 jvm Attach 流程:

  1. 查找 /tmp/.java_pid${pid} 这个 unix socket,如果存在则检查权限,然后建立连接。
  2. 如果不存在则先创建 /proc/pid/cwd/.attachpid{pid}/cwd/.attach_pidpid/cwd/.attachpid{pid},开始通知 jvm 线程。
  3. 首先判断是不是 LinuxThread如果是 LinuxThread则找到 LinuxThreadsManager,然后给其所有子进程发送 SIGQUIT.
  4. 如果不是 LinuxThread,则直接给目标进程发送 SIGQUIT。
  5. 目标进程收到信号后,创建 Attach Listener,监听 /tmp/.java_pid${pid}。
  6. 开始正常的 socket 通信,根据通信的具体内容,可以是 dumpThread(jstack),也可以是加载 JavaAgent,比如上面提到的 arthas。

**Java Attach 机制之 Native 篇 [ 1] **也是一个不错的 attach API 解析。

为什么对1号进程 attach 会报错?

首先,/tmp/.java_pid${pid} 当时是肯定不存在的,如果存在就是直接通信加载 Arthas 了。也可以通过查看文件来确认这一点。

其次,.attach_pid${pid} 文件也是能够创建成功的,

我们也可以通过 strace 输出来确认:

open(“/proc/424/cwd/.attach_pid424”, O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0666 <unfinished …>。

最有可能的原因就是线程判断、发送信号这一步了,我们以 jstack 为例查找为什么 attach 会失败。

本来类似上一次的查找过程,想着通过调试符号来查,但是在 alpine 上的调试符号无法显示源码内容,编译环境又很麻烦。所以还是优先用 strace 来查,值得注意的是, jstack 的逻辑中有 fork,所以记得使用 strace -f jstack 1 来查。

查了下 strace 的输出,没有 kill 请求。看来问题是处在线程模型判定的。

刚刚提到 jvm 会判断是不是 LinuxThread,那么什么是 LinuxThread 呢?首先看下判断的源码:

在这里插入图片描述

通俗的讲,Linux 内核刚开始是不支持“线程”的,LinuxThread 机制就是通过 fork 机制+共享内存空间的方式来实现线程。但 LinuxThread 在内核看来就是一些独立的父子进程,在信号处理、同步原语上有很多缺陷,要通过 manager thread 来处理这些逻辑。后来 Red Hat 发起 NPTL,内核开始支持线程能力,也能够通过更加标准的方式来处理信号、同步等逻辑。

可以用 getconf GNU_LIBPTHREAD_VERSION 来查看是哪种线程模型,比如我的机器上输出是 NPTL 2.34。

当然,如上面代码所写。可以用 confstr(_CS_GNU_LIBPTHREAD_VERSION,) 来获取当前的线程模型,**详情参考手册 [ 2] **。

  • 如果 confstr(_CS_GNU_LIBPTHREAD_VERSION,) 返回 0,则表示是 glibc 旧版本,认为是 LinuxThread:先找到 manager thread(通过查找父进程),然后给各个子进程发送 SIGQUIT 信号(这个过程需要遍历系统内所有进程)。
  • 如果 confstr(_CS_GNU_LIBPTHREAD_VERSION,) 结果包含 NPTL,则认为不是 LinuxThread,按照 NPTL 来处理:直接发送 SIGQUIT。

但很可惜的是,LinuxThread/confstr(_CS_GNU_LIBPTHREAD_VERSION,) 不是 POSIX 标准,所以 Alpine 自带的 musl 对这个调用返回 0。

按照上面逻辑,jvm 会认为是 LinuxThread,尝试找到父进程,如果 pid 是 1 的话,自然找不到父进程,所以报错 Unable to get pid of LinuxThreads manager thread,导致文章最开始说的 arthas 无法使用。

关于两种线程模型的详细比较,可以参考 **Linux 线程模型比较:LinuxThreads 和 NPTL [3 ] **。

为什么非1号进程就能 attach?

模拟了下先手动进入 shell(这时 sh 就是 1 号进程),然后再手动执行 java Main(pid为 8 ),然后我们看下 getLinuxThreadsManager 是怎么表现的:

在这里插入图片描述

可以看到,在这种情况下,jvm 认为 manager thread 是 1 号进程。此时会后执行 sendQuitToChildrenOf(mpid):

在这里插入图片描述

在这里插入图片描述

即遍历所有的子进程,都发送 SIGQUIT,这个逻辑其实是有点奇怪的。 **“超凡的主张,需要有超凡的证据” [ 4] **。我们重新跑一遍,用 strace -f 验证一下。

进程树(其中绿色的是线程):

在这里插入图片描述

jstack 发送的 kill 信号,可以看到 jstack 给 1 号进程的所有子进程发送了 SIGQUIT:

在这里插入图片描述

这个行为和刚刚分析是一致的。不过非常巧合的是,大部分进程是忽略了 SIGQUIT 信号的,所以在这种情况下,jstack 反而是正常工作了的。

怎么解决这个问题?

最快捷 workaround

注:这种方式不需要调整容器参数,不需要重启容器,比较推荐。

既然 attach 主要卡在了发送信号上,那我们就用 shell 来模拟这个流程:

pid=1 ;\
touch /proc/${pid}/cwd/.attach_pid${pid} && \kill -SIGQUIT ${pid} && \sleep 2 &&ls /proc/${pid}/root/tmp/.java_pid${pid}
# 接下来就可以正常 java -jar arthas-boot.jar 挂arthas了

通过上面的操作后,Attach Listener 已经启动并且监听了路径,第二次 attach 就直接可以连接了;就可以按照正常的方式使用 arthas 了。

其中有一点需要注意,一定需要提前创建 .attach_pid${pid} 文件, 不然 jvm 会将这个信号交给默认的 sigaction 处理,对于 pid 1 来说,会导致容器退出!

也有人基于类似原理,做了一个 **jattach [ 5] **工具,可以直接在 Alpine 中,通过 apk add jattach 来安装,然后 jattach ${pid} properties,也能起到一样的效果。

设置启动参数

注:这种方式需要调整启动参数或者环境变量,需要重启应用/容器,可能会丢失业务现场。

Jvm 支持设置 -XX:+StartAttachListener,这样就能在启动 Jvm 的时候,自动启动 Attach Listener 线程并监听,也可以正常使用 arthas。

对于容器环境下,更加容易的做法是给容器添加环境变量 JAVA_TOOL_OPTIONS=-XX:+StartAttachListener,这样不用修改启动脚本也能达到效果。

上游优先,修改镜像

注:这种方式需要修改镜像。

OpenJDK 8 官方没有修复这个问题,所以如果直接使用 openjdk:8-jdk-alpine,是避免不了这个问题的。**Docker 镜像仓库也有人讨论这个问题 [ 6] **。

OpenJDK 11 就已经解决了这个问题了(见**源码 [ 7] **),不再对古旧的 LinuxThread 模型做判断,这样 arthas 也能工作。

不过 Alpine 官方仓库中的 OpenJDK 8 已经通过自己打 patch 的方式,修复了这个问题:

https://gitlab.alpinelinux.org/alpine/aports/-/issues/13032

作为比较知名的 JDK 发行版,也在 eclipse-temurin:8-jdk-alpine 中修复了这个问题,可以直接使用这个镜像。相关讨论见:

https://github.com/adoptium/jdk8u/pull/8

总结

在 arthas 的 issue 中,或者网上相关的文章中,总是重复着 Java 不能作为 1 号进程。很多时候,就因为如此,我们没有办法挂上诊断工具,导致现场丢失,故障原因不能及时定位。

作为技术人员还是需要了解底层,这样在排查问题、架构设计上才会有更多自由度,更能够抓住问题、解决问题。

后续还会出系列文章,来解决容器环境下奇奇怪怪的 jvm 问题,欢迎关注!

相关链接

[1] Java Attach 机制之 Native 篇

https://my.oschina.net/u/3784034/blog/5526214

[2] 详情参考手册

https://man7.org/linux/man-pages/man3/confstr.3.html

[3] Linux 线程模型比较:LinuxThreads 和 NPTL

https://www.jianshu.com/p/6c507b966ad1

[4] 超凡的主张,需要有超凡的证据

https://zh.wikipedia.org/zh-hans/%E8%96%A9%E6%A0%B9%E6%A8%99%E6%BA%96

[5] jattach

https://github.com/apangin/jattach

[6] Docker 镜像仓库也有人讨论这个问题

https://github.com/docker-library/openjdk/issues/76

[7] 源码

https://github.com/openjdk/jdk11u/blob/jdk-11%2B28/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java#L78

相关文章:

为什么在容器中 1 号进程挂不上 arthas?

作者&#xff1a;卜比 本文是《容器中的 Java》系列文章之 4/n &#xff0c;欢迎关注后续连载 &#x1f603; 。 系列1&#xff1a;JVM 如何获取当前容器的资源限制&#xff1f; 系列2&#xff1a;Java Agent 踩坑之 appendToSystemClassLoaderSearch 问题 系列3&#xff1a;让…...

23种设计模式之策略模式

一、概念 就是将一系列算法封装起来&#xff0c;并使它们之间相互替换。被封装起来的算法具有独立性外部不可改变其特性。 策略模式属于对象行为模式&#xff0c;它通过对算法进行封装&#xff0c;把使用算法的责任和算法的实现分割开来&#xff0c;并委派给不同的对象对这些算…...

不会做UI自动化测试?一起设计框架再实践吧

目的相信做过测试的同学都听说过自动化测试&#xff0c;而UI自动化无论何时对测试来说都是比较吸引人的存在。相较于接口自动化来说它可以最大程度的模拟真实用户的日常操作与特定业务场景的模拟&#xff0c;那么存在即合理&#xff0c;自动化UI测试自然也是广大测试同学职业道…...

数据分析实战项目3:RFM用户分群

目录1、RFM模型介绍2、Excel实际RFM划分案例3、RFM案例3.1 数据加载和基本信息查看3.2 数据预处理和RFM的初始值计算3.3 RFM区间和划分和分值计算3.4 RFM计算结果保存3.4.1 保存到excel3.4.2 保存到数据库3.5 RFM计算结果可视化3.6 结果分析&#xff08;营销建议&#xff09;3.…...

消息中间件概述

目录1.为什么学习消息队列2.什么是消息中间件3.消息队列应用场景3.1 应用解耦3.2 异步处理3.3 流量削峰3.4 什么是QPS&#xff0c;PV3.5 什么是PV,UV,PR4. AMQP 和 JMS4.1 AMQP4.2 JMS4.3. AMQP 与 JMS 区别5. 消息队列产品6. RabbitMQ6.1 RabbitMQ简介6.2 RabbitMQ 中的相关概…...

vue和js给后端接口返回的数据(如以json数据为元素的数组)添加新的json字段

文章目录vue和js给后端接口返回的数据&#xff08;如以json数据为元素的数组&#xff09;添加新的json字段1. res为后端接口的响应2. 获取后端接口返回的数据3. 向 tableData 添加字段3.1. 向 tableData 中添加一个新json元素( {"time", "2023-02-09"} )3.…...

负载均衡的方式

在业务初期&#xff0c;我们一般会先使用单台服务器对外提供服务。随着业务流量越来越大&#xff0c;单台服务器无论如何优化&#xff0c;无论采用多好的硬件&#xff0c;总会有性能天花板&#xff0c;当单服务器的性能无法满足业务需求时&#xff0c;就需要把多台服务器组成集…...

python(15)--函数设计

前言 函数是可重用的程序代码块。 函数的作用&#xff0c;不仅可以实现代码的复用&#xff0c;还可以保证修改函数的代码时&#xff0c;所有调用该函数的地方都能得到体现。目前我已知函数的作用是&#xff1a;对代码实现了封装、函数调用、传递参数、返回计算结果等。 正文 …...

手把手教你用Python做可视化数据,还能调节动画丝滑度

数据可视化动画还在用Excel做&#xff1f; 现在一个简单的Python包就能分分钟搞定&#xff01; 而且生成的动画也足够丝滑&#xff0c;效果是酱紫的&#xff1a; 这是一位专攻Python语言的程序员开发的安装包&#xff0c;名叫Pynimate。 目前可以直接通过PyPI安装使用。 使用…...

湖南中创教育PMP项目管理——变更管理

【变更管理​】包括 一、如何理解需求变更 二、如何控制需求变更 三、项目变更管理流程 四、如何应对“奇葩”变更 一、如何理解需求变更&#xff1a; 1、项目中发生变更是正常现象&#xff0c;变更无法回避 2、哪里都可能出现变更&#xff0c;任何人都有权提出变更 3、…...

IC真题 —— 刷题记录(1)

引言 记录一些 我自己刷的 IC行业招聘真题&#xff0c;不是每题记录&#xff0c;只记录一些值得记录的&#xff0c;写下自己的看法。主要是一些数字IC行业题目&#xff0c;偏前端。 1、有一个逐次逼近型 8位A/D 转换器&#xff0c;若时钟频率为250KHz&#xff0c;完成一次转换…...

【C++入门】命名空间,输出输入,缺省参数,函数重载

文章目录命名空间C输入与输出缺省参数函数重载命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标 识符的名称进行本地化&#xff0…...

cmu 445 poject 2笔记

2022年的任务 https://15445.courses.cs.cmu.edu/fall2022/project2/ checkpoint 1&#xff0c;实现b树&#xff0c;读&#xff0c;写&#xff0c;删 checkpoint 2, 实现b树&#xff0c;迭代器&#xff0c;并发读写删 本文不写代码&#xff0c;只记录遇到的一些思维盲点 checkp…...

梅开二度的 axios 源码阅读,三千字详细分享功能函数,帮助扩展开发思维

前言 第一遍看 axios 源码&#xff0c;更多的是带着日常开发的习惯&#xff0c;时不时产生出点联想。 第二遍再看 axios 源码&#xff0c;目标明确&#xff0c;就是奔着函数来的。 当有了明确清晰的目标&#xff0c;阅读速度上来了&#xff0c;思绪也转的飞快。 按图索骥&a…...

vcs仿真教程

VCS是在linux下面用来进行仿真看波形的工具&#xff0c;类似于windows下面的modelsim以及questasim等工具&#xff0c;以及quartus、vivado仿真的操作。 1.vcs的基本指令 vcs的常见指令后缀 sim常见指令 2.使用vcs的实例 采用的是全加器的官方教程&#xff0c;首先介绍不使用…...

java 自定义json解析注解 复杂json解析 工具类

java 自定义json解析注解 复杂json解析 工具类 目录java 自定义json解析注解 复杂json解析 工具类1.背景2、需求-各式各样的json一、一星难度json【json对象中不分层】二、二星难度json【json对象中出现层级】三、三星难度json【json对象中存在数组】四、四星难度json【json对象…...

类的 6 个默认成员函数

文章目录一、构造函数1. 构造函数的定义2. 编译器生成的构造函数3. 默认构造函数4. 初始化列表5. 内置成员变量指定缺省值(C11)二、析构函数1. 析构函数的定义2. 编译器生成的析构函数3. 自己写的析构函数的执行方式三、拷贝构造函数1. C语言值传递和返回值时存在 bug2. 拷贝构…...

基于Verilog HDL的状态机描述方法

⭐本专栏针对FPGA进行入门学习&#xff0c;从数电中常见的逻辑代数讲起&#xff0c;结合Verilog HDL语言学习与仿真&#xff0c;主要对组合逻辑电路与时序逻辑电路进行分析与设计&#xff0c;对状态机FSM进行剖析与建模。 &#x1f525;文章和代码已归档至【Github仓库&#xf…...

6年软件测试经历:成长、迷茫、奋斗

前言 测试工作6年&#xff0c;经历过不同产品、共事过不同专业背景、能力的同事&#xff0c;踩过测试各种坑、遇到过各种bug。测试职场生涯积极努力上进业务和技术能力快速进步过、也有努力付出却一无所得过、有对测试生涯前景充满希望认为一片朝气蓬勃过、也有对中年危机思考不…...

OpenMMLab AI实战营第五次课程

语义分割与MMSegmentation 什么是语义分割 任务&#xff1a; 将图像按照物体的类别分割成不同的区域 等价于&#xff1a; 对每个像素进行分类 应用&#xff1a;无人驾驶汽车 自动驾驶车辆&#xff0c;会将行人&#xff0c;其他车辆&#xff0c;行车道&#xff0c;人行道、交…...

【软考】系统集成项目管理工程师(二十)项目风险管理

一、项目风险管理概述1. 风险概念2. 风险分类3. 风险成本二、项目风险管理子过程1. 规划风险管理2. 识别风险3. 实施定性风险分析4. 实施定量风险分析5. 规划风险应对6. 控制风险三、项目风险管理流程梳理一、项目风险管理概述 1. 风险概念 风险是一种不确定事件或条件,一旦…...

2017-PMLR-Neural Message Passing for Quantum Chemistry

2017-PMLR-Neural Message Passing for Quantum Chemistry Paper: https://arxiv.org/pdf/1704.01212.pdf Code: https://github.com/brain-research/mpnn 量子化学的神经信息传递 这篇文献作者主要是总结了先前神经网络模型的共性&#xff0c;提出了一种消息传递神经网络&am…...

Python:每日一题之全球变暖(DFS连通性判断)

题目描述 你有一张某海域 NxN 像素的照片&#xff0c;"."表示海洋、"#"表示陆地&#xff0c;如下所示&#xff1a; ....... .##.... .##.... ....##. ..####. ...###. ....... 其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿…...

企业级安全软件装机量可能大增

声明 本文是学习大中型政企机构网络安全建设发展趋势研究报告. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 研究背景 大中型政企机构是网络安全保护的重中之重&#xff0c;也是国内网络安全建设投入最大&#xff0c;应用新技术、新产品最多的机构…...

为什么要用频谱分析仪测量频谱?

频谱分析仪是研究电信号频谱结构的仪器&#xff0c;用于信号失真度、调制度、谱纯度、频率稳定度和交调失真等信号参数的测量&#xff0c;可用以测量放大器和滤波器等电路系统的某些参数&#xff0c;是一种多用途的电子测量仪器。从事通信工程的技术人员&#xff0c;在很多时候…...

Python环境搭建、Idea整合

1、学python先要下载什么&#xff1f; 2、python官网 3、idea配置Python 4、idea新建python 学python先要下载什么&#xff1f; python是一种语言&#xff0c;首先你需要下载python&#xff0c;有了python环境&#xff0c;你才可以在你的电脑上使用python。现在大多使用的是pyt…...

HTTP请求返回304状态码以及研究nginx中的304

文章目录1. 引出问题2. 分析问题3. 解决问题4. 研究nginx中的3044.1 启动服务4.2 ETag说明4.3 响应头Cache-Control1. 引出问题 之前在调试接口时&#xff0c;代码总出现304问题&#xff0c;如下所示&#xff1a; 2. 分析问题 HTTP 304: Not Modified是什么意思&#xff1f; …...

【GD32F427开发板试用】使用Arm-2D显示电池电量

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;boc 【虽迟但到】 由于快递的原因&#xff0c;11月份申请的&#xff0c;12月1日才收到GD32F427开发板。虽然姗姗来迟&#xff0c;但也没有减少…...

TS第二天 Typesrcipt编译

文章目录自动编译tsconfig.json配置选项include 比较重要excludeextendsfilescompilerOptions 比较重要自动编译 手动模式&#xff1a;每次ts文件修改完&#xff0c;手动编译一次 tsc 01.ts监视模式&#xff1a;ts文件修改完&#xff0c;自动监视编译 tsc 01.ts -w编译所有文…...

基于C#制作一个飞机大战小游戏

此文主要基于C#制作一个飞机大战游戏&#xff0c;重温经典的同时亦可学习。 实现流程1、创建项目2、界面绘制3、我方飞机4、敌方飞机5、子弹及碰撞检测实现流程 1、创建项目 打开Visual Studio&#xff0c;右侧选择创建新项目。 搜索框输入winform&#xff0c;选择windows窗体…...

电子商务网站基本功能/天津关键词优化专家

微信公众号&#xff1a;infoQc如有问题或建议&#xff0c;请公众号留言最近更新&#xff1a;2018-08-19 包装类型 在讲解正文之前&#xff0c;我很想问这么一个问题&#xff1a;"Java为我们提供了8种基本数据类型&#xff0c;为什么还需要提供各自的包装类型呢&#xff1f…...

wordpress 插件角色/个人网站免费推广

Java的异常 1.Java中所有异常和错误的基类&#xff1a;Throwable     Throwable error        Exception       &#xff08;检查时异常&#xff09;&#xff08;运行时异常&#xff09;              RuntimeException2.Java中的异常分为运行时…...

楚雄州住房和城乡建设局网站/企业网站的推广方式和手段有哪些

...

wordpress 文章点击/郑州发布最新通告

也许是我一直在初创公司度过的时光&#xff0c;但是尽管我非常珍视Scrum的想法&#xff0c;并支持自组织团队和不断的反馈–我不禁感到看板代表了敏捷的新高度&#xff0c;为我们提供了更大的灵活性并从中吸取了教训我们从精益中学到了东西。 Scrum 很多人倾向于认为敏捷意味着…...

网站建设公司做前端/昆明装饰企业网络推广

小目录链接题目描述样例输入样例输出思路代码链接 YbtOJ 木板涂色 Luogu 涂色 题目描述 给出一个长度为5的字符串&#xff0c;现在要求你把一个空的字符串涂色成给出字符串&#xff08;一次可变化多个字符&#xff09;&#xff0c;问最少要几次涂色 样例输入 AAAAA样例输出…...

大城 网站建设/seo是什么化学名称

springcloud 总集&#xff1a;www.tapme.top/blog/detail… 前言 在第四篇和第五篇中提到一个叫关联 id的东西&#xff0c;用这个东西来将所有请求串起来&#xff0c;用来清晰的记录调用过程&#xff0c;以便以微服务的问题调试。 微服务虽然能够将单体软件系统分解为更小的、更…...