背景

在微服务系统里服务非常的分散,服务日志也分散在各处,多个服务没有统一并且唯一的检索条件,导致问题排查难度很大,因此trace链路追踪技术就应运而生。


一、trace-dubbo组件介绍

github:https://github.com/zbrave429/dubbo-trace

dubbo-trace基于dubbo3.x实现了traceId,spanId链路传递,使用非常简单,代码0侵入,maven直接引入即可

二、设计原理

2.1 原理图

官方文档:https://dubbo.apache.org/zh/docs/v3.0/references/features/attachment/



从图中可以看到,左边为consumer,右边为provider

在consumer端filter里面setAttachment 放入trace参数,在provider端filter里面getAttachment获取trace参数,执行后续处理。

原理已经很清楚了,接下来就是干

2.2 实现方案

  • 请求入口将trace信息缓存到ThreadLocal内和Log参数
  • consumer在发起dubbo调用时从ThreadLocal内获取trace信息设置到Attachment参数内
  • provider接收到请求后从Attachment获取到trace信息缓存到ThreadLocal和Log内

2.2.1 consumer端实现

// CommonConstants.CONSUMER 客户端过滤器
@Activate(group = {CommonConstants.CONSUMER})
public class TraceConsumerFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 1.从ThreadLocal内获取trace信息
Tracer tracer = TraceContext.get();
if (!Objects.isNull(tracer)){
// 2.trace信息设置到Attachment内
setTrace(invocation, tracer);
}
// 3.执行调用
return invoker.invoke(invocation);
}
}

2.2.2 provider端实现

// CommonConstants.PROVIDER
@Activate(group = {CommonConstants.PROVIDER})
public class TraceProviderFilter implements Filter { @Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 1.获取attachments参数
Map<String, String> attachments = invocation.getAttachments();
// 2.构建trace信息
Tracer tracer = buildTracer(attachments);
try{
// 3.将trace信息存到ThreadLocal内和Log参数内
initTraceContext(tracer);
// 4.执行业务
return invoker.invoke(invocation);
} finally {
// 5.清除trace信息,防止线程污染
removeTraceContext();
}
}
}

2.2.3 traceId和spanId生成算法

不在本篇文章讨论范围,感兴趣可以自行clone代码

git clone https://github.com/zbrave429/dubbo-trace.git

2.2.4 ThreadLocal局限性

理想状态下trace信息应该在一次请求的所有执行线程内进行传递,但是ThreadLocal无法在子线程内传递,因此java引入了InheritableThreadLocal ,InheritableThreadLocal可以解决主线程创建子线程时,子线程获取缓存数据的场景。但是目前更多的是使用线程池,线程池一般在服务启动时初始化,就导致通过线程池执行异步操作trace信息丢失的问题。

为了彻底解决这个问题我们可以引入阿里的线程池组件transmittable-thread-local,dubbo-trace组件已经集成,原理和使用大家可以自行百度

或参考 https://github.com/zbrave429/async-task

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.4</version>
</dependency>

三、使用步骤

3.1.clone项目

git clone https://github.com/zbrave429/dubbo-trace.git

3.2.打包

maven install

3.3.maven工程引入依赖

<dependency>
<groupId>com.brave</groupId>
<artifactId>dubbo-trace</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

3.4.日志输出配置

日志输出格式内增加配置 %X{traceId} %X{spanId}

  • %X{traceId}:traceId参数
  • %X{spanId}:spanId参数,调用树

3.5.服务入口调用初始化方法

/**
* IdGenEnum idGenEnum id生成器类型,目前支持两种
* UUID - 通过UUID生成的lang整形19位带符号数字
* CURRENT_TIME - 通过(时间戳11位 + 自增ID4位 + 随机数4位)生成的19位字符串
*
* prefix 前缀,拼接在系统内置的算法生成的字符串之前,CURRENT_TIME模式下才有效,
* 用来增强traceId的唯一性,例如:prefix = IP + APPKEY
*/ TraceContext.init(IdGenEnum idGenEnum, String prefix);

总结

希望本篇文章能对大家有所帮助,后续会持续在这个项目上集成更多实用的功能,例如:压测标记传递,泳道测试环境,线上测试链路,打点监控等。github上点个star,多多支持!

最新文章

  1. [Note] Software Testing
  2. java(2)之前往对象村
  3. AC日记—— codevs 1031 质数环(搜索)
  4. sqlzoo.net刷题3
  5. asp.net 播放flash
  6. 架设wordpress再vps上的 一些感想总结
  7. 不要再坑人啦!NSOperation才是苹果推荐使用的多线程技术!
  8. beep的控制程序
  9. Docker部署JavaWeb项目实战(转)
  10. Leetcode:Minimus Depth of Binary Tree
  11. MVC3+EF4.1学习系列(三)-----排序 刷选 以及分页
  12. 测试MarsEdit
  13. CCF2013123最大的矩形(C语言版)
  14. .Net轻量级ORM-NPoco的使用方法-摘自NPoco国外官方Wiki
  15. JavaScript中你所不知道的Object(一)
  16. 关于CKEditor4.5.6的使用,自定义toolbar配置,上传图片案例(SpringMVC+MyBatis案例),自定义行高,去编辑器的中内容,将编辑器中内容设置到指定的位置等
  17. python——几种截图对比方式!
  18. Redis数据结构之skiplist
  19. VSS(Virtual Switching System)
  20. mysql explain中的 “Select tables optimized away”

热门文章

  1. C语言中的typedef跟define的区别
  2. NSURL组成部分详解
  3. 它来了,那个最帅的男人来了 Linux常用命令精华讲解 中部
  4. 通过安装HomeBrew来安装Python3
  5. SYSTEM表空间满,解决方法
  6. DDD-领域驱动设计简谈
  7. Nginx服务器SSL证书安装
  8. 关于WebStorm 破解
  9. python-利用pymysql获取数据简单使用总结
  10. TestNG基本使用