dubbo链路跟踪

前言

现在分布式系统中一次接口调用都需要多个服务协同完成,其中一个服务出现问题,都会导致最终失败,而查询起来非常不方便。如果在整个链路中,可以通过一个唯一ID(traceId)跟踪本次服务调用,方便查询问题。

代码目录

dubbo链路跟踪

实现

TraceIdUtil.java 用来生产traceId和存储

public class TraceIdUtil {

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

    private static final String HTTP_TYPE = "HTTP-";
    private static final String RPC_TYPE = "RPC-";

    public static String getTraceId() {
        return TRACE_ID.get();
    }

    /**
     * 获取
     *
     * @return traceid
     */
    public static String getTraceId(String type) {
        if (TRACE_ID.get() == null) {
            setTraceId(type + UUID.randomUUID().toString());
        }
        return Optional.ofNullable(TRACE_ID.get()).orElse("");
    }

    public static String getHttpTraceId() {
        return TraceIdUtil.getTraceId(HTTP_TYPE);
    }

    public static String getRpcTraceId() {
        return TraceIdUtil.getTraceId(RPC_TYPE);
    }

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

}

dubbo调用使用spi实现检测是否有traceId

消费者:GlobalTraceConsumerFilter

@Slf4j
@Activate(group = {Constants.CONSUMER}, order = -9999)
public class GlobalTraceConsumerFilter implements Filter {

    private static final String TRACE_ID = "traceId";

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String traceId = TraceIdUtil.getRpcTraceId();
        if (StringUtils.isNotEmpty(traceId)) {
            log.info("consumer当前traceId:{}", traceId);
            RpcContext.getContext().setAttachment(TRACE_ID, traceId);
        } else {
            // 调用无traceID
            RpcContext.getContext().setAttachment(TRACE_ID, TraceIdUtil.getRpcTraceId());
        }
        return invoker.invoke(invocation);
    }
}

生产者:GlobalTraceProviderFilter

@Slf4j
@Activate(group = {Constants.PROVIDER}, order = -9999)
public class GlobalTraceProviderFilter implements Filter {

    private static final String TRACE_ID = "traceId";

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String traceId = invocation.getAttachment(TRACE_ID);
        if (!StringUtils.isBlank(traceId)) {
            log.info("当前traceId:{}", traceId);
            RpcContext.getContext().setAttachment(TRACE_ID, traceId);
            TraceIdUtil.setTraceId(traceId);
        } else {
            log.warn("当前traceId无");
            // 调用无traceID
            RpcContext.getContext().setAttachment(TRACE_ID, TraceIdUtil.getRpcTraceId());
            TraceIdUtil.setTraceId(traceId);
        }
        return invoker.invoke(invocation);
    }
}

对于http请求统一拦截

WebTraceIdFilter.java

@Slf4j
@WebFilter(urlPatterns = "/*")
@Order(-9999)
public class WebTraceIdFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        String httpTraceId = TraceIdUtil.getHttpTraceId();
        log.info("接受http请求添加traceId:{}", httpTraceId);
    }

}

为了让dubbo的spi机制生效还要在resoutces下META-INF/dubbo目录新建文件
com.alibaba.dubbo.rpc.Filter
内容:

gCtrace=com.example.common.traceid.GlobalTraceConsumerFilter
gPtrace=com.example.common.traceid.GlobalTraceProviderFilter

http调用日志:

2019-11-08 18:45:35.175 [DubboServerHandler-10.112.206.222:20990-thread-2] INFO  c.example.common.traceid.GlobalTraceProviderFilter - 当
前traceId:RPC-445e493a-914e-4614-891f-dd9aa248e1c7

可以通过taceId判断请求来源http还是rpc请求。

相关推荐