草庐IT

springboot~openfeign开启熔断之后MDC为null的理解

敢于对过去告一个段落,才有信心掀开新的篇章! 2023-04-16 原文

MDC概念

MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能,也可以说是一种轻量级的日志跟踪工具。

MDC能做什么

那么通过MDC的概念,我们可以知道,MDC是应用内的线程级别,不是分布式的应用层级别,所以仅靠它无法做到分布式应用调用链路跟踪的需求。它要解决的问题主要是让我们可以在海量日志数据中快速捞到可用的日志信息。
场景分析。

原理

既然我们知道MDC底层使用TreadLocal来实现,那根据TreadLocal的特点,它是可以让我们在同一个线程中共享数据的,但是往往我们在业务方法中,会开启多线程来执行程序,这样的话MDC就无法传递到其他子线程了。这时,我们需要使用额外的方法来传递存在TreadLocal里的值。MDC提供了一个叫getCopyOfContextMap的方法,很显然,该方法就是把当前线程TreadLocal绑定的Map获取出来,之后就是把该Map绑定到子线程中的ThreadLocal中了,具体代码如下:

图中有几个MDCAdapter适配器,我们拿BasicMDCAdapter为例,它的put,get这些方法,实事上是对InheritableThreadLocal<Map<String, String>>类型的变量进行操作的,在主线程中获取值,将值转到子线程里使用它。

private InheritableThreadLocal<Map<String, String>> inheritableThreadLocal = new InheritableThreadLocal<Map<String, String>>() {

public Map<String, String> getCopyOfContextMap() {
    Map<String, String> oldMap = inheritableThreadLocal.get();
    if (oldMap != null) {
        return new HashMap<String, String>(oldMap);
    } else {
        return null;
    }
}

public void setContextMap(Map<String, String> contextMap) {
    inheritableThreadLocal.set(new HashMap<String, String>(contextMap));
}
``

也就是说,我们在主线程中获取MDC的值,然后在子线程中设置进去,这样,子线程打印的信息也会带有整个调用链共同的traceId了。

# openfeign
openfeign开启熔断之后MDC为null,这是有前提的,首先,你的熔断开启后,使用的是线程池的熔断模式,即hystrix.command.default.execution.isolation.strategy=THREAD,或者不写这行,如果值是`SEMAPHORE`模式,是可以获取到MDC对象的,因为这种信号量模式,并没有产生新的线程,所以对于ThreadLocal类型的MDC对象,是可以获取到的。
# openFeign的熔断配置

ribbon:

ribbon请求连接的超时时间- 限制3秒内必须请求到服务,并不限制服务处理的返回时间

connectTimeout: 1000

请求处理的超时时间 下级服务响应最大时间,超出时间消费方(路由也是消费方)返回timeout,超时时间不可大于断路器的超时时间

readTimeout: 2000
hystrix:
command:
default:
execution:
timeout:
enabled: true
isolation:
strategy: THREAD #信号量模式,无超时时间;THREAD线程池模块,这是默认的
thread:
timeoutInMilliseconds: 3000 #对THREAD模式才有效
feign:
hystrix:
# Feign启用断路器,默认为FALSE,如果开启熔断,如果是线程池模式,会在新线池中发起请求,这时MDC无论获取到,如果是SEMAPHORE模式,是可以获取到MDC的
enabled: true

# 在openFeign的拦截器中,获取MDC中的traceId
> 注意,咱们的这个拦截器获取traceId功能,只是在SEMAPHORE模式才有效【注意,这种模式的熔断是没有超时时间的,所以性能不太好,高并发时,请求慢的慢,容易堆积,造成服务器的雪崩】

@Configuration
public class FeignTraceIdInterceptor implements RequestInterceptor {

@Override
public void apply(RequestTemplate template) {
	String traceId = MDC.get(TRACE_ID);
	if (traceId != null) {
		template.header(HTTP_HEADER_TRACE, traceId);
	}
}

}

在后面的调研中,我们还会针对THREAD模块进行探究,找到获取MDC中traceId的方法,请期待。

有关springboot~openfeign开启熔断之后MDC为null的理解的更多相关文章

  1. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  2. "\0"null 的 Ruby 测试? - 2

    我在破坏脚本的字符串中出现了一些奇怪的字符。据我所知,通过putbadstring到控制台,它们是"\0\0\0\0"。我想对此进行测试,以便我可以忽略它们...但是如何呢?以为这就是blank?和empty?的用途?!?:>badstring="\0"=>"\u0000">badstring.blank?NoMethodError:undefinedmethod`blank?'for"\u0000":Stringfrom(irb):97from/Users/meltemi/.rvm/rubies/ruby-2.0.0-p195/bin/irb:16:in`'>badstring.em

  3. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  4. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  5. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  6. ruby - 如何理解 Ruby 中的发送者和接收者? - 2

    我很难理解Ruby中sender和receiver的实际含义。它们一般是什么意思?到目前为止,我只是将它们理解为方法调用和获取其返回值的调用。但是,我知道我的理解还远远不够。谁能给我一个Ruby中发送者和接收者的具体解释? 最佳答案 面向对象中的一个核心概念是消息传递和早期概念化,这在很大程度上借鉴了计算的Actor模型。艾伦·凯(AlanKay)创造了面向对象一词并发明了最早的OO语言之一SmallTalk,他拥有voicedregretatusingatermwhichputthefocusonobjectsinsteadofo

  7. ruby-on-rails - Rails - 理解 application.js 和 application.css - 2

    rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:

  8. ruby - 你如何理解 Ruby 中的这个三元条件? - 2

    我在某些代码中遇到了三元组,但我无法理解条件:str.split(/',\s*'/).mapdo|match|match[0]==?,?match:"somestring"end.join我确实理解我是在某些点上拆分字符串并将总结果转换为数组,然后依次处理数组的每个元素。除此之外,我不知道发生了什么。 最佳答案 一种(稍微)不那么令人困惑的写法是:str.split(/',\s*'/).mapdo|match|ifmatch[0]==?,matchelse"somestring"endend.join我认为多行三元语句很糟糕,尤其是

  9. ruby - 您如何将 S3 理解为 Ruby 中的分层目录结构? - 2

    有没有人成功地将S3存储桶读取为子文件夹?文件夹1--子文件夹2----文件3----文件4--文件1--文件2文件夹2--子文件夹3--文件5--文件6我的任务是读取文件夹1。我希望看到子文件夹2、文件1和文件2,但看不到文件3或文件4。现在,因为我将存储桶键限制为prefix=>'folder1/',你仍然会得到file3和4,因为它们在技术上具有folder1前缀。似乎真正做到这一点的唯一方法是吸收folder1下的所有键,然后使用字符串搜索从结果数组中实际排除file3和file4。有没有人有过这方面的经验?我知道像Transmit和Cyber​​duck这样的FTP风格的S3

  10. 联通家庭宽带开启ipv6 - 2

    联通家庭宽带开启ipv6废话不多,直接开干首先登录联通光猫的后台,机身有写我的是http://192.168.1.1/CU.html广州家庭宽带账号密码CUAdmincuadmin00259e这里好像是默认设置,不大记得了。保存就好然后登陆路由器后台,我的是tp-link选桥模式这里的桥模式跟光猫的wan类型应该是互斥关系,光猫设置桥接,路由器就要设pppoe拨号,我没试过。然后在系统就可以查看了或者直接访问这个网址http://testipv6.com/注意1:如果你是便宜小米红米之类的路由器,他好像是默认不打开这个ipv6防火墙的,也就是你可能在系统上看到有ipv6地址,但实际上是不互通的

随机推荐