听说你没法在 JRE 中使用 arthas?不,你可以

news2024/11/13 8:41:17

作者:卜比

本文是《容器中的 Java》系列文章之 5/n ,欢迎关注后续连载 😃 。

  • JVM如何获取当前容器的资源限制?——容器中的Java 1
  • Java Agent踩坑之appendToSystemClassLoaderSearch问题——容器中的Java 2
  • 让 Java Agent 在 Dragonwell 上更好用——容器中的Java 3
  • 为什么在容器中1号进程挂不上arthas?——容器中的Java 4

之前经常遇到的问题是,排查问题需要挂arthas,但客户用的是JRE,没法挂载arthas。就只能让客户更换成JDK,再重新部署、排查问题。

很多有用的现场,在这个过程中也会丢失,最终导致问题排查效率降低。于是就探索了下如何在JRE环境中,使用artahs。

复现问题

如果一个Bug 没法复现,研发大概率是无法修复的。—— by 网友

我们写一个Java例子和Dockerfile:

// ./src/main/java/Main.java
public class Main {
  public static void main(String[] args) throws Exception {
    while (true) {
      System.out.println("hello!");
      Thread.sleep(30 * 1000);
    }
  }
}
# ./Dockerfile
FROM openjdk:8-jdk-alpine as builder
COPY ./ /app
WORKDIR /app/src/main/java/
# 编译java文件
RUN javac Main.java

# 运行时容器使用JRE
FROM openjdk:8-jre-alpine
RUN apk add bash curl busybox-extras
WORKDIR /app/src/main/java/
# 将arthas copy 到容器中
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
COPY --from=builder /app/src/main/java/ /app/src/main/java/
CMD ["java", "Main"]

构建并正常启动应用,并尝试用arthas attach,此处为了便于了解原理,我们使用as.sh来执行:

$ # 构建镜像
$ docker build . -t example-attach
$ # 启动容器
$ docker run --name example-attach --rm example-attach

$ # 在另一个终端进入容器,执行as.sh
$ docker exec -it example-attach sh
/app/src/main/java $ /opt/arthas/as.sh
Arthas script version: 3.6.7
tools.jar was not found, so arthas could not be launched!

行吧,咱们先用jdk运行下,先看下arthas是怎么attach起来的:

# 替换容器为JDK镜像并运行

# 先启动Attach Listener
$ pid=1 ;\
  touch /proc/${pid}/cwd/.attach_pid${pid} && \
  kill -SIGQUIT ${pid} && \
  sleep 2 &&
  ls /proc/${pid}/root/tmp/.java_pid${pid}
# -x表示调试执行,会输出执行了哪些命令;1为java进程pid
$ bash -x /opt/arthas/as.sh 1
...
+ /usr/lib/jvm/java-1.8-openjdk/bin/java -Xbootclasspath/a:/usr/lib/jvm/java-1.8-openjdk/lib/tools.jar -Djava.awt.headless=true -jar /opt/arthas/arthas-core.jar -pid 1 -core /opt/arthas/arthas-core.jar -agent /opt/arthas/arthas-agent.jar
...
+ telnet 127.0.0.1 3658
...

可以看到,最主要的逻辑是java -jar arthas-core.jar -pid 1 -core arthas-core.jar -agent arthas-agent.jar,然后再去连接3658端口。

-Xbootclasspath/a:tools.jar当然有用,但是在JRE中没有tools.jar,所以可以忽略。那么上面的逻辑我们直接尝试在JRE上运行呢?我们继续在JRE镜像中执行上面的命令:

# 替换容器为JRE镜像并运行

# 先启动Attach Listener
$ pid=1 ;\
  touch /proc/${pid}/cwd/.attach_pid${pid} && \
  kill -SIGQUIT ${pid} && \
  sleep 2 &&
  ls /proc/${pid}/root/tmp/.java_pid${pid}
$ cd /opt/arthas/
$ java -jar arthas-core.jar -pid 1 -core arthas-core.jar -agent arthas-agent.jar
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/attach/AgentLoadException
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
    at java.lang.Class.getMethod0(Class.java:3018)
    at java.lang.Class.getMethod(Class.java:1784)
    at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: com.sun.tools.attach.AgentLoadException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 7 more

对照代码来看,这个报错其实很正常,arthas-core中会调用Attach API,然后加载Agent(重点代码都已经标记):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BieJ2Jvf-1677748988565)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b9476d0ceddf4adf8924c9d7e884fe34~tplv-k3u1fbpfcp-zoom-1.image “1.png”)]

熟悉类加载机制的同学们可能猜到了,Arthas.class中依赖了com.sun.tools.的一些类,所以上面的报错其实是在类链接的时候就报错了。这也是为什么报错的stacktrace中没有任何arthas的包出现。

看着上面arthas的代码,就不得不思考下如何规避掉对tools.jar的依赖了。

如何去除对 JDK 的依赖

第一 像图中这样,直接调用com.sun.tools.attach.*相关类、方法,是肯定不行的,上面的报错其实已经很说明情况了。另外,通过反射也不行,tools.jar就不存在,自然无法加载这些类。

第二, 能不能通过我们手动把tools.jar放到容器中的方式呢?理论上确实可以,相关issue也说了具体的操作和注意事项:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-44yIRJja-1677748988566)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29c548e459a7418c9292c0d0c03b2bdf~tplv-k3u1fbpfcp-zoom-1.image “2.png”)]

理论上这样确实能工作,但其一,tools.jar是根据不同的jdk发行版、不同的jdk版本而不同的。比如,同样在eclipse-temurin:11-jre-alpine里面也挂不上arthas,你就不能copy jdk8的tools.jar来处理。

我们在继续看下有没有其他方式来挂agent。

第三, 看了一圈,ByteBuddy实现了attach agent的功能。但ByteBuddy是通过逐个尝试的方式来尝试attach,而且几乎都依赖tools.jar,大家感兴趣的话,可以看下下面几个策略的实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fQ7V0z0c-1677748988566)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cc288841c4854cbe9594ecc28eba6184~tplv-k3u1fbpfcp-zoom-1.image “3.png”)]

看起来我们可以自己实现一个AttachmentProvider,然后改造arthas通过ByteBuddy挂agent就可以了。

刚开始也是这样想的,甚至代码都写了一半了。直到晚上回家路上,想到上一篇文章中说的,可以通过自定义脚本或者jattach的方式来attach。

第四, 通过jattach来加载。

参考jattach的文档,如下操作下即可:

# 安装 jattach
$ apk add jattach

# 挂载arthas-agent.jar
$ jattach 1 load instrument false /opt/arthas/arthas-agent.jar
Connected to remote JVM
JVM response code = 0
return code: 0

# netstat确认下监听端口
$ netstat -alnp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:3658          0.0.0.0:*               LISTEN      1/java
...

# 连接对应端口
$ java -jar /opt/arthas/arthas-client.jar 127.0.0.1 3658

经过了如上操作,arthas就可以畅快执行了:

在这里插入图片描述

最终解决方案

咱知道有的时候,我们仅仅需要一个答案:

$ pid=1 ;\
  jattach ${pid} load instrument false /opt/arthas/arthas-agent.jar && \
  java -jar /opt/arthas/arthas-client.jar 127.0.0.1 3658

总结

相比上一次musl+jdk8+pid 1的问题,这次我们用attach机制做了更多的事情。开发同学遇到JRE,再也不用换JDK、换镜像,能够最大程度的保留现场,问题排查就变得顺畅高效的多了。当然,在容器环境中,Java应用遇到的奇奇怪怪的情况,不止如此,欲知后事如何,且听《容器中的Java》系列下回分解吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/383399.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SEO 如何提升网站权重?

关于SEO如何提高网站权重,米贸搜整理了以下内容,希望对大家有所帮助:1. 网站不能都使用收藏。有些站长,在网站上线之前,没有充分考虑,没有很好地定位网站,网站内容的来源从哪里来,就…

全网最详细的软件测试基础知识概述(绝密),一般人我不告诉他

目录 1、什么是软件 2、软件工程的内容 3、软件的生命周期 4、什么是软件测试 5、软件测试的方法 6、软件测试阶段有哪些任务 7、测试的原则 8、软件测试工作流程图 9、自动化测试 10、自动化测试的过程 11、自动化测试的优点 12、自动化测试技术 13、自动化测试的…

EasyExcel 实现写入多个sheet数据进excel模板并下载

目录说明说明 场景说明:对数据库或者其他数据源读取获取到数据,需要写入到excel完成下载功能,其中一个sheet是固定模板,只需要填充值,另一个sheet是动态的表头和数据需要填充。模板如下图,模板提前放在项目…

【简单DP】Children’s Queue

哈哈,独立做出来了,不错感觉这种暴力DP还是很好做的Problem - 1297 (hdu.edu.cn)题意:思路:写了这么多DP,我认识到DP的状态设计是最难的首先看阶段,就是第i个人然后影响决策的因素就是,女生不能…

【docker mysql】docker 快速安装mysql和redis

docker_hub 官网:点击docker_hub仓库地址 docker run --name mysql-bear -p 3307:3306 -e MYSQL_ROOT_PASSWORDmysql-bear -d mysql:latestdocker run --name redis-bear -p 6479:6379 -d redis再次使用docker ps 命令查看即可。 我这里把端口映射到主机上了&…

【Axure教程】橡皮擦的擦除效果——刮奖原型

橡皮擦的擦除效果是系统常见的效果,在可以画图编辑的系统中或者是在抽奖刮奖的系统中非常常见。所以今天和大家分享在Axure中如何制作橡皮刷的效果,我们会议刮奖原型为案例,教大家制作出一个刮奖效果的高保真原型模板。一、效果展示1、鼠标移…

做测试一定要知道的——软件测试流程和测试规范标准文档

目录 1、目的 2、工作范围 3、工作职责 4、测试的流程 5、测试准备阶段 6、测试方法制定阶段 7、测试执行阶段 8、bug管理 9、标准文档 总结感谢每一个认真阅读我文章的人!!! 重点:配套学习资料和视频教学 1、目的 通…

关于Thread.start()后的困惑、imap

在for循环中,接着开thread,开完就start,当时有个困惑,就是比如开的一个thread的这个start执行完,但是这个for循环还没执行完,那程序会跑到for循环的后面逻辑吗?比如下面13行for循环开始开第一个…

浅谈子网掩码、IP地址、网络地址之间关系

文章目录一、什么是子网掩码二、给定IP地址,如何求网络地址网络标识(net-id)和主机标识(host-id)计算步骤三、CIDR地址表示方法(Classless Inter Domain Routing)四、IP地址与MAC地址一、什么是子网掩码 在TCP/IP协议…

阿里云云原生每月动态 | 聚焦实战,面向开发者的系列课程全新上线

作者:云原生内容小组 云原生是企业数字创新的最短路径。 《阿里云云原生每月动态》,从趋势热点、产品新功能、服务客户、开源与开发者动态等方面,为企业提供数字化的路径与指南。 本栏目每月更新。 趋势热点 《云原生实战指南》白皮书发布 …

如何使用金山轻维表发送生日祝福、入职纪念日祝福

作为企业HR或行政,如果能在员工生日当天发送一份生日祝福生日礼物,是不是可以给员工强烈的归属感和惊喜,但核查员工生日需要每天对着花名册查询,或单独设置提醒,对HR行政来说又比较繁琐复杂,还经常容易忘&a…

matlab - 特殊矩阵、矩阵求值、稀疏矩阵

学习视频1.特殊矩阵1.1 通用特殊矩阵format % 零矩阵(全0) 幺矩阵(全1) 单位矩阵 % zeros ones eye rand(生成0~1的随机元素) randn(生成均值为1,方差为0的符合正太分布的随机阵)zeros(3) % 3x3的全0方阵 zeros(3, 4) % 3x4的全0矩阵 exA ones(3, 5) % 3x5的…

mapbox-gl实现 2.5D 图层高度编辑器

文章目录前言表达式逻辑mapbox表达式转数学表达式数学表达式转mapbox表达式实现效果前言 mapbox-gl 支持表达式编辑 2.5D 建筑物高度,但是 style 文件原生的表达式很不直观,本文实现一个简单的 2.5D高度图层编辑器,核心是理解mapbox表达式规…

【Sentence Simplification via Large Language Models 论文精读】

Sentence Simplification via Large Language Models 论文精读InformationAbstract1 Introduction2 Related Work3 Sentence Simplification via LLMs4 Experiments4.1 Evaluation Settings4.2 Automatic Evaluation4.3 Human Evaluation4.4 Qualitative Study4.5 Ablation Stu…

开发同城外卖系统源码时应配置哪些功能?外卖系统源码分析

外卖系统大家都不会陌生,我们都会想到某团、某饿这两个行业top,他们已经成为了年轻人手机必备软件之一,而且除了app端外,他们还很贴心开发了微信小程序的版本,免去了下载app的繁琐,打开微信就能使用。那么&…

阿里开源自研高性能核心搜索引擎 Havenask

去年12月,阿里开源了自研的大规模分布式搜索引擎 Havenask(内部代号 HA3)。  Havenask 是阿里巴巴内部广泛使用的大规模分布式检索系统,支持了淘宝、天猫、菜鸟、优酷、高德、饿了么等在内整个阿里的搜索业务&#…

点击糖化学试剂361154-30-5,Ac4ManNAz,1,3,4,6-四-O-乙酰基-N-叠氮乙酰基氨基甘露糖

Ac4ManNAz产品描述:N-叠氮乙酰基甘露糖胺-三酰化(AC4MANAZ)可用作标记试剂,点击糖化学试剂,叠氮化物基团允许它与炔烃反应,是一种含叠氮的代谢糖蛋白标记试剂,叠氮化物修饰的蛋白质可以通过与炔…

webman apidoc安装、生成接口文档

1 npm install apidoc -g 2 apidoc -h 3 新建 apidoc.json { "name": "demo", "version": "1.0.0", "description": apidoc demo", "title": "demo",…

如何提高大数据传输的安全性

面对大数据传输安全相关的挑战和威胁,业界针对安全防护技术进行了针对性的实践和调研。本文主要从平台安全、数据安全、隐私保护三个方面对大数据传输安全技术的发展进行阐述。 如何安全地改进大数据传输? 平台安全、数据安全、隐私保护等相关技术不断完…

springboot原项目配置文件迁移至nacos

目录一、配置文件迁移nacos1.安装nacos2.添加依赖3.改造service-product3.改造server-gateway一、配置文件迁移nacos 1.安装nacos 1,如果之前安装过nacos,nacos数据保存至mysql,先删除已安装的nacos,再安装 docker stop nacos …