2026/4/6 7:47:10
网站建设
项目流程
flash xml网站,海口cms模板建站,如何看出网站用dede做的,网络推广培训心得体会Arthas 是什么#xff1f;
简单讲#xff0c;他是一款开源的线上诊断工具
可以在#xff0c;不重启应用的前提下#xff0c;对服务进行实时监控#xff0c;诊断#xff0c;调试#xff0c;甚至进行热修复
官方文档#xff1a;https://arthas.aliyun.com/doc/Arthas 解决…Arthas 是什么简单讲他是一款开源的线上诊断工具可以在不重启应用的前提下对服务进行实时监控诊断调试甚至进行热修复官方文档https://arthas.aliyun.com/doc/Arthas 解决了什么问题1、线上debug只能加日志-》打包-》重新部署-》等待复现。2、性能瓶颈慢方法、cpu飙高、内存泄漏难以定位3、类加载异常难定位ClassNotFoundException、NoSuchMethodError等不知道从哪加载的是否被覆盖4、逻辑调用链不清晰方法被谁调用的参数是什么5、紧急bug只能停机重新发布适用场景适合线上紧急问题、性能问题、类加载问题排查以及临时调试不适合因为Arthas需手动交互数据不存储所以不适合自动化或长期监控。Arthas 是怎么解决的这些问题说白了Arthas利用了Java AgentBytecode Instrumentation字节码增强技术,在运行时动态注入探针实现对 JVM 内部状态的非侵入式观测与干预Java Agent: 允许在不修改源代码、不重启应用的前提下对程序进行监控、诊断、性能分析、日志增强、安全审计甚至热修复Arthas提供了哪些能力能力说明实时监控查看方法入参、返回值、异常watch性能剖析分析方法耗时、生成火焰图trace/profiler类信息查询查看类从哪个 JAR 加载、反编译字节码sc/jad热更新动态替换类定义修复线上 BugredefineJVM 全局视图实时查看线程、内存、GC、系统负载dashboard调用链追踪查看方法被谁调用、调用栈stack所有操作无需重启应用无需改代码秒级生效。Arthas如何使用1、安装任选其一# 方式一快速启动推荐curl-O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar# 方式二脚本安装Linux/macOScurl-L https://arthas.aliyun.com/install.sh|sh./as.sh2、启动运行java -jar arthas-boot.jar-》列出当前机器上所有 Java 进程输入目标进程的编号进入 Arthas 命令行提示符如[arthas12364]$启动时如指定 HTTP 端口java -jar arthas-boot.jar --http-port 8563可在浏览器访问http://服务器IP:8563图形化界面。3、Arthas提供了哪些命令# 查看系统实时状态线程、内存、GCdashboard# 反编译某个类确认线上代码是否正确jad com.example.service.UserService# 监控方法入参和返回值“这个方法执行时参数/返回值/异常是什么” → 监控 方法内部数据watchcom.example.service.UserService login{params, returnObj}-x2# 追踪方法调用耗时定位慢接口trace com.example.controller.UserController getUser# 查看某个方法的调用栈“谁调用了这个方法” → 查看 调用栈Call Stackstack com.example.service.UserService saveUser# 动态修改日志级别无需重启logger --name com.example.service.UserService --level debug# 搜索已加载的类sc *UserService*# 搜索类的方法sm com.example.service.UserService *# 生成火焰图需 profiler 支持profiler start# ...等待几秒...profiler stop如何使用Arthas进行线上具体场景问题排查发现现象 → 确定排查思路 → 使用Arthas排查 → 解决问题常见场景速查表问题类型关键命令核心输出CPU 100%thread -n 3→jad→profiler高 CPU 线程 热点代码死锁thread -b死锁线程对 锁依赖关系慢接口trace→watch→stack耗时分布 参数/异常类加载问题sc→jad→classloader类加载情况 类反编译内容场景一CPU飙高现象1、应用响应变慢甚至无响应2、服务器负载飙升top显示某个 Java 进程 CPU 占用接近 100%排查思路CPU飙高通常是因为无限循环、正则回溯、复杂计算等引起的。所以排查思路是1、找出哪个线程在疯狂占用 CPU2、这个线程在执行什么代码Arthas排查定位步骤1、启动 Arthas 并 attach 到目标进程java -jar arthas-boot.jar 并进入目标服务进程2、查看 CPU使用率最高 的前 3 个线程thread -n 3关键信息线程名Thread-10ID45CPU占用 98.7%卡在DataProcessor.java:28执行后输出示例如下 Threads Total: 50, NEW: 0, RUNNABLE: 10, BLOCKED: 0, WAITING: 20, TIMED_WAITING: 20 Thread-10 Id45 cpuUsage98.7% RUNNABLE at com.example.service.DataProcessor.process(DataProcessor.java:28) at com.example.service.DataProcessor.lambda$start$0(DataProcessor.java:15) ...3、反编译该类确认代码逻辑是否有死循环或低效算法jad com.example.service.DataProcessor例如while(true){// ← 问题在这里list.add(newObject());}4、生成火焰图并下载到本地用浏览器打开观察其中的热点方法。profiler start# 等待 10 秒然后输出结果文件 arthas-output/xxx.htmlprofiler stop --format html5、定位到具体原因修改后重新部署场景二死锁Deadlock现象1、请求全部超时应用完全卡住2、日志中无异常信息但日志不再输出线程不再处理新任务排查思路死锁通常由多个线程互相持有对方需要的锁导致。JVM 能自动检测死锁。Arthas排查定位步骤1、启动 Arthas 并 attach 到目标进程java -jar arthas-boot.jar 并进入目标服务进程2、检查是否存在死锁thread -b-b参数表示detect deadlock检测死锁存在死锁则会输出死锁的具体信息以下Thread-A、Thread-B相互引用典型死锁Found one Java-level deadlock: Thread-A: waiting to lock monitor 0x00007f8b4c003a88 (object 0x000000076b8d1234, a java.lang.Object), which is held by Thread-B Thread-B: waiting to lock monitor 0x00007f8b4c004b99 (object 0x000000076b8d1240, a java.lang.Object), which is held by Thread-A Java stack information for the threads listed above: Thread-A: at com.example.service.OrderService.pay(OrderService.java:30) - waiting to lock 0x000000076b8d1234 (a java.lang.Object) at com.example.controller.OrderController.submit(OrderController.java:22) ...3、查看完整线程栈thread# 查看所有线程状态# 或指定线程 IDthread454、根据线程栈找出具体死锁位置及原因并加以解决重新部署。场景三慢接口现象其他接口正常只有某个接口响应时间暴涨例如100ms-》5s排查思路可能的原因1、是不是数据库慢查询2、是不是调用的其他服务的http接口超时进而导致的超时3、本地方法逻辑复杂如大循环、序列化此时需要追踪整个调用链的耗时分布。Arthas排查定位步骤假设慢接口对应 Controller 方法com.example.controller.UserController.getUser1、使用trace命令追踪方法调用耗时trace com.example.controller.UserController getUser1.1、然后触发一次请求使Arthas输出调用链路如curl http://localhost:8080/user/123---ts2025-12-13 17:40:01;thread_namehttp-nio-8080-exec-2;id2a;is_daemontrue;priority5;TCCLorg.springframework.boot... ---[5023.45ms] com.example.controller.UserController:getUser() ---[0.12ms] com.example.service.UserService::findById() ---[5022.89ms] com.example.service.NotificationService::sendEmail() # ← 耗时 5 秒 ---[0.05ms] return result1.2、分析调用链路找出耗时原因。例如上诉sendEmail()花了 5 秒可能是 SMTP 超时或网络问题。1.3、重复上诉步骤找到最终的那个慢方法。例如继续分析sendEmail方法内部trace com.example.service.NotificationService sendEmail2、监控慢方法的参数和返回值确定问题出现的原因。watchcom.example.service.NotificationService sendEmail{params, returnObj, throwExp}-v -x2## 可看到是否传入了错误邮箱、是否抛出异常等。3、可通过热更新先保证线上服务可用临时解决应急例如跳过该逻辑3.1. 修改UserController.java注释掉notificationService.sendEmail(...)3.2. 编译生成.class3.3. 执行redefine /tmp/UserController.class4、根本上解决该问题并发布更新。场景四类加载异常现象异常常见原因ClassNotFoundException类根本不存在于 classpathNoClassDefFoundError编译时存在运行时缺失如依赖未打包NoSuchMethodError方法签名不一致通常是版本冲突A 依赖 v1B 依赖 v2IncompatibleClassChangeError类结构不兼容如接口变抽象类LinkageError/ClassCastException同一个类被不同 ClassLoader 加载排查思路核心问题本质类找不到→ 检查是否在 classpath类找到了但不对→ 检查是否被错误版本覆盖同一个类加载了多份→ 检查 ClassLoader 隔离问题Arthas 排查思路四步法1、类是否被加载→ 使用scSearch Class2、如果已加载从哪加载的→ 使用sc -d查看类的详细信息含 ClassLoader 和 codeSource3、反编译字节码确认方法/字段是否存在→ 使用jad查看实际加载的代码4、检查类加载器层次分析是否存在冲突→ 使用classloader命令分析 ClassLoader 树Arthas排查定位详细步骤假设有以下报错java.lang.NoSuchMethodError: com.example.util.StringUtils.isBlank(Ljava/lang/String;)Z根据报错怀疑StringUtils被低版本 JAR 覆盖1、搜索该类是否被加载sc *StringUtils*发现存在两个StringUtils需进一步确认用的是哪个com.example.util.StringUtils org.apache.commons.lang3.StringUtils2、查看具体类的加载信息关键sc -d com.example.util.StringUtils输出示例重点看code-source和class-loaderclass-info com.example.util.StringUtils code-source /app/lib/utils-1.0.jar ← ⚠️ 关键来自哪个 JAR判断是不是你所期望的那个code-source 为空可能是从 classes 目录加载非 JAR name com.example.util.StringUtils isInterface false isAnnotation false isEnum false isAnonymousClass false isArray false isLocalClass false isMemberClass false isPrimitive false isSynthetic false simple-name StringUtils modifier public annotation interfaces super-class java.lang.Object class-loader org.springframework.boot.loader.LaunchedURLClassLoader1c20c6b4 class-loader-hash 1c20c6b43、反编译确认方法是否存在jad com.example.util.StringUtils例如以下输出片段没有isBlank方法所以抛出NoSuchMethodErrorpublicclassStringUtils{publicstaticbooleanisEmpty(Stringstr){returnstrnull||str.length()0;}// 注意没有 isBlank 方法}4、检查是否有多个版本的 JAR方法 A列出所有 JAR 中的该类需知道可能路径# 查看 classpath 下所有 JARclassloader -l方法 B搜索所有 ClassLoader 中的该类Arthas 3.5# -a 表示 all classloaders可发现不同 ClassLoader 加载了不同版本。sc -a *StringUtils*方法 C查看某个 ClassLoader 加载了哪些资源# 先获取 ClassLoader hash从 sc -d 输出中拿到如 1c20c6b4classloader -c 1c20c6b4 -r com/example/util/StringUtils.class# 输出file:/app/lib/utils-1.0.jar!/com/example/util/StringUtils.class5、对比期望版本 vs 实际版本5.1. 将正确版本的StringUtils.class上传到服务器5.2. 用 Arthas 反编译对比# 反编译线上加载的jad --source-only com.example.util.StringUtilsonline.java# 反编译你本地正确的先放到 /tmp/correct/ 目录jad --source-only -c /tmp/correct/StringUtils.classcorrect.java# diff 对比diffonline.java correct.java总结类加载问题排查流程图Arthas 的scjadclassloader组合拳是解决此类问题的“黄金三角”graph TD A[出现 ClassNotFoundException / NoSuchMethodError] -- B{sc *ClassName* 是否有输出?} B -- 无 -- C[类未在 classpath检查打包/依赖] B -- 有 -- D[sc -d ClassName 查看 code-source] D -- E[jad ClassName 确认方法/字段是否存在] E -- F{是否符合预期?} F -- 否 -- G[版本冲突检查依赖树和 JAR 内容] F -- 是 -- H[检查 ClassLoader 是否隔离/重复加载] H -- I[classloader -a 或 sc -a 排查多加载]使用实用建议1、精准监控特定参数# 只监控用户名为 admin 的登录请求watchcom.example.service.UserService loginparams[0]admin-v2、限制监控次数# 只捕获前 3 次调用watchcom.example.service.UserService login{params, returnObj}-n33、结合 OGNL 表达式过滤watchcom.example.service.OrderService createOrderparams[0].amount 1000-x34、快速定位 CPU 飙高# 查看最耗 CPU 的线程thread -n3# 结合 jstack 分析死锁thread -b5、热修复谨慎使用# 1. 修改本地 .java 文件并编译成 .class# 2. 上传到服务器# 3. 执行redefine /tmp/UserService.class注意redefine不能增减字段/方法仅支持方法体修改。6、导出堆快照用于 MAT 或 JProfiler 分析内存泄漏。heapdump --live /tmp/heap.hprof7、类冲突定位7.1、模糊搜索 包过滤只搜自己项目的类避免第三方干扰sc com.yourcompany.*Service7.2、结合异常堆栈定位具体类从异常日志中提取完整类名直接sc -d它7.3、注意内部类写法# 内部类要用 $ 分隔sc com.example.OuterClass$InnerClassjad com.example.OuterClass$InnerClass7.4、Spring Boot 特别注意Spring Boot 使用LaunchedURLClassLoader类通常来自BOOT-INF/classes或BOOT-INF/lib/xxx.jar如果sc -d显示code-source为空可能是从classes目录加载非 JAR