关于Spring Cloud + Dubbo的链路追踪及traceId方案及思考(2)

关于Spring Cloud + Dubbo的链路追踪及traceId方案及思考(2)

    • Spring Cloud + dubbo的traceId方案
      • 1. 使用SkyWalking作为日志traceId工具
      • 2. 使用Spring Cloud Sleuth作为日志traceId工具
        • 2.1 默认情况下,Spring Cloud Sleuth支持服务之间http请求的traceId的传递。如最为常见的Feign和RestTemplate等。
        • 2.2扩展Dubbo支持Sleuth的traceId的传递

Spring Cloud + dubbo的traceId方案

因为我们公司使用ELK作为日志分析系统,日志的链路追踪在问题定位是哪个尤为重要。如何把同一个请求经过的多个服务的所有日志拉取出来呢?这里的思路是在链路日志中放入traceId,把相同的trackId的日志抽取出来,就形成了整条链路的日志。

1. 使用SkyWalking作为日志traceId工具

方案一:(1)由于之前选择了SkyWalking作为服务链路监控工具,所以自然而然想到SkyWalking中的traceId是否能复用到日志中。

  • 使用 maven 依赖相应的工具包
<dependency>
   <groupId>org.apache.skywalkinggroupId>
   <artifactId>apm-toolkit-logback-1.xartifactId>
   <version>6.6.0version>
dependency>
  • 在logback.xml中的Pattern配制节中,设置%tid
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%nPattern>
            layout>
        encoder>
    appender>
  • 当你使用-javaagent参数激活sky-walking的探针, 如果当前上下文中存在traceid,logback将在输出traceId。如果探针没有被激活,将输出TID: N/A.而且SkyWalking是基于字节码增强的,traceId的传递依赖于SkyWalking的服务端,如果服务端异常等客户端连接不上服务端的情况,就会出现TID: [Ignored Trace]的情况。
  • 效果如下:
    • Http 请求
      关于Spring Cloud + Dubbo的链路追踪及traceId方案及思考(2)_第1张图片在这里插入图片描述
    • Dubbo请求
      在这里插入图片描述
      在这里插入图片描述

2. 使用Spring Cloud Sleuth作为日志traceId工具

方案二:(2)在上面的方案中,日志的traceId是否有,依赖SkyWalking的服务端与客户端的连接。某些场景下,可能会丢失traceId。所以考虑到第二种方案就是通过Spring Cloud Sleuth生成和传递traceId,但是对源码有一定的侵入性。所以大家在方案选择的时候,可以根据实际情况选择。

2.1 默认情况下,Spring Cloud Sleuth支持服务之间http请求的traceId的传递。如最为常见的Feign和RestTemplate等。

  • 使用maven依赖
<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-sleuthartifactId>
dependency>
  • 在logback.xml中的Pattern配制节中,设置%X{X-B3-TraceId}
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
        	<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [traceId:%X{X-B3-TraceId}] [%thread] %-5level %logger{36} -%msg%nPattern>
        encoder>
    appender>
  • 启动效果在这里插入图片描述
  • 请求后效果
    关于Spring Cloud + Dubbo的链路追踪及traceId方案及思考(2)_第2张图片

2.2扩展Dubbo支持Sleuth的traceId的传递

注意:Spring Cloud Sleuth不支持服务在dubbo调用之间传递,所以我们要扩展dubbo的代码
从Dubbo官网可以看到,Dubbo官方提供Filter的SPI扩展。

  • 1.所以我们在服务消费者和生产者中引入dubbo依赖
<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubboartifactId>
    <scope>providedscope>
dependency>
  • 2.编写Dubbo的自定义Filter
    • consumer端把Sleuth放在日志MDC中的traceId拿出来放到Dubbo的上下文中,
    • provider端把Dubbo上下文中的traceId拿出来放到日志MDC中。
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.MDC;

/**
 * @author Marvin
 * @version 1.0.0
 * @date 2020-06-05 14:51
 */
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, value = "tracing")
@Slf4j
public class DubboTraceFilter implements Filter {

    /**
     * TraceId key
     */
    static final String TRACE_ID = "X-B3-TraceId";
    /**
     * SpanId key
     */
    static final String SPAN_ID = "X-B3-SpanId";

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 获取dubbo上下文中的traceId
        String traceId = RpcContext.getContext().getAttachment(TRACE_ID);
        if (StringUtils.isBlank(traceId) ) {
            // customer 设置traceId到dubbo的上下文
            RpcContext.getContext().setAttachment(TRACE_ID, MDC.get(TRACE_ID));
        } else {
            // provider 设置traceId到日志的上下文
            MDC.put(TRACE_ID, traceId);
        }
        //log.info(MDC.get(TRACE_ID));
        Result result = invoker.invoke(invocation);
        return result;
    }
}
  • 3.在项目中引入Filter
    • 在resources目录下创建META-INF目录,在META-INF目录下创建dubbo目录
    • 在dubbo目录下创建org.apache.dubbo.rpc.Filter文件
      目录结果如下:
      在这里插入图片描述
      org.apache.dubbo.rpc.Filter文件内容如下
    traceFilter=com.marvin.light.starter.trace.filter.DubboTraceFilter
    
    • 在配置文件中新增配置
    dubbo:
    consumer:
      filter: traceFilter
    provider:
      filter: traceFilter
    
  • 4.最终效果
    Dubbo的consumer调用日志:
    关于Spring Cloud + Dubbo的链路追踪及traceId方案及思考(2)_第3张图片
    Dubbo的Provider日志:
    在这里插入图片描述

你可能感兴趣的:(微服务)