dubbo⾃定义路由_⼀种基于dubbo的分布式服务全链路追踪的
解决⽅案
背景
⽬前,微服务和分布式服务架构在互联⽹公司被普遍应⽤,在国内阿⾥dubbo⽤的⽐较多,但是,dubbo只是⼀个rpc框架,缺乏全链路追踪组件,并不像springcloud是⼀个⽣态,包含了各种分布式组件。
我们公司也是⽤dubbo,分布式服务虽然解决了⽔平扩展的问题,但是却⼜带来了其他新的问题,⽐如链路追踪这⼀块,如果是单体应⽤,所有的⽇志都在⼀个项⽬,现在是服务集,各个服务之间的调⽤关系是错综复杂的,同⼀个服务具体是⾛的哪⼀个机器,是根据负载均衡算法路由的,所以不好查⽇志。哪怕是⽤了elk中⼼化⽇志系统,由于同⼀时间并发请求数量⽐较⾼,不同的请求⽇志都混在⼀起,所以最好可以做到链路追踪,尤其是全链路追踪,即不仅仅是在同⼀个项⽬到当前线程的所有⽇志,⽽且还要在不同项⽬之间到同⼀个请求的所有⽇志。
有了全链路追踪,就可以把分布式服务的每个服务节点串起来,从⽽更好的排查故障和监控系统。
具体实现原理是基于业界普遍的分布式追踪id,即把唯⼀的分布式追踪id从⼊⼝处,⼀直往下传递,最后每个服务的⽇志都包含了该分布式服务追踪id。
线程内和跨进程
要解决两⼤问题,
1、解决同⼀个进程内的同⼀个线程的链路追踪
基于java线程本地变量ThreadLocal实现。
2、解决跨进程的链路追踪
即在dubbo的服务消费者和服务提供者之间传递链路id,基于dubbo上下⽂RpcContext实现。
架构图
核⼼设计思想
1、进程内的线程链路追踪
所谓进程内,就是指服务消费者或服务提供者内部的链路追踪,实现原理是基于
1)扩展⽇志框架(⽐如logback)的功能
分布式和微服务的关系2)每次打印⽇志的时候,⾃动携带链路id
2、跨进程的链路追踪
所谓跨进程,就是指服务消费者和服务提供者是两个运⾏在不同机器的进程,实现原理是基于:
1)⾃定义dubbo
实现dubbo的Filter接⼝;
根据当前请求线程的所在进程是服务消费者还是服务提供者,分表做不同的业务逻辑处理。
2)服务消费者
写数据到⽇志ThreadLocal;
在⾥,写数据到dubbo上下⽂RpcContext。
3)服务提供者
在,从dubbo上下⽂RpcContext读数据;
写数据到⽇志ThreadLocal。
总结
1、基于ThreadLocal,实现线程链路追踪。
2、基于dubbo的扩展功能,实现跨进程链路追踪,每个进程都要引⼊链路追踪功能才能实现全链路追踪。
3、链路追踪id被写在每个⽇志的⽇志戳字段⾥,通过在elk中⼼化⽇志系统⾥搜索链路Id,就可以搜索到⼀个请求的完整⽇志信息。链路id ⽇志戳字段,需要⾃⼰扩展⽇志框架功能,⽐如可以基于slf + logback实现。
代码
跨进程
⾃定义扩展dubbo
/**
* dubbo⽇志,作⽤
1.打印消费者和提供者的⼊参和响应
基于dubbo实现
2.全链路追踪
基于⽇志(线程本地变量)和dubbo上下⽂实现。(注:全链路追踪的每个服务,都要配置该,才能实现全链路追踪) */
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
public class AccessLogExtFilter implements Filter {
public Result invoke(Invoker> invoker, Invocation inv) throws RpcException {
...
handleTraceNo();
...
}
/**
* 在消费者和提供者之间传递⽇志戳-流⽔号数据,⽤于链路追踪
*/
private void handleTraceNo() {
boolean isConsumer = Context().isConsumerSide();
if (isConsumer) { //如果是消费者,写数据到dubbo上下⽂
.setAttachment("xxx_TRACE_NO", CurrentThreadLogPreFix(""));
} else { //如果是提供者,从dubbo上下⽂读数据
String traceNo = Context().getAttachment("xxx_TRACE_NO");
if (StringUtils.isBlank(traceNo)) { //如果消费者没有设置流⽔号,就随机⽣成
traceNo = UUID.randomUUID().toString();
}
LogPreFixConverter.setLogPreFixNoAppendThread(traceNo);
}
}
线程内
扩展⽇志框架logback
1)⾃定义字段 配置⽂件
"logback.pattern"
value="%date{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%logPreFix|%class.%method:%line|%extjson|%sensitiveMsg%n" /> logPreFix是⾃定义字段/⽇志戳/全链路id。
2)实现⾃定义字段处理类
略
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论