微服务全链路跟踪:jaeger集成hystrix
微服务全链路跟踪:jaeger集成istio,并兼容uber-trace-id与b3
背景
> 当springcloud服务集成hystrix,并且用了hystrixCommend注解到方法上时,jaeger链路会断掉
方案
在网上搜索到了大量jaeger遇到多线程时的处理方式,都是包装线程池来做到ThreadLocal传递,有很多都用到了阿里开源的transmittable-thread-local。
下面说一下当集成hystrix时,jaeger链路丢失问题,大家都知道hystrix默认是线程池隔离,所以归根结底还是遇到多线程线程变量没有共享的问题,网上也罗列了几种方案:
方案一:变更隔离方式
hystrix.command.default.execution.isolation.strategy: SEMAPHORE
当并发高时这里设置信号量隔离是有风险的,可以根据情况优化断路器配置来降低风险
方案二:自定义隔离策略
隔离策略官方文档有定义:

原先我就定义了一个feign传递request中header信息的策略,在原有的隔离策略下面参考https://github.com/opentracing-contrib/java-concurrent项目的代码:

将原有feign自定义隔离策略做了响应变动,代码如下
/**
* 自定义Feign的隔离策略:
* 在转发Feign的请求头的时候, 如果开启了Hystrix,
* Hystrix的默认隔离策略是Thread(线程隔离策略), 因此转发拦截器内是无法获取到请求的请求头信息的,
* 可以修改默认隔离策略为信号量模式:hystrix.command.default.execution.isolation.strategy=SEMAPHORE,
* 这样的话转发线程和请求线程实际上是一个线程, 这并不是最好的解决方法, 信号量模式也不是官方最为推荐的隔离策略;
* 另一个解决方法就是自定义Hystrix的隔离策略:
* 思路是将现有的并发策略作为新并发策略的成员变量,在新并发策略中,
* 返回现有并发策略的线程池、Queue;将策略加到Spring容器即可;
*/
@Component
@Slf4j
public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
private HystrixConcurrencyStrategy delegate;
@Lazy
@Autowired
private Tracer tracer;
public FeignHystrixConcurrencyStrategy() {
try {
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
if (this.delegate instanceof FeignHystrixConcurrencyStrategy) {
// Welcome to singleton hell...
return;
}
HystrixCommandExecutionHook commandExecutionHook =
HystrixPlugins.getInstance().getCommandExecutionHook();
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
HystrixPropertiesStrategy propertiesStrategy =
HystrixPlugins.getInstance().getPropertiesStrategy();
this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
HystrixPlugins.reset();
HystrixPlugins instance = HystrixPlugins.getInstance();
instance.registerConcurrencyStrategy(this);
instance.registerCommandExecutionHook(commandExecutionHook);
instance.registerEventNotifier(eventNotifier);
instance.registerMetricsPublisher(metricsPublisher);
instance.registerPropertiesStrategy(propertiesStrategy);
} catch (Exception e) {
log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
}
}
private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
HystrixMetricsPublisher metricsPublisher,
HystrixPropertiesStrategy propertiesStrategy) {
if (log.isDebugEnabled()) {
log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
+ this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
+ metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
}
}
@Override
public <t> Callable<t> wrapCallable(Callable<t> callable) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return new WrappedCallable<>(callable, requestAttributes,tracer,tracer.activeSpan());
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixProperty<integer> corePoolSize,
HystrixProperty<integer> maximumPoolSize,
HystrixProperty<integer> keepAliveTime,
TimeUnit unit, BlockingQueue<runnable> workQueue) {
return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
unit, workQueue);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixThreadPoolProperties threadPoolProperties) {
return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
@Override
public BlockingQueue<runnable> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}
@Override
public <t> HystrixRequestVariable<t> getRequestVariable(HystrixRequestVariableLifecycle<t> rv) {
return this.delegate.getRequestVariable(rv);
}
static class WrappedCallable<t> implements Callable<t> {
private final Callable<t> target;
private final RequestAttributes requestAttributes;
private final Span span;
private final Tracer tracer;
public WrappedCallable(Callable<t> target, RequestAttributes requestAttributes,Tracer tracer, Span span) {
this.target = target;
this.requestAttributes = requestAttributes;
this.tracer=tracer;
this.span=span;
}
@Override
public T call() throws Exception {
Scope scope = span == null ? null : tracer.scopeManager().activate(span);
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return target.call();
} finally {
RequestContextHolder.resetRequestAttributes();
if (scope != null) {
scope.close();
}
}
}
}
}
其中改动部分就是在原有的WrappedCallable中增加了span、trace的注入。
至于自定义隔离策略以及Callable是可以支持多个链的,这里不做详细描述,大家有兴趣可以参考,下面的链接:
https://blog.csdn.net/songhaifengshuaige/article/details/80345012
https://www.jianshu.com/p/c60fe209a799
https://www.cnblogs.com/duanxz/p/10949816.html
微服务全链路跟踪:jaeger集成hystrix的更多相关文章
- Go微服务全链路跟踪详解
在微服务架构中,调用链是漫长而复杂的,要了解其中的每个环节及其性能,你需要全链路跟踪. 它的原理很简单,你可以在每个请求开始时生成一个唯一的ID,并将其传递到整个调用链. 该ID称为Correlati ...
- Spring Cloud 微服务分布式链路跟踪 Sleuth 与 Zipkin
Zipkin 是一个开放源代码分布式的跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集.存储.查找和展现.它的理论模型来自于Google ...
- 微服务, 架构, 服务治理, 链路跟踪, 服务发现, 流量控制, Service Mesh
微服务, 架构, 服务治理, 链路跟踪, 服务发现, 流量控制, Service Mesh 微服务架构 本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件.本文侧 ...
- 微服务之分布式跟踪系统(springboot+zipkin+mysql)
通过上一节<微服务之分布式跟踪系统(springboot+zipkin)>我们简单熟悉了zipkin的使用,但是收集的数据都保存在内存中重启后数据丢失,不过zipkin的Storage除了 ...
- SpringCloud初体验:六、利用 Sleuth 和 Zipkin 给微服务加上链路监控追踪查看功能
首先:装上 Zipkin 服务,收集调用链跟踪数据,体验时装在了本机docker上, 方便快捷 docker run -d -p : openzipkin/zipkin 安装后访问地址也是 9411端 ...
- springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin
相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...
- SpringBoot 整合 Elastic Stack 最新版本(7.14.1)分布式日志解决方案,开源微服务全栈项目【有来商城】的日志落地实践
一. 前言 日志对于一个程序的重要程度不用过多的言语修饰,本篇将以实战的方式讲述开源微服务全栈项目 有来商城 是如何整合当下主流日志解决方案 ELK +Filebeat . 话不多说,先看实现的效果图 ...
- SpringBoot之微服务日志链路追踪
SpringBoot之微服务日志链路追踪 简介 在微服务里,业务出现问题或者程序出的任何问题,都少不了查看日志,一般我们使用 ELK 相关的日志收集工具,服务多的情况下,业务问题也是有些难以排查,只能 ...
- IDEA 集成 Docker 插件实现一键远程部署 SpringBoot 应用,无需三方依赖,开源微服务全栈项目有来商城云环境的部署方式
一. 前言 最近有些童鞋对开源微服务商城项目 youlai-mall 如何部署到线上环境以及项目中 的Dockerfile 文件有疑问,所以写了这篇文章做个答疑以及演示完整的微服务项目发布到线上的流程 ...
- 全链路跟踪skywalking简介
该文章主要包括以下内容: skywalking的简介 skywalking的使用,支持多种调用中间件(httpclent,springmvc,dubbo,mysql等等) skywalking的tra ...
随机推荐
- UIButton选择状态下长按时会变回原始状态
问题大概就像这样 (请无视那红字) 一般而言这是高亮状态的设置有所缺乏.完善代码如下: [_pupilBtn setImage:[UIImage imageNamed:@"a1"] ...
- 关于 KL 散度和变分推断的 ELBO
01 KL 散度 Kullback-Leibler (KL) 散度,是一种描述 一个概率分布 \(P\) 相对于另一个概率分布 \(Q\) 的非对称性差异的概念. KL 散度是非负的:当且仅当两个分布 ...
- TensorFLow手写字识别深度学习网络分析详解
Tensorflow和MNIST简介 TensorFlow 是一个采用数据流图,用于数值计算的开源软件库.它是一个不严格的"神经网络"库,可以利用它提供的模块搭建大多数类型的神经网 ...
- [AGC030C] Coloring Torus
非常巧妙的一道构造题,发现对于所构造的 \(n\) 有上限,那么对于 \(K<=500\) 的情况,很好构造,每行全是一个数就行了,对于 \(K>500\) 的情况,显然每行都是 \(1, ...
- 算法金 | 致敬深度学习三巨头:不愧是腾讯,LeNet问的巨细。。。
大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 抱个拳,送个礼 读者参加面试,竟然在 LeNet 这个基础算法上被吊打~ LeNe ...
- TP5 连接多个数据库
use think\Config; $config = Config::get('database2'); //读取第二个数据库配置 $connect = Db::connect($config); ...
- 玄机-第一章 应急响应- Linux入侵排查
目录 前言 简介 应急开始 准备工作 步骤 1 步骤 2 步骤 3 步骤 4 步骤5 总结 前言 作者这一次也是差一点一次过,因为没有经验的原因,或者说题目对问题描述不太对,如果说是求黑客反连的ip的 ...
- sql server 编写函数,去除小数点后多余的0
sql server 编写函数,去除小数点后多余的0 要在 SQL Server 中编写一个函数来去除小数点后多余的零,你可以使用以下示例的方法: CREATE FUNCTION dbo.Remove ...
- WPF/C#:实现导航功能
前言 在WPF中使用导航功能可以使用Frame控件,这是比较基础的一种方法.前几天分享了wpfui中NavigationView的基本用法,但是如果真正在项目中使用起来,基础的用法是无法满足的.今天通 ...
- SQL 注入漏洞详解 - Union 注入
1)漏洞简介 SQL 注入简介 SQL 注入 即是指 Web 应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在 Web 应用程序中事先定义好的查询语句的结尾上添加额外的 SQL 语句,在 ...