
为 Dubbo 服务接入 CAT 监控cross 报表、依赖分析与全链路 Trace 实战【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址: https://gitcode.com/gh_mirrors/ca/cat导读本文围绕本仓库integration/apache-dubbo目录下的 Dubbo 与 CAT 整合插件展开讲解如何以最小的接入成本仅引入一个 Maven 依赖为基于 Dubbo 的微服务系统开启调用监控使每一次 RPC 调用自动产生跨服务cross报表、依赖分析dependency、服务端 matrix 以及调用链路 trace 数据。读完本文你将掌握该插件的接入方式、手动启停 API、底层 Filter 拦截与消息树上下文透传原理以及两类错误打点的分类口径可直接用于排查 Dubbo 调用的耗时与异常问题。一、插件定位一行依赖带来的监控能力该插件名为cat-monitor其设计目标非常聚焦监控当前系统 Dubbo 调用的执行情况包括耗时以及异常统计。与手工埋点不同它基于 Dubbo 的 Filter 扩展机制自动生效业务代码零侵入。按官方接入说明只需在 Maven 中引入插件包dependency groupIdnet.dubboclub/groupId artifactIdcat-monitor/artifactId version0.0.6/version /dependencyThats All!添加以上依赖之后CAT 服务端即会出现以下报表插件自身说明trace 信息在 CAT 1.0.8 及以后版本提供cross 报表跨服务调用统计展示调用方与被调用方之间的调用量、耗时、成功率dependency 报表服务依赖关系图用于梳理服务间调用拓扑服务端 matrix 报表服务端处理矩阵观察各接口的响应时间分布调用链路 trace 信息从消费端到提供端的完整消息树串联可用于单次调用的全链路追踪。需要说明的是仓库中实际上维护了两套同名插件实现分别面向不同 Dubbo 版本线integration/apache-dubbo基于org.apache.dubbo:dubbo:2.7.15的新版实现其 pom.xml 将 Dubbo 声明为provided作用域依赖运行时环境自带integration/dubbo基于com.alibaba.dubbo2.x 时代的旧版实现源码结构与新版本基本一致仅包名不同如com.alibaba.dubbo.common.Constants对应新版的org.apache.dubbo.common.constants.CommonConstants。因此接入时需按自身 Dubbo 版本选择对应实现使用 Apache Dubbo 2.7.x 请参考integration/apache-dubbo使用阿里 Dubbo 2.x 请参考integration/dubbo。二、手动开启 / 关闭监控插件默认在引入依赖后即自动生效同时提供全局开关 API便于在特殊场景如灰度验证、故障期间临时关闭监控下动态控制DubboCat.disable(); // 关闭 dubbo cat 监控 DubboCat.enable(); // 开启 dubbo cat 监控该开关的实现位于 DubboCat.java核心逻辑如下public class DubboCat { private static boolean isEnable true; public static void disable() { isEnable false; } public static void enable() { isEnable true; } public static boolean isEnable() { boolean isCatEnabled false; try { isCatEnabled Cat.getManager().isCatEnabled(); } catch (Throwable e) { CatLogger.getInstance().error([DUBBO] Cat init error., e); } return isCatEnabled isEnable; } }从源码可以看到两个关键细节isEnable()是双重校验既要插件自身开关为开启状态又要求 CAT 客户端全局可用Cat.getManager().isCatEnabled()。若 CAT 客户端初始化失败或未配置监控会自动失效而不会影响 Dubbo 调用本身开关是静态变量进程内全局生效当 CAT 客户端初始化抛出异常时插件会记录[DUBBO] Cat init error.日志后降级为不采集体现了监控失败不影响业务调用的设计原则。三、核心原理基于 Dubbo Filter 的自动埋点插件的自动埋点能力完全依赖 Dubbo 的 SPI 扩展机制。核心过滤器 CatTransaction.java 通过Activate注解同时激活在 PROVIDER 和 CONSUMER 两侧并设置order -9000抢占过滤链的最前端Activate(group {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order -9000) public class CatTransaction implements Filter {order -9000意味着该 Filter 在调用链中尽可能早执行从而能捕获最完整的调用耗时包含后续所有过滤器与真实调用的时间。整个invoke流程的核心步骤为开关校验若DubboCat.isEnable()为 false直接放行原调用不产生任何额外开销确定调用方向根据invoker.getUrl()的side参数判断当前是消费端还是提供端并据此决定 CAT Transaction 的类型消费端CatConstants.CROSS_CONSUMER PigeonCall提供端CatConstants.CROSS_SERVER PigeonService两个类型常量定义在 CatConstants.java 中。这里复用了 CAT 原有 RPC 框架Pigeon的消息命名目的是让 cross 报表在服务端天然兼容、直接展示创建 Transaction 并记录 cross 明细loggerName由接口简单名.方法名拼接而成如UserService.getUserById作为 cross 报表中调用名称的维度调用真实业务逻辑执行invoker.invoke(invocation)根据结果决定 Transaction 的成功或失败状态finally 收尾transaction.complete()完成埋点并清理 ThreadLocal 上下文。3.1 消费端 cross 明细PigeonCall消费端侧在发起调用前通过createConsumerCross打点三个 Event用于 cross 报表的调用方视角统计Event 类型常量值含义CONSUMER_CALL_APPPigeonCall.app被调用的提供方应用名CONSUMER_CALL_SERVERPigeonCall.server提供方主机url.getHost()CONSUMER_CALL_PORTPigeonCall.port提供方端口url.getPort()对应源码见 CatTransaction.java。这三个 Event 会被transaction.addChild挂到当前 Transaction 下随消息树一起上报。3.2 提供端 cross 明细PigeonService提供端侧在收到请求后通过createProviderCross打点两个 Event见 CatTransaction.javaEvent 类型常量值含义PROVIDER_CALL_APPPigeonService.app调用方消费端应用名PROVIDER_CALL_SERVERPigeonService.client调用方主机RpcContext.getContext().getRemoteHost()其中消费端应用名的获取依赖 RPC 上下文中透传的application参数见下文 AppNameAppendFilter若拿不到则降级为远程主机:远程端口形式保证 cross 报表仍有数据可看。四、异常分类三类 Error 打点插件对 Dubbo 调用的异常做了分类统计共定义了三个 Event 类型见 CatTransaction.javaEvent 类型常量值触发场景DUBBO_BIZ_ERROR业务异常服务端业务代码抛出的非 RPC/Remoting 异常DUBBO_TIMEOUT_ERROR调用超时RpcException且根因cause为TimeoutExceptionDUBBO_REMOTING_ERROR网络/远程通信异常RpcException但非超时或RemotingException及其子类判定逻辑位于 CatTransaction.java调用返回后若result.hasException()则根据异常类型创建对应 Eventevent.setStatus(result.getException())记录异常对象同时将 Transaction 状态置为异常类的简单类名若无异常则transaction.setStatus(Message.SUCCESS)。另外值得注意的两点实现细节异步调用的特殊处理若RpcUtils.isAsync判定为异步调用插件不会判断返回结果中的异常源码注释明确说明这会阻塞接口因为AsyncRpcResult.hasException会触发 future.get直接标记为成功异常兜底在catch (RuntimeException e)分支中若init已成功会调用Cat.logError(e)记录错误日志并同样打点分类 Event若发生异常时连初始化都未完成则仅透传异常保证监控自身故障不影响调用方。五、链路串联消息树上下文在 RPC 间透传要形成完整的调用链路 trace必须把消费端发起的 Transaction与提供端接收的 Transaction串到同一棵消息树上。插件通过 Dubbo 的RpcContextattachment 机制完成上下文透传核心是 CAT 客户端Cat.Context的三个字段见 Cat.java 中定义的ROOT、CHILD、PARENT常量_catRootMessageId —— 根消息 ID _catChildMessageId —— 子消息 ID _catParentMessageId —— 父消息 ID具体流程见 CatTransaction.java消费端通过Cat.logRemoteCallClient(context)生成新的消息树上下文setAttachment把 ROOT / CHILD / PARENT 三个 ID 写入RpcContext的 attachments随 RPC 请求发送到提供端提供端在initContext时从RpcContext.getContext().getAttachments()中取出这三个 ID 还原Cat.Context再调用Cat.logRemoteCallServer(context)将当前消息树挂接到上一跳从而完成跨进程的链路串联。上下文对象DubboCatContext使用ThreadLocalCat.Context保存静态字段CAT_CONTEXT并在 finally 中CAT_CONTEXT.remove()清理避免线程池复用导致的上下文串扰。六、应用名透传让 cross 报表指名道姓cross 报表的价值在于展示谁调了谁因此调用双方的应用名至关重要。插件通过两个组件共同保证应用名的正确性6.1 消费端AppNameAppendFilterAppNameAppendFilter.java 仅激活在 CONSUMER 侧在发起调用前把当前提供方 URL 中的application参数写入 RpcContext attachment使下游能识别调用方应用Activate(group {CommonConstants.CONSUMER}) public class AppNameAppendFilter implements Filter { Override public Result invoke(Invoker? invoker, Invocation invocation) throws RpcException { RpcContext.getContext().setAttachment( CommonConstants.APPLICATION_KEY, invoker.getUrl().getParameter(CommonConstants.APPLICATION_KEY)); return invoker.invoke(invocation); } }6.2 提供端Registry 包装获取服务端应用名CatRegistryFactoryWrapper.java 通过包装 Dubbo 的RegistryFactory在服务提供方注册 URL 时追加一个自定义参数serverApplicationName常量定义见 CatConstants.java值为提供方自身的applicationprivate URL appendProviderAppName(URL url) { String side url.getParameter(CommonConstants.SIDE_KEY); if (CommonConstants.PROVIDER_SIDE.equals(side)) { url url.addParameter(CatConstants.PROVIDER_APPLICATION_NAME, url.getParameter(CommonConstants.APPLICATION_KEY)); } return url; }RegistryWrapper在register/unregister/lookup等关键操作上统一调用appendProviderAppName做 URL 增强。这样消费端拿到提供方地址后即可通过url.getParameter(CatConstants.PROVIDER_APPLICATION_NAME)直接读出被调服务应用名无需额外配置若该参数缺失getProviderAppName会降级为从接口全限定名中截取包名前缀作为应用名见 CatTransaction.java保证数据不中断。说明CatRegistryFactoryWrapper的使用需要额外配置注册中心工厂的包装扩展通过 Dubbo SPI 的qos-registry-factory或 XML 中显式指定接入时请结合自身 Dubbo 配置方式确认该环节是否生效核心的 Filter 埋点第三、四、五节则无需任何额外配置随依赖自动激活。七、从入门到排查接入路径小结确认 Dubbo 版本线Apache Dubbo 2.7.x 使用 integration/apache-dubbo阿里 Dubbo 2.x 使用 integration/dubbo引入依赖在服务提供方和消费方应用尤其是 RPC 入口应用的 pom.xml 中加入net.dubboclub:cat-monitor:0.0.6确认 CAT 客户端配置插件依赖com.dianping.cat:cat-clientpom.xml 中声明 2.0.0需保证各应用已正确接入 CAT 客户端域名、服务端地址等否则Cat.getManager().isCatEnabled()为 false监控不会生效观察报表部署后即可在 CAT 服务端查看 cross、dependency、matrix 与 trace 数据验证耗时与异常统计是否符合预期动态控制特殊场景下可通过DubboCat.disable()/DubboCat.enable()在不重启应用的情况下启停监控。通过上述步骤Dubbo 服务的调用耗时、超时、业务异常、网络异常即可自动沉淀为可检索、可告警的监控数据为微服务架构下的故障定位与服务治理提供第一手依据。【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址: https://gitcode.com/gh_mirrors/ca/cat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考