ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CAT .NET 客户端接入指南:AsyncLocal 异步埋点、并行调用与配置化

CAT .NET 客户端接入指南:AsyncLocal 异步埋点、并行调用与配置化 可观测性指标监控告警APM后端链路追踪【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址https://gitcode.com/gh_mirrors/ca/cat点击查看免费下载CATCentral Application Tracking作为服务端项目基础组件提供 Java、C/C、Node.js、Python、Go、.NET 等多语言客户端已在美团点评基础架构中间件框架中深度集成。本仓库的 lib/csharp 目录下是一套改进自 ctripcorp/cat.net 的 C# 客户端实现核心改进点是使用 AsyncLocal 取代 ThreadLocal 以完整支持 async/await 异步调用、提供显式的 NewForkedTransaction 支持异步并行调用、支持从 App.config 的 CatConfiguration section 读取服务端配置、提供数据库访问 Wrap 类 DBUtil并原生支持 .NET Core。读完本文你将掌握 CAT .NET 客户端的工程结构、配置方式、异步埋点与并行调用 API以及 SQL 场景的埋点封装。一、客户端定位与工程结构本客户端改进自 ctripcorp/cat.net位于仓库 lib/csharp 目录。它承担两类职责一是把业务代码中的 Transaction / Event / Heartbeat / Metric 消息组装成消息树二是通过 TCP 把消息树发送到 CAT 服务端默认 2280 端口供服务端聚合出性能指标、健康状况与实时告警报表。1.1 解决方案构成用 Visual Studio 2017 或更高版本打开Cat.sln可以看到解决方案包含四个工程工程说明目标框架CatCAT .NET 客户端实现代码.NET Framework 4.6.1CatCore.NET Standard 版本实现.NET Standard 2.0CatClientTest示例程序和测试用例.NET FrameworkCatCoreClientTest.NET Standard 版本示例程序.NET Standard1.2 关键源码文件客户端实现集中在 lib/csharp/src/CatClientCat.cs门面类提供NewTransaction、NewForkedTransaction、LogEvent、LogMetricForCount等全部静态埋点 APICatConstants.cs常量定义如SUCCESS 0、EVENT_SQL、EVENT_SQL_ROWS等CatConfigurationSection.cs基于 .NETConfigurationSection的配置模型LocalClientConfig.cs本地配置加载实现DBUtil.cs数据库访问 Wrap 类DefaultMessageManager.cs消息上下文管理核心DefaultForkedTransaction.cs并行调用 Transaction 实现。1.3 运行时要求.NET Framework 4.6.1 或 .NET Standard 2.0如需支持 .NET Framework 4.5可自行 clone 后用 CallContext 替换 AsyncLocalAsyncLocal 在 4.5 上不可用CatCore 依赖 Microsoft.Extensions.Configuration因此 .NET Core 场景下可用 JSON 配置见下文 3.3。二、核心改进一用 AsyncLocal 支撑 async/await原版 cat.net 使用 ThreadLocal 保存线程上下文而 async/await 期间方法会在不同线程间切换执行ThreadLocal 无法跨 await 延续上下文导致异步代码中的埋点丢失或错乱。本客户端改用 AsyncLocal见 CatThreadLocal.cs上下文会随异步执行流自动传播从而完整支持 async/await。在 DefaultMessageManager.cs 中上下文容器为CatThreadLocalContextSetup()创建新 Context 并写入 AsyncLocalStart/End分别压栈/弹栈管理 Transaction 栈消息树在根 Transaction Complete 后由Flush发送。三、核心改进二配置化摆脱本地 client.xml 依赖3.1 在 App.config 中添加 CatConfiguration section在 .NET Framework 工程Cat中请把以下配置片段放入App.configconfigSections section nameCatConfiguration typeOrg.Unidal.Cat.Configuration.CatConfigurationSection,Cat/ /configSections CatConfiguration domain idcat_test enabledtrue max_message_size1024 client_load_balancetrue/ logEnabled enabledtrue/ servers server ip172.22.60.139 port2280 http-port8080/ !--可配置多个server地址-- !--server ip127.0.0.1 port2280 http-port8080/-- /servers /CatConfiguration配置模型在 CatConfigurationSection.cs 中定义各属性含义如下节点/属性类型默认值说明domain/idstringUnknown应用标识DomainCAT 服务端据此区分业务线domain/enabledboolfalse是否启用 CAT 客户端domain/max_message_sizeint1024单棵消息树允许的最大消息数超过会触发截断见 DefaultMessageManager.cs 的AddTransactionChilddomain/client_load_balanceboolfalse是否启用客户端随机负载均衡见 AbstractClientConfig.cslogEnabled/enabledboolfalse是否开启客户端本地日志server/ipstring必填CAT 服务端 IPserver/portint2280CAT 服务端 TCP 端口server/http-portint8080CAT 服务端 HTTP 端口用于拉取路由配置server/enabledbooltrue该 server 是否参与发送3.2 配置加载逻辑加载逻辑在 LocalClientConfig.cs 的Init方法中优先读取AppSettings[LocalClientConfig]指向的本地 XML即传统d:\data\appdatas\cat\client.xml方式若未配置或文件不存在则回退读取CatConfigurationsection仅添加enabledtrue的 server根据 domain 的id与enabled决定Cat.Enabled。配置被读取后AbstractClientConfig会向 CAT 路由服务发送http://{server}:{http-port}/cat/s/router?domain{Domain}请求2 秒超时获取该 domain 对应的服务端列表若开启client_load_balance会对列表随机打乱AbstractClientConfig.cs。3.3 .NET Core 场景CatConfigurationSection.Load appsettings.jsonCatCore.NET Standard 版本示例 CatStandardClientTest/Program.cs 展示了 .NET Core 的配置方式IConfiguration config new ConfigurationBuilder() .AddJsonFile(appsettings.json, optional: false, reloadOnChange: true) .Build(); CatConfigurationSection.Load(config);即在appsettings.json中提供CatConfiguration节点然后通过CatConfigurationSection.Load(config)显式加载。四、客户端埋点基础用法4.1 Transaction 埋点private static async Task InvokePayment(int i) { ITransaction paymentTransaction null; try { paymentTransaction Cat.NewTransaction(NewPayment i, PaymentDetail); // Do Business Staff paymentTransaction.Status CatConstants.SUCCESS; } catch (Exception ex) { paymentTransaction.SetStatus(ex); throw; } finally { paymentTransaction.Complete(); } }要点Cat.NewTransaction(type, name)创建 Transaction 并自动开始计时成功时设置Status CatConstants.SUCCESS即 0异常时SetStatus(ex)会把异常类型与堆栈写入状态标记失败并继续抛出必须通过Complete()结束否则会在服务端生成 BadInstrument 告警事件见 DefaultMessageManager.cs 的Validate/markAsNotCompleted。4.2 其他常用 APICat.csAPI用途Cat.LogEvent(type, name, status, data)记录事件可附带 keyvalue 形式数据Cat.LogError(Exception)记录异常事件Cat.LogHeartbeat(type, name, status, kv)记录心跳消息Cat.LogMetricForCount(name[, quantity])计数器指标类型 CCat.LogMetricForDuration(name, ms)耗时指标类型 TCat.LogMetricForSum(name, value)求和指标类型 SCat.NewTaggedTransaction(type, name, tag)创建 TaggedTransaction配合Cat.Bind(tag, title)跨线程关联Cat.CreateMessageId()/Cat.GetThreadLocalMessageTree()获取消息 ID 与当前消息树心跳报表在服务端展示效果见下五、核心改进三异步并行调用 NewForkedTransaction并行调用如Task.WhenAll并发发起多个远程调用场景下每个子任务都在独立执行流中运行。为此客户端提供Cat.NewForkedTransaction(remote, Service Name)显式开启新的调用上下文。5.1 完整示例// 并行调用 var tasks Enumerable.Range(1, 5).Select(async (i) { await InvokePaymentWrap(i).ConfigureAwait(false); }); await Task.WhenAll(tasks); // InvokePaymentWrap方法需要调用NewForkedTransaction private static async Task InvokePaymentWrap(int i) { var forkedTran Cat.NewForkedTransaction(remote, InvokePaymentWrap); asyncLocal.Value new Context() { Value i }; try { await InvokePayment(i).ConfigureAwait(false); forkedTran.Status CatConstants.SUCCESS; } catch (Exception ex) { forkedTran?.SetStatus(ex); } finally { forkedTran?.Complete(); } }5.2 底层原理DefaultForkedTransaction.cs 的实现要点创建时在父线程中捕获RootMessageId与ParentMessageId并生成独立的ForkedMessageIdFork()在子线程执行流中manager.Setup()建立新 Context并把新消息树的MessageId覆盖为ForkedMessageId、ParentMessageId指向父消息树从而与服务端日志视图中的父子关系衔接父子线程之间不做强引用、不加锁——若子线程 Transaction 未及时 Complete父线程通过linkAsRunAway()以软引用方式把 ForkedTransaction 标记为 RunAway 事件保证两端可独立完成、互不阻塞见 DefaultMessageManager.cs 的LinkAsRunAway。CAT 服务端会把各并行分支按ParentMessageId组织成树状日志视图效果图见文章开头。六、核心改进四数据库访问 Wrap 类 DBUtilDBUtil.cs 提供 4 个重载在业务代码前后自动开启与结束 Transaction方法签名适用场景WrapWithCatTransaction(Action, queryCatetroy, operationType)同步、无返回值WrapWithCatTransactionTResult(FuncTResult, queryCatetroy, operationType)同步、有返回值WrapWithCatTransactionAsync(FuncTask, queryCatetroy, operationType)异步、无返回值WrapWithCatTransactionAsyncTResult(FuncTaskTResult, queryCatetroy, operationType)异步、有返回值6.1 示例EF Core 更新操作public virtual async Task UpdateAsync(TEntity entity) { await Org.Unidal.Cat.DBUtil.WrapWithCatTransactionAsync(async () { ValidUpdateEntity(entity); await DoUpdateAsync(entity); await SaveChangesAsync(); OnUpdateEntity(entity); }, typeof(TEntity).Name, UPDATEASYNC); }6.2 行为细节通过AsyncLocalITransaction保存当前 SQL Transaction嵌套调用时复用外层 TransactionownTransfalse避免重复开启自动记录SQL.Method事件附带Caller{文件}Member{方法}Line{行号}调用点信息利用CallerFilePath/CallerMemberName/CallerLineNumber若返回值实现ICollection还会记录SQL.Rows事件按行数分档10 / 100 / 1000 / 5000 / 10000 / 10000异常时SetStatus(ex)标记失败并重新抛出成功或失败都会在 finally 中正确Complete()关闭 CATCat.Enabled false时直接透传业务委托零额外开销。七、测试用例与验证仓库 lib/csharp/test/CatClientTest 提供了可运行的示例与测试TaggedTransactionTest.cs演示NewTaggedTransaction 子线程Cat.Bind(tag, title)的跨线程关联是理解 TaggedTransaction 语义的最小示例PerformanceTest 下的ForkedTransactionPerformanceTest.cs、MultithreadTest.cs、BatchSendTest.cs等用于验证并行与高吞吐场景EstimateByteSizeTest.cs、TruncateTransactionTest.cs 验证消息大小估算与超长消息树截断逻辑。八、接入步骤小结用 Visual Studio 2017 打开 Cat.sln选择 CatFramework或 CatCoreStandard工程引用到业务项目在App.config配置CatConfigurationsectionFramework或在appsettings.json配置后调用CatConfigurationSection.Load(config).NET Core在业务方法中用Cat.NewTransaction包裹核心逻辑并用CatConstants.SUCCESS标记成功、SetStatus(ex)标记异常并行调用场景使用Cat.NewForkedTransaction为每个子任务开启独立上下文数据库访问使用DBUtil.WrapWithCatTransaction(Async)自动埋点部署 CAT 服务端后访问服务端报表页面查看 Transaction、Event、Heartbeat、Metric 与并行调用日志视图。CAT 服务端部署、报表字段说明等更多信息可参考仓库根目录 README.md 与 docker、helm 目录下的部署配置。赞分享可观测性指标监控告警APM后端链路追踪【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址https://gitcode.com/gh_mirrors/ca/cat点击查看免费下载相关推荐Erlang 应用接入 CAT 监控erlcat 客户端安装、配置与埋点 API 实战指南Erlang 应用接入 CAT 监控erlcat 客户端安装、配置与埋点 API 实战指南 本文以 CAT 开源仓库中的 lib/erlang/README.可观测性指标监控告警APM后端链路追踪CAT Java 客户端接入实战指南从安装配置到 Transaction/Event/Metric 埋点CAT Java 客户端接入实战指南从安装配置到 Transaction/Event/Metric 埋点 CATCentral Application Tr可观测性指标监控告警APM后端链路追踪CAT Python 客户端pycat / cat-sdk接入指南安装、初始化与 Transaction / Event / Metric 埋点实战CAT Python 客户端pycat / cat sdk接入指南安装、初始化与 Transaction / Event / Metric 埋点实战 py可观测性指标监控告警APM后端链路追踪创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进