首页 > 其他分享 >异步调用中链路信息TRACE丢失问题

异步调用中链路信息TRACE丢失问题

时间:2024-02-16 15:00:42浏览次数:26  
标签:异步 拦截器 span TRACE 信息 ThreadLocal 链路 Span

1、问题描述

链路框架底层为jaegertracing,行内的北斗链路是对这个jaegertracing进行了一层包装

框架中使用自定义注解@RvcAsync来执行异步任务,RvcAsync注解核心逻辑为使用CompletableFuture.runAsync()方法执行多线程任务,传入的第二个参数asyncTaskExecutor为自定义线程池。

1  CompletableFuture.runAsync(() -> {
2             try {
3                 TimeUnit.SECONDS.sleep(1);
4                 this.proceed(point);
5             } catch (Exception ex) {
6                 userLogUtils.logError(ex.getMessage() + ExceptionUtils.getStackTrace(ex));
7             }
8         }, asyncTaskExecutor);

在与主机方进行Http请求的时候,链路信息莫名其妙消失了,通常情况下链路信息会由北斗链路框架中的一个httpInterceptor拦截器对Http请求拦截,然后在请求头中塞入链路信息,使得在调用方和主机方追溯调用链路的时候,主机方找不到渠道端给出的链路ID的日志信息,导致问题追踪困难。

2、问题分析

通过查看源码,链路信息保存在JaegerTracer对象和JaegerSpan中,再继续看JaegerTracer对象的属性,发现内部有一个叫scopeManager的变量,它的内部存放了当前链路中所有的活跃span信息,经过调试发现这个属性注入的具体依赖为为ThreadLocalScopeManager这个类,它内部使用了ThreadLocal类型来保存tlsScope这个变量,这个变量存储的是Span信息,ThreadLocal只在当前线程中生效,当进入子线程当中,httpInterceptor拦截器拦截http,并去获取当前活跃span信息的时候,获取到的span对象为null,这时候作为客户端调用方,则直接放过合格拦截也就是请求头中不再带有链路信息。ThreadLocalScopeManager的代码如下:

 1 public class ThreadLocalScopeManager implements ScopeManager {
 2     final ThreadLocal<ThreadLocalScope> tlsScope = new ThreadLocal<ThreadLocalScope>();
 3 
 4     @Override
 5     public Scope activate(Span span) {
 6         return new ThreadLocalScope(this, span);
 7     }
 8 
 9     @Override
10     public Span activeSpan() {
11         ThreadLocalScope scope = tlsScope.get();
12         return scope == null ? null : scope.span();
13     }
14 }

服务端的链路信息是怎么生成的呢,继续研究发现是一个叫做TracingFilter的拦截器实现的,这个拦截器作用于整个服务,也就是当有请求到controller的时候,会首先被这个filter拦截,这个拦截器的作用就是调用jaegertracing的start方法去拿到Span信息,在这个start方法中,如果有存活的Span,则添加当前的服务的这一跳的Span信息到childrenSpan中,如果没有Span信息,则判断当前为第一跳,生成链路ID,SpanID等链路信息。

3、问题修复

由于我们之前分析,链路丢失的根本原始是scopeManager这个属性,在注入依赖的时候所注入的那个对象ThreadLocalScopeManager,他的内部使用了ThreadLocal来保存span信息,那么我们可以自己定义一个MyScopeManager对象,实现ScopeManager接口,然后指定这个对象为Primary,也就是接口再有多个实现类的情况下,指定当前类为默认bean,在这个MyScopeManager中指定存储Span对象的这个变量为InheribleThreadLocal,并且重写activate和activeSpan方法,这样,在项目启动的时候,加载jaegerTracing这个bean的时候,会注入我们自己定义的ScopeManager,这样就可以实现父子线程之间Span信息的共享了。

待解决问题:由此可见,在jaegerTracing这个bean内部注入ScopeManager的时候,并没有指定注入具体哪一个实现类,因为如果指定了具体实现类,那我们自定义的MyScopeManager,就算加上Primary注解指定为默认bean,但是Spring会优先根据beanName去注入对应的实现类,根绝beanName没找到,才会去注入默认的这个实现类,那么为什么会注入ThreadLocalScopeManager呢,推测可能是bean的加载顺序有关。

标签:异步,拦截器,span,TRACE,信息,ThreadLocal,链路,Span
From: https://www.cnblogs.com/zeevy/p/18017158

相关文章

  • 数据链路层
    一、数据链路层1.链路、数据链路、帧帧2.数据链路层的三个问题A、封装成帧和透明传输B、差错检测发送方通过对数据采用某种差错检测算法计算出一个检错码,接收方也是使用同一算法计算看是否出现误码。C、可靠传输3.可靠传输停止-等待协议回退N帧协议一但出错就需......
  • C#实现异步编程的常用方式总结
    随着现代软件对性能和响应速度的要求越来越高,异步编程已经成为许多开发者必须掌握的技能。C#提供了多种实现异步编程的方式,每种方式都有其特定的适用场景和优缺点。本文将详细介绍C#中实现异步编程的常用方式,帮助读者更好地理解并选择合适的异步编程方法。一、Task和TaskC#......
  • perf与ftrace
    ftraceftrace是一种调试工具,用于了解Linux内核中的情况。如需详细了解ftrace高级功能,请参阅ftrace文档:/Documentation/trace/ftrace.txtFtrace的设计目标简单,本质上是一种静态代码插装技术,不需要支持某种编程接口让用户自定义trace行为。静态代码插装技术更加可靠,不会......
  • 【Java 并发】【队列应用】【一】ArrayBlockingQueue 的使用-Logback异步日志打印
    1 前言看了那么多Java提供的队列工具,那么我们这节开始看看哪些地方用到了这些队列哈。这一节我们讲解logback异步日志打印中ArrayBlockingQueue的使用。2  异步日志打印模型概述在高并发、高流量并且响应时间要求比较小的系统中同步打印日志已经满足不了需求了,这是因为......
  • 链路聚合实验
    拓扑配置pc1pc2LSW1[SW1]intEth-Trunk1//创建一个逻辑口[SW1-Eth-Trunk1]modemanualload-balance//手工聚合模式(手动将成员接口加入),且开启负载均衡[SW1-Eth-Trunk1]trunkportg0/0/2//将物理接口绑定到逻辑口上[SW1-Eth-Trunk1]trunkportg0/0/3[SW1-Eth-Trunk1]......
  • react引用async异步函数数据渲染
    当需要在React组件中引用异步函数获取的数据时,可以使用useState钩子来存储数据,并在组件渲染时进行处理。下面是一个示例,展示了如何在React中引用异步函数的数据并进行渲染:importReact,{useState,useEffect}from'react';functionMyComponent(){const[data,......
  • Java新建一个子线程异步运行方法
    如何在运行主方法的同时异步运行另一个方法,我是用来更新缓存;1.工具类publicclassThreadPoolUtils{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(ThreadPoolUtils.class);privatestaticfinalStringPOOL_NAME="thread-im-runner";//......
  • 【Cisco Packet Tracer】集线器和交换机区别
    ......
  • linux调试工具strace,gdb
    strace用于跟踪系统调用和信号。strace是一个集诊断、调试、统计于一体的工具,我们可以使用strace跟踪程序的系统调用和信号传递分析程序,以解决问题或了解程序工作过程。当然strace与专业的调试工具比如说gdb之类的是没法相比的,因为它不是一个专业的调试器。strace最简......
  • client-go http trace分析耗时
    klog.InitFlags(nil)flag.Parse()deferklog.Flush()cfg,err:=clientcmd.BuildConfigFromFlags("","/root/.kube/config")iferr!=nil{ klog.Fatalf("Errorbuildingkubeconfig:%s",err.Error())}kubeClient,err:=kubern......