Skywalking 6.6.0对arthas的兼容性问题

背景

目前在参与公司全链路压测项目,在部署到日常环境服务进行测试时,用 arthas 进行追踪排查问题发现无法追踪被 agent 增强的类。于是尝试解决这个问题。

报错如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//arthas trace 时命令行报错
[arthas@24580]$ trace com.mysql.jdbc.PreparedStatement execute
Affect(class count: 1 , method count: 5) cost in 480 ms, listenerId: 8
Enhance error! exception: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change superclass or interfaces
error happens when enhancing class: class redefinition failed: attempted to change superclass or interfaces, check arthas log: /home/www/logs/arthas/arthas.log


//arthas 日志报错
2020-09-10 17:05:24 [arthas-command-execute] INFO c.t.arthas.core.advisor.Enhancer -enhance matched classes: [class com.mysql.jdbc.PreparedStatement, class com.mysql.jdbc.JDBC4PreparedStatement, class com.mysql.jdbc.CallableStatement, class com.mysql.jdbc.ServerPreparedStatement]
2020-09-10 17:05:24 [arthas-command-execute] ERROR c.t.arthas.core.advisor.Enhancer -Enhancer error, matchingClasses: [class com.mysql.jdbc.PreparedStatement, class com.mysql.jdbc.JDBC4PreparedStatement, class com.mysql.jdbc.CallableStatement, class com.mysql.jdbc.ServerPreparedStatement]
java.lang.UnsupportedOperationException: class redefinition failed: attempted to change superclass or interfaces
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
at com.taobao.arthas.core.advisor.Enhancer.enhance(Enhancer.java:368)
at com.taobao.arthas.core.command.monitor200.EnhancerCommand.enhance(EnhancerCommand.java:149)
at com.taobao.arthas.core.command.monitor200.EnhancerCommand.process(EnhancerCommand.java:96)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

解决思路

首先 skywalking 和 arthas 都是目前比较受欢迎的开源项目,我们应该不是第一个碰到这个问题的人。Github 一搜,果然不少人都碰到了这个问题(部分资料见参考资料)。

其中 arthas 维护团队的一位成员已经对 skywalking 提出了 pr,并已经合并到 matser,但是我们是 6.6.0,master 已经是 8.x。只能参考下进行改造。

基本的改造点为:

  1. 开源代码中的方案包括了 文件 和 内存缓存两种方式,我们不需要文件这种比较重量级的方式,于是去掉了,而且将内存的方式改为了LRU。
  2. 6.6.0 加载自定义 CacheableTransformerDecorator 的方式和 8.x 不太一样,主要是 bytebuddy 版本差异造成的。6.6.0 加载的地方为 agentBuilder.installOn(x,x) 。

这样改造后基本就能兼容 arthas 了。

参考资料