dubbob架构中链路追踪的实现

原文链接: https://blog.csdn.net/GAMEloft9/article/details/82621036

在基于dubbo的分布式应用集群中,调试会变得比较麻烦,不知道一个请求会被发送到哪一台机器上。我们可以通过dubbo的SPI扩展中的调用拦截扩展,来解决这个问题。 dubbo的调用拦截扩展可以对服务提供方和消费方的调用进行拦截,然后加入自己的处理逻辑。通过简单的三个步骤即可实现一个自定义的调用拦截扩展。

1、扩展配置

在dubbo的xml配置文件中,加入filter配置,如下所示:

<!-- 消费方调用过程拦截 -->
<dubbo:reference filter="xxx,yyy" />
<!-- 消费方调用过程缺省拦截器,将拦截所有reference -->
<dubbo:consumer filter="xxx,yyy"/>
<!-- 提供方调用过程拦截 -->
<dubbo:service filter="xxx,yyy" />
<!-- 提供方调用过程缺省拦截器,将拦截所有service -->
<dubbo:provider filter="xxx,yyy"/>

2、配置实现

在META-INF中创建dubbo文件夹,然后在dubbo文件夹下创建com.alibaba.dubbo.rpc.Filter文本文件,如下所示:

然后编辑该文本文件,指定filter的实现类,例如:

xxx=com.gameloft9.XxxFilter

3、编写实现类

 通过实现dubbo的Filter接口,实现具体的拦截逻辑,例如:

package com.gameloft9;
 
import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
 
public class XxxFilter implements Filter {
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // before filter ...
        Result result = invoker.invoke(invocation);
        // after filter ...
        return result;
    }
}


   Slf4j接口里面有MDC,熟悉logback的同学应该不会陌生,我们可以通过MDC,将有用的信息打印到日志里面去。接下来我们就通过MDC和调用拦截扩展来实现分布式的调用追踪。

1、扩展配置

<!--配置filter,在filter里面处理traceId-->
<dubbo:provider filter="traceid"/>
<dubbo:consumer filter="traceid"/>

2、配置实现类

traceid=com.gameloft9.demo.filter.TraceDubboFilter

3、编写实现逻辑

 逻辑很简单,当consumer调用时,将生成的traceId放入rpc context,provider接收到请求时,从traceId获取到traceId,并放入MDC。

package com.gameloft9.demo.filter;
 
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.gameloft9.demo.util.TraceUtil;
import lombok.extern.slf4j.Slf4j;
 
 
@Slf4j
@Activate(order = 1000, group = {Constants.PROVIDER, Constants.CONSUMER})
public class TraceDubboFilter implements Filter {
	public TraceDubboFilter(){
        super();
	}

public Result invoke(Invoker<?> invoker, Invocation invocation)
		throws RpcException {
	RpcContext context = RpcContext.getContext();
	if (context.isConsumerSide()) {
		TraceUtil.putTraceInto(context);
	} else if (context.isProviderSide()) {
		TraceUtil.getTraceFrom(context);
	}
	return invoker.invoke(invocation);
}

}
对traceId的处理,封装到了一个工具类中:

package com.gameloft9.demo.util;
 
import com.alibaba.dubbo.rpc.RpcContext;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
 
import java.util.UUID;
 
/**
 * traceId工具类
 * Created by gameloft9 on 2018/9/7.
 */
public class TraceUtil {
 
    public final static String TRACE_ID = "trace_id";
 
    /**
     * 初始化traceId,由consumer调用
     */
    public static void initTrace() {
        String traceId = generateTraceId();
        setTraceId(traceId);
    }
 
    /**
     * 从Dubbo中获取traceId,provider调用
     * @param context
     */
    public static void getTraceFrom(RpcContext context) {
        String traceId = (String) context.getAttachment(TRACE_ID);
        if (traceId == null) {
            traceId = generateTraceId();
        }
 
        setTraceId(traceId);
    }
 
    /**
     * 把traceId放入dubbo远程调用中,consumer调用
     * @param context
     */
    public static void putTraceInto(RpcContext context) {
        String traceId = getTraceId();
        if (traceId != null) {
            context.setAttachment(TRACE_ID, traceId);
        }
    }
 
    /**
     * 从MDC中清除traceId
     */
    public static void clearTrace() {
        MDC.remove(TRACE_ID);
    }
 
    /****************************私有方法区*********************************/
    
    /**
     * 从MDC中获取traceId
     * */
    private static String getTraceId() {
        return MDC.get(TRACE_ID);
    }
 
    /**
     * 将traceId放入MDC
     * @param traceId
     */
    private static void setTraceId(String traceId) {
        if (StringUtils.isNotBlank(traceId)) {
            traceId = StringUtils.left(traceId, 36);
        }
        MDC.put(TRACE_ID, traceId);
    }
 
    /**
     * 生成traceId
     * @return
     */
    static private String generateTraceId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }
 
}

如何使用:
1、consumer端

ICalculator demo = (ICalculator)context.getBean("calculator");
TraceUtil.initTrace();
int res = demo.add(1,3);
log.info("测试结果:{}",res);

2、provider端

provider端不需要做任何操作,读取traceId和设置MDC都在filter里面做了。

3、logback配置

 logback中,通过%X{trace_id}读取MDC 中的traceId,并打印出来。
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%.15thread] [%X{trace_id}] %logger{36} - %.-4096msg%n
        </pattern>
    </encoder>
</appender>

原文链接:https://blog.csdn.net/GAMEloft9/article/details/82621036

猜你喜欢

转载自blog.csdn.net/Jatham/article/details/102567598