dubbo链路跟踪

39次阅读

共计 2799 个字符,预计需要花费 7 分钟才能阅读完成。

前言

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

代码目录

实现

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 请求。

正文完
 0