CnOps 社区
首页开源项目实践文章视频课程常见问答开发者工具
导航菜单
首页开源项目实践文章视频课程常见问答开发者工具

CnOps 社区

愿景

CnOps 社区是一个以"智能运维与可观测"为核心的开放、包容、分享的技术社区,旨在聚集运维专家、开发者和爱好者,共同探讨、学习和分享可观测最佳实践与最新技术,与众多技术社区合作互动,共同探讨交叉领域的技术挑战,推动可观测领域的创新与进步。

内容社区

  • 实践文章
  • 视频课程
  • 开源项目
  • 常见问答
  • 开发者工具

友情链接

  • Prometheus
  • Grafana Lab
  • OpenTelemetry
  • LoongCollector

关注我们

阿里云云原生公众号阿里云云原生
阿里云可观测公众号阿里云可观测

Copyright © 2026 CnOps 社区. All rights reserved.

首页实践文章拥抱 OpenTelemetry,阿里云 Java Agent 演进实践

拥抱 OpenTelemetry,阿里云 Java Agent 演进实践

#可观测性#微服务#云原生#监控#日志#指标

agenticOps | 2026-05-23

背景

在 2018 年的 2 月,ARMS Java Agent的第一个版本正式发布,为用户提供无侵入的的可观测数据采集服务。6 年后的今天,随着软件技术的迅猛发展、业务场景的逐渐丰富、用户规模的快速增长,我们逐渐发现过去的功能以及架构的设计逐渐难以合理、优雅的满足今天的需求,重构越来越多的被提及,但总是缺少一个合理的契机。

适时,OTel项目异军突起,其社区经过短短四年的发展,活跃度位列CNCF第二,逐渐成为可观测领域的开源标准。OTel(OpenTelemetry)是一个位于云原生计算基金会(CNCF)的开放源代码项目,旨在标准化遥测数据的收集、处理和导出的方式。其贡献者由来自不同公司和组织的成员组成,他们共同协作创建和维护用于分布式追踪、指标和日志的 API、SDK 和工具。他们的目标是使可观测性更加易于访问并整合到云原生软件开发中,从而使用户能够更有效地监控、调试和优化他们的应用程序。

同时,我们调研了国外APM领域的一些头部商业化公司,比如 New Relic、Grafana、Elasticsearch 以及部分云厂商比如 Azure、AWS 都已经开始基于 OTel Java Agent 打造自己的商业化探针。

这些现象也极大的引起了我们的兴趣, 促使我们对OTel Java Agent进行了一次深入的调研。

关于OTel Java Agent

首先我们对比了OTel Java Agent和ARMS 现有探针在Tracing、Metrics、Logs、Profiling以及其他五个方面的功能差异,如下表所示。可以看到,简单的从功能层面来说,OTel Java Agent依托社区广大的贡献者,在插件数量上远远领先。此外,基于一些领先的埋点技术,对于各种异步场景支持较好;ARMS 探针则依托广大的商业化用户场景和多年服务集团内外客户的经验,在采样,多协议支持、指标丰富度以及各种三方功能集成方面比较领先。

功能大类功能子类ARMS (3.1.4)OTel Java Agent(1.28.0)
Tracing插件支持≈60≈128
采样能力头采样、尾采样头采样 
TraceId 透传协议支持 eagleeye, w3c, zipkin, skywalking,Jaeger,自适应切换,自定义配置w3c、zipkin、Jaeger 
异步透传手动配置自动 
兼容 OTel SDK部分支持全支持 
动态新增 span支持不支持 
MetricsRED 指标支持支持
线程相关指标支持不支持 
连接池指标支持支持 
异常指标支持不支持 
系统/JVM指标支持支持 
JMX 指标不支持支持 
动态新增指标不支持不支持 
logsMDC支持支持
自动采集不支持支持 
profiling支持 Profiling 事件类型数量

5 类

CPU耗时

内存样本数

内存分配大小

应用级墙钟

代码热点

不支持
关联 traceId支持不支持 
eventevent 类型数量简单不支持
other应用安全支持不支持
Arthas支持不支持 
微服务治理支持不支持 
内存 dump支持不支持 

除了上面列举的功能对比,在对OTel Java Agent调研中,我们也发现他有很多领先的设计在解决埋点生效判断、异步、类隔离等问题时十分方便。这里简单介绍一下他的几个比较领先的设计。

muzzle-check机制

编译时收集我们埋点代码中访问了被增强类的哪些方法、字段。在运行时,如果待增强类没有相应的方法和字段,则不执行增强动作,避免增强代码报错;在平时,可以对待增强类的所有版本执行静态检测,获得支持版本列表。

VirtualField机制

JVM的字节码增强机制有一些限制,对于已加载类的增强,只能修改方法体,不能给类新增字段。这个限制对于我们影响较大,因为在APM的场景下,往往有较多的场景需要给类增加字段来作一些变量传递。opentelemetry-java-instrumentation提供了VirtualField机制,如下图所示,通过统一的编程接口,可以给类T添加一个类型为F的字段。

  • 当类T当前尚未加载时,此时的实现就是给类T增加了类型为F的字段。当访问类T的F字段时和访问普通的类字段一致
  • 当类T已经加载时,此时的实现是有一个全局的ConCurrentWeakhashMap,map的key类型为T,value类型为F。当访问类T的F字段时实际在底层为map的get操作

public static <U extends T, V extends F, T, F> 
VirtualField<U, V> find(Class<T> type, Class<F>fieldType) {
return RuntimeVirtualFieldSupplier.get().find(type, fieldType);
}

异步上下文透传

除了原生的JDK线程池,对市面上常见的异步框架akka、netty event loop等均做了异步埋点。异步埋点思路整体上包含两个步骤

  1. 实现了Runnable接口的实现类,利用上述的VirtualField机制,给实现类增加一个记录Trace上下文的字段,同时埋点其run方法,run方法执行时获取增加字段中的trace上下文,并设置到当前线程的ThreadLocal中
  2. 埋点Exectuor的execute方法,在execute方法执行时从ThreadLocal获取当前Trace上下文,并设置给对应的Runnable实现类

新埋点思路

最大程度利用框架的拓展能力进行埋点,比如利用Dubbo的Filter机制、grpc的Intercepter机制、实现lettuce的tracing接口等等。而不是一味的对框架的方法进行增强

除了上面提到的这些,opentelemetry-java-instrumentation还有很多亮点设计,比如类加载器隔离,opentelemetry-java-sdk兼容,多JDK版本兼容等等,这里不再一一赘述,后续会推出系列文章专门介绍OTel Java Agent的一些亮点设计和技巧。

调研结论

当完成OTel Java Agent各方面的调研之后,我们会发现他的很多设计都是领先于当初选择的Pinpoint探针的,一章节提到的那些代码设计和技巧、埋点方式等帮助我们打开了新的思路,可以解决很多困扰许久的问题。OTel Java Agent 的蓬勃发展成为了一个促使我们进行一次大规模重构最合理的契机,再考虑到拥抱开源、拥抱标准的基本原则,于是我们在2023年的夏天做了一个重大的决定,在 ARMS Java Agent 的下一个大版本 4.x 版本中,基于OTel Java Agent做一次升级重构,将现有ARMS 3.X版本探针的商业化能力迁移过来,并做到能100%兼容3.x探针的功能。

围绕OTel Java Agent做了哪些增强

在接下来将近一年的时间里,围绕openTelemetry-java-instrumentation,首先,我们对其现有的功能进行了升级重构。包括新插件支持,基础的tracing能力增强,指标类型增加、指标维度增加等等;其次,迁移了很多过往几年沉淀的商业化能力。包括Arthas诊断,应用安全、内存Dump,微服务治理(全链路灰度、无损上下线,限流降级等等);最后,围绕探针构建了完善的稳定性保障措施。升级后的探针整体架构图如下图所示



 

下面分别展开说明

新插件支持

OTel探针对国内一些被广泛使用的框架、中间件支持较少,比如druid、xxl-job、hsf、influxdb、mybatis、xxlJob、motan、shenyu等,我们此次增加了对这些框架的支持,并且部分已经贡献给开源。

Tracing增强

Tracing能力是APM探针的核心能力,OTel探针原生的Tracing能力在企业内部复杂场景下往往会遇到不少挑战,包括多协议场景下断链、极端场景下span数量爆炸、采样难以命中高价值数据等等。针对这些问题,我们对OTel探针做了以下增强来解决:

多协议支持

原理:默认情况下会自动按照 EagleEye、W3C、Skywalking、Zipkin、Jaeger 、Skywalking的顺序识别并恢复上游透传的 Trace 上下文。同样也支持按照用户需求配置优先或者强制使用某种协议

优点:在客户多语言、内部不同部门使用多套tracing系统、外部流量携带trace上下文、上云迁移等场景下能尽量保证不断链

调用链压缩

原理:ARMS 探针会将一些同一层级的重复span压缩成一个,比如业务代码在一个 for 循环中,调用 数据库 应用 10000 次,那么在调用链中会生成 10000 个 span,而经过调用链压缩后,仅会记录一个span,并在这个span中记录重复span的次数、最大耗时、最小耗时、总耗时等信息,效果如下图所示。

同时,为了避免尽可能保留重要信息。会将耗时top3和最开始报错的三个span转换为spanEvent保留在压缩后span的spanEvent中。

优点:一方面可以避免极端场景下产生大量数据,客户overhead过高;另一方面避免span过多场景下,后端查询缓慢、前端渲染卡顿、展示臃肿、客户排查问题难以抓住重点等问题

缺点:因为仅保留了部分样本,无法看到全部的信息,可能导致丢失用户真正关注的数据

采样

相比于其他产品单一的采样策略,ARMS 探针提供相对较为丰富的采样策略,且大多不需要用户进行复杂配置,每个采样策略保证特定场景下高价值Tracing数据被采样,低价值Tracing数据少采样,分别如下所示:

固定比例采样

即现有的默认采样,按照百分比采样链路

自适应采样

自适应采样会按照 LFU 的策略选取当前调用量 top-1000 的接口,每个接口的采样彼此隔离,可设置两种采样策略,两种策略两种采样分别如下所示。

  • 每秒固定条数(默认):一秒采样10条
  • 自适应比例:默认10%,会根据该接口上一分钟请求量动态调整,避免大流量接口采样太多无效数据

另外对于调用量 top-1000 以外的接口,可以认为是一个 other 接口。处理逻辑和前面介绍的 top-1000 中任1接口一致

小流量采样

无需用户配置,自动保证每一个接口每一分钟至少有一个span。原理是用一个布隆过滤器存储一分钟内已经被采样过的接口。并每一分钟定期重置该布隆过滤器。这样可以保证无论用户接口有多发散,内存开销都是确定的。

错慢异常采样

无需用户配置,当一次调用满足下面三个条件时,则上报该次调用相关span。

接口报错:http 类接口响应码非 2xx、3xx或者本次调用的 localRootSpan 埋点方法处抛出异常

接口内部有异常:一次调用的非 LocalRootSpan 的 span 记录到异常信息

接口调用耗时长的定义:接口耗时大于过去一段时间该接口的 p99耗时

该采样对于问题排查十分重要,但是因为时机问题,无法保证链路完整。比如接口A调用接口B,A命中错慢采样,并不能保证B接口的Span一定上报

自定义采样

即用户自己配置 100% 采样接口、接口前缀、接口后缀等等。满足用户配置要求的调用会一定采样

总结

上述各个采样策略会在一次调用中都生效,一个Span是否上报由上述采样策略综合决定,详细流程如下图所示

其中不同颜色的采样策略区别在于

紫色:标准的头采样,只会在链路的RootSpan处触发,采样后可以保证后续链路完整

蓝色:只要当前的采样结果是不采样,可以在链路的任何一个LocalRootSpan处触发,采样后可以保证后续链路完整

绿色:只要当前的采样结果不采样,可以在链路的任何节点触发,采样后无法保证后续链路完整

以一个常见的链路A->B->C为例说明,在不同节点命中不同采样规则时,对应会链路哪些span会上报,哪些span不上报

Metrics增强

更丰富的指标

  • 线程池监控指标:针对常见JDK线程池,Jetty、Undertow线程池监控,支持核心线程、最大线程、活跃线程、当前线程、历史最大线程、调度任务、完成任务、拒绝任务以及队列大小9类指标。便于排查线程池打满类问题
  • 线程监控指标:将当前JVM种所有线程归类后,统计不同类别线程的耗时以及处于不同状态线程的数量,并定时抓取线程栈,便于排查线程阻塞、线程耗时高等问题
  • MQ消费延迟指标:针对MQ类组件,出了常见的RED指标,增加消费延迟指标,便于排查消费延迟类问题
  • 数据库响应大小:针对DB类操作,增加请求、响应大小指标,便于排查大查询类问题
  • 新增异常类指标:指标主要为异常次数,维度记录了当前接口,便于排错异常类问题

更多样的维度

  • 接口类RED指标记录上游接口:方便查看接口到接口的调用拓扑、调用关系,方便接口异常时快速定位上下游
  • 数据库类调用指标。额外记录当前接口、数据库语句维度,方便接口出问题时,快速定位是否db的问题。db出问题时,快速查询影响的接口,具体出问题的sql语句

Profiling能力支持

和阿里云 Dragonwell 团队合作,底层基于async-profiler,提供 CP(Continuous Profiling)的能力。阿里云 Java Agent 提供的 CP 支持多种剖析类型,比如 CPU 热点剖析、堆内存热点剖析,墙钟热点剖析等。

特色能力介绍

除了常见的 CPU 热点剖析、内存热点剖析,ARMS 还针对慢调用链诊断场景,提供了代码热点产品能力,其是在开源 Async Profiler 墙钟能力的基础上,通过关联调用链中的 TraceId & SpanId 信息提供了调用链级别的 On & Off-CPU 火焰图,可有效对 Tracing 的监控盲区细节进行还原,帮助用户诊断各类常见的慢调用链问题,详情可参见文档

那么,ARMS持续剖析和客户自己用开源的 Async Profiler 生成火焰图相比有什么优势呢?

首先,支持常态化开启,开源的 Async Profiler 未提供支持常态化开启的数据存储与处理能力,难以在生产环境常态化开启,对于一些线上偶现的问题,难以使用其进行问题排查。

其次,运行环境覆盖面更广,开源的 Async Profiler 一些剖析类型对应用运行环境有一定要求,比如 Alpine Linux 基础镜像为了控制体积而去除了 JDK 调试符号(debug symbols)导致无法使用内存热点剖析功能,但是 ARMS 在其基础上通过针对特定版本的 Alpine Linux 基础镜像对应的 JDK 调试符内容做了预适配,对相关类型的环境,在不安装调试符的情况下,也可以使用内存热点。

最后,更好的稳定性。开源的 Async Profiler 常态化开启过程中可能会容易出现 Crash 问题比如#694或者多个剖析引擎(CPU热点、内存热点等)同时启动,一个外部条件不满足引发的单引擎失败会导致整体失败,ARMS在开源 Async Profiler 基础上做了一些 bugfix 和剖析引擎隔离优化,稳定性更好。

性能优化

在分析OTel Java Agent的过程中,我们发现它在创建span、记录指标等地方,对于Attributes有大量的重复copy以及排序操作,这些部分是占用整个探针CPU开销的大头,我们对这些操作进行了大量的优化,结果表明在TPS4000流量的测试场景下,aliyun-java-agent探针相较开源版本OTel Java探针CPU性能表现更好,整体容器CPU开销水位大约降低2%;内存性能表现上,在进行2h压测后容器申请的RSS内存,aliyun-java-agent探针相较开源版本OTel探针的内存占用降低约10MB

问题诊断场景的增强

  • 集成代码级问题诊断利器Arthas。无需依赖JDK,一键开启、关闭。常见命令白屏化操作。且支持企业级鉴权、审计能力。避免任意用户随意执行Arthas命令。详情见 链接
  • 内存 Dump。一键对指定机器执行内存dump,并配套白屏化分析能力。

云产品集成

  • 微服务治理。在同一个 Java Agent 中集成了阿里云 MSE 微服务治理能力,包括全链路灰度、限流降级、无损上下线,系统防护、消息灰度等;
  • 集成云安全中心应用安全 RASP。一键开启后拥有危险组件检测、25+种攻击行为的监控,阻断的能力

探针稳定性建设

由于Java探针和用户代码运行在一个进程中,且会对用户代码进行增强修改,Java探针的稳定性建设尤为重要,多年的公有云用户服务经验告诉我们,对于一款可观测产品而言,我们的底线是不能影响业务行为,比如导致用户进程启动失败,用户进程crash,用户接口报错,占用大量用户机器资源等等。为了最大程度的避免这类问题,并在出现这类问题时能够及时止血, 我们在OT的基础上增加了下述能力

  • 探针CPU/内存占用上限控制能力:在探针CPU开销,内存占用超过指定阈值时,自动降级探针的Tracing或者Metrics数据采集能力
  • 探针启动预检能力;因为探针本身有运行的环境要求,为了避免在非预期环境中出现异常行为,探针启动有若干检测项,比如JVM类型、JVM版本、最大堆内存等等,最大程度的避免影响用户业务
  • 探针功能可动态插拔能力:大部分探针功能,特别是可能影响用户业务的能力,都具备动态控制开关,可以在出现问题时快速关闭

阿里云 Java Aent 4.0 探针带来了哪些好处

从功能层面上来说,这次升级,完全吸纳了OTel的优秀设计,对我们现有的很多功能做了升级或者增强

  • 遵循JDBC规范的数据库埋点从JDBC接口层面埋点,理论上支持所有遵循JDBC规范的数据库埋点(3.x探针仅支持固定的9种)
  • 异步埋点无需用户配置,不会断链
  • vertx、webflux、lettuce、Rabbitmq、kafka、RocketMq、ONS等插件相比老版本,因为埋点的位置优化,指标统计更准确,支持版本范围更广
  • 支持容器场景的系统指标采集
  • 线程池监控支持用户自定义线程池的监控

从工程质量上来看来说,这次升级重构是对3.x代码的一次取其精华、去其糟粕的过程、是重新树立更合理科学的开发规范的过程,通过这次升级重构

  • 4.0 探针的内存占用下降了20%、线程数降低了60%,探针包大小降低了30%。

最后,从长远发展来看,我们制定了每三个月合并一次开源最新稳定代码的计划,可以快速的享受到社区快速迭代的红利。

我们为社区做了什么

在基于OTel Java Agent二次开发的过程中,我们也积极的反哺开源,在过去6个月中,我们累计向社区贡献并合并各类PR 40+,其中包含新增在国内广泛使用的XXL-JOB、InfluxDB、MyBatis等插件,参与社区日常PR Review 100+,steverao和123liuziming两位同事成为社区member,其中steverao受邀作为该项目的Triager并且负责该社区的日常维护、代码CR,且个人贡献长期位列社区前四名,贡献度积分位列社区Top 20,亚太地区第一。

此外,我们也积极参与社区相关各类会议活动,今年6月,受社区邀请,在北美举行的2024 OpenTelemetry Community Day活动中,我们同事望陶和铖朴,为社区带来了《GraalVM 静态编译下 OTel Java Agent 的自动增强方案与实现》主题分享,对相关问题的原创性解决方案得到了社区开发者的广泛关注。今年8月,在中国香港举行的KubeCon China 2024大会上,望陶和铖朴与社区其他开发者一起,在社区Governance Committee团队的支持下,代表社区在大会上做了《社区最新进展以及阿里云拥抱OTel社区实践》相关分享。此外,为了促进亚太地区与社区的交流,在团队相关同学向社区提议,在与社区Governance Committee Member成员沟通后,OTel社区也在多个领域,设立了亚太地区友好的周会交流时间。其中包含Java: SDK + Instrumentation、Semantic Conventions: LLM、Contributor Experience和Developer Experience,相关时间可以参考社区周会安排,相关会议中有社区最资深的开发者一起参与,欢迎有兴趣的朋友加入。

目前,我们也正在将由阿里云开源的 Go Instrumentation 贡献到OTel社区,相关内容正在与社区相关Governance Committee和Technical Committee团队讨论中#1961。

写在最后

我们用了接近一年的时间完成了基于 OTel Java Agent 的升级重构,并于今年5月份发布了4.x探针的第一个版本4.1.0,经过接近半年时间的验证、回归、优化,目前最新的稳定版本4.1.12已经正式发布,欢迎大家了解使用。

接下来的时间,一方面我们将持续的 Follow OTel Java Agent 的发版节奏,定期合并开源稳定代码,保障用户可以持续的享受社区最新的feature;另一方面,我们也将重点打造阿里云 Java Agent相比OTel Java Agent的差异化能力,补齐其不足与短板,帮助用户获得更全面、更透彻的应用可观测体验。

文章大纲