文档章节

Dubbo链路追踪——生成全局ID(traceId)

BakerZhu
 BakerZhu
发布于 2018/09/10 19:07
字数 903
阅读 1767
收藏 24

全局 traceId

关于链路追踪,在微服务的趋势下,一次调用的日志信息分布在不同的机器上或目录下,当需要看一条链路调用所有的日志信息时,这是个比较困难的地方,我们虽然有ELK , Sentry等日志异常收集分析工具, 但是如何把信息串起来也是一个关键的问题。 我们一般的做法是在系统调用开始时生成一个traceId , 并且它伴随着一次调用的整个生命周期 。 当一个服务调用另外一个服务的时候,traceId 则向下透传,全局使用唯一一个。

一、通过修改Dubbo源码实现全局traceId(侵入性高不建议使用)

我们通过分析源码可以知道客户端在调用服务段进行服务消费时,实际上发送的是封装过的Request实体 ,Data为Invocation实体对象(接口签名,参数类型,参数值,及attachment附件)

final class HeaderExchangeChannel implements ExchangeChannel {
...
    public ResponseFuture request(Object request, int timeout) throws RemotingException {
        if (closed) {
            throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
        }
        // create request.
        Request req = new Request();
        req.setVersion("2.0.0");
        req.setTwoWay(true);
        req.setData(request);
        DefaultFuture future = new DefaultFuture(channel, req, timeout);
        try {
            channel.send(req);
        } catch (RemotingException e) {
            future.cancel();
            throw e;
        }
        return future;
    }
...
}

通过源码可知 request是入参,其他参数均为固定,所以只能在request中做文章。

代码涉及到的类有

  • TraceIdUtil : 链路追踪全局ID生成器
  • InvokerInvocationHandler : 消费端Invocation处理器
  • DubboProtocol : Dubbo协议处理入口,内有服务提供者处理请求数据信息的Handler处理器

TraceIdUtil源码如下

public class TraceIdUtil {

	private static final ThreadLocal<String> TRACE_ID = new ThreadLocal<String>();

	public static String getTraceId() {
		if(TRACE_ID.get() == null) {
			String s = UUID.randomUUID().toString();
			setTraceId(s);
		}
		return TRACE_ID.get();
	}

	public static void setTraceId(String traceId) {
		TRACE_ID.set(traceId);
	}
}

Dubbo线程模型图示可知,Dubbo客户端调用实际上通过JavassistProxyFactory获取的是Proxy代理对象。 Dubbo线程模型图示 代码如下

public class JavassistProxyFactory extends AbstractProxyFactory {
	...
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }
	...
}

其中 InvokerInvocationHandler 调用数据的处理及rpc调用实体的封装过程。所以我们需要在调用的起始位置添加traceId信息 。 traceId

其次是服务提供者进行请求处理过程: DubboProtocol的requestHandler 请求处理器(不明白请详读服务Dubbo服务暴露过程源码) traceId

将traceId 从RpcInvocation 的attachment属性中取出 ,传给TraceIdUtil 方面后续调用过程使用。

扩展Provider端Filter (无侵入性,建议使用)

创建Filter 服务提供者端扩展

/**
 * Created with IntelliJ IDEA.
 *
 * @author: bakerZhu
 * @description:
 * @time: 2018年09月09日
 * @modifytime:
 */
@Activate(group = {Constants.CONSUMER, Constants.PROVIDER} , order = -9999)
public class GlobalTraceFilter implements Filter {

	@Override
	public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
		String traceId = invocation.getAttachment("traceId");
		if(!StringUtils.isBlank(traceId)) {
			RpcContext.getContext().setAttachment("traceId",traceId);
		}else { // 第一次发起调用
			RpcContext.getContext().setAttachment("traceId", UUID.randomUUID().toString());
		}
		return invoker.invoke(invocation);
	}
}

资源文件夹下创建 META-INF/dubbo 文件夹 创建com.alibaba.dubbo.rpc.Filter 文件,并编辑文件内容 gtrace=com.alibaba.dubbo.rpc.filter.GlobalTraceFilter

疑惑点 为什么设置Dubbo上下文的attachment调用时会出现在 RpcInvocation中

详见 AbstractInvoker.invoke(Invocation inv) 方法

public abstract class AbstractInvoker<T> implements Invoker<T> {
    public Result invoke(Invocation inv) throws RpcException {
		......
        Map<String, String> context = RpcContext.getContext().getAttachments();
        if (context != null) {
            invocation.addAttachmentsIfAbsent(context);
        }
        if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
            invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
        }
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
		......
    }
}

将上下文的“附件信息”拷贝到RpcInvocation中

赞赏支持

赞赏支持

© 著作权归作者所有

共有 人打赏支持
BakerZhu
粉丝 105
博文 517
码字总数 423086
作品 0
通州
程序员
私信 提问
Dubbo + Zipkin + Brave实现全链路追踪

Dubbo + Zipkin + Brave实现全链路追踪 最近写了一个链路追踪Demo分享下,实现了链路追踪过程中数据的记录,还有能扩展的地方,后期再继续补充。 原理参考上面文章 《Dubbo链路追踪——生成全...

BakerZhu
2018/09/14
0
4
分布式系统调用链监控

分布式系统调用链监控 应用架构由集中式向分布式演进后,整个调用关系变得复杂。 分布式架构由复杂且较大规模集群构成,各个应用之间相当独立,可能由不同团队、不同语言实现。 系统一个完整...

wangyangzhizhou
2016/12/23
0
0
服务化改造实践(三) | Dubbo + Zipkin

随着业务的发展,应用的规模不断的扩大,传统的应用架构无法满足诉求,服务化架构改造势在必行,以 Dubbo 为代表的分布式服务框架成为了服务化改造架构中的基石。随着微服务理念逐渐被大众接...

阿里云云栖社区
2018/10/24
0
0
#研发解决方案介绍#Tracing(鹰眼)

郑昀 最后更新于2014/11/12 GoogleDapper、分布式跟踪、鹰眼、Tracing、HBase、HDFS、 本文档适用人员:研发 分布式系统为什么需要 Tracing? 先介绍一个概念:分布式跟踪,或分布式追踪。 ...

旁观者-郑昀
2014/12/17
0
1
分布式调用跟踪系统调研笔记

分布式调用链跟踪系统通常有几个设计目标 低侵入性 -- 作为非业务组件,应当尽可能少侵入或者无侵入其他业务系统,对于使用方透明,减少开发人员的负担; 灵活的应用策略 -- 可以(最好随时)...

ginobefun
2017/05/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

RadosClient OSDC

RadosClient.h class librados::RadosClient : public Dispatcher//继承自Dispatcher(消息分发类){public: using Dispatcher::cct; md_config_t *conf;//配置文件private: ......

banwh
43分钟前
1
0
如果让你写一个消息队列,该如何进行架构设计?

面试题 如果让你写一个消息队列,该如何进行架构设计?说一下你的思路。 面试官心理分析 其实聊到这个问题,一般面试官要考察两块: 你有没有对某一个消息队列做过较为深入的原理的了解,或者...

李红欧巴
今天
4
0
错题

无知的小狼
今天
2
0
PowerShell因为在此系统中禁止执行脚本的解决方法

参考:window系统包管理工具--chocolatey 报错提示: & : 无法加载文件 C:\Users\liuzidong\AppData\Local\Temp\chocolatey\chocInstall\tools\chocolateyInstall.ps1,因为在此系统上禁止运...

近在咫尺远在天涯
今天
3
0
TP5 跨域请求处理

https://blog.csdn.net/a593706205/article/details/81774987 https://blog.csdn.net/wyk9916/article/details/82315700...

15834278076
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部