1. 线上服务卡顿排查实战
遇到线上服务响应变慢时,最头疼的就是不知道问题出在哪里。去年我们电商大促时就遇到过首页加载突然变慢的情况,当时用Arthas快速锁定了问题。下面分享具体排查套路:
首先连上目标应用后,直接输入dashboard命令,这个实时监控面板就像汽车的仪表盘,能一眼看出CPU、内存、线程的健康状况。当时我们发现有个线程的CPU占用率长期保持在90%以上,明显不正常。
接着用thread -n 3查看最忙的3个线程,果然发现有个名为"price-calculator"的线程堆栈显示卡在数据库查询。这时候祭出trace命令追踪调用链路:
trace com.example.PriceService calculatePrice '#cost > 500'这个命令会打印出所有耗时超过500ms的方法调用路径。我们很快发现是价格计算时频繁调用用户等级校验导致的,原来最近新增了会员等级体系但没加缓存。
最后用watch命令观察方法参数和返回值:
watch com.example.UserService checkUserLevel '{params, returnObj}' -x 3确认每次请求都重复查询相同用户等级后,紧急加了Redis缓存,20分钟内解决了这个性能瓶颈。
2. 内存泄漏精准定位技巧
内存泄漏就像程序里的慢性病,初期不易察觉但危害极大。上个月我们监控系统发现某个服务内存持续增长,用Arthas是这样排查的:
先用jvm命令查看基础内存情况,发现老年代占用异常高且Full GC后不释放。这时候heapdump命令可以直接生成内存快照:
heapdump /tmp/leak.hprof但8G的堆内存生成快照太耗时,改用vmtool命令动态获取对象统计:
vmtool --action getInstances --className java.util.HashMap --limit 10发现某个业务缓存HashMap的体积异常庞大。进一步用sc -d查看类加载信息,结合ognl表达式检查缓存管理器:
ognl '@com.example.CacheManager@instance.cacheSize'最终定位到是定时任务不断往缓存添加数据但从未清理。临时用redefine命令热修复了清理逻辑,为正式发版争取了时间。
3. 热更新代码验证方案
线上紧急修复时最怕改错代码引发新问题。我们团队现在都用Arthas做预验证:
假设要修复的类OrderService有个计算优惠券的方法有bug。先用jad反编译线上代码确认问题:
jad --source-only com.example.OrderService calculateDiscount把修正后的代码保存为OrderService.java,用mc命令编译:
mc OrderService.java -d /tmp最关键的一步是用redefine热加载:
redefine /tmp/com/example/OrderService.class立即用tt命令录制测试请求:
tt -t com.example.OrderService calculateDiscount -n 5确认无误后再发版,这种方案特别适合修复紧急但不适合立即重启的场景。上周刚用这个方法修复了优惠券叠加计算的BUG,整个过程用户无感知。
4. 复杂日志动态追踪术
有些BUG在测试环境死活不出现,到线上又不敢乱加日志。这时候可以用Arthas的动态日志功能:
比如想监控支付回调处理,但不想改代码重新部署。先用stack看调用链路:
stack com.example.PaymentCallbackHandler process找到关键方法后,用watch命令打印入参和异常:
watch com.example.PaymentService verifyPayment '{params, throwExp}' -e -x 2遇到签名验证失败时,还能用tt命令回放特定请求:
tt -i 1003 -p最厉害的是可以临时修改返回值测试兼容性:
ognl '#obj=@com.example.PaymentService@instance, #obj.setDebugMode(true)'这种动态插桩的能力,让我们排查第三方接口对接问题效率提升了好几倍。
5. 线程阻塞问题诊断
服务假死是最严重的线上事故之一。上季度我们MQ消费者线程池就发生过集体阻塞,分享当时的排查过程:
先用thread -b找出所有阻塞线程,发现都在等待数据库连接。通过thread --state BLOCKED统计阻塞线程数:
thread --state BLOCKED | wc -l用jvm命令查看连接池状态:
ognl '@com.zaxxer.hikari.HikariDataSource@getHikariPoolMXBean().getActiveConnections()'发现连接泄漏,接着用tt记录慢查询:
tt -t java.sql.Connection prepareStatement -n 10最终定位到有个批量更新没关ResultSet。临时解决方案是用vmtool强制回收连接:
vmtool --action forceGc --className java.sql.Connection6. 方法级性能调优
去年优化风控系统时,我们用Arthas发现了不少性能金矿:
先用profiler start做CPU采样,生成火焰图看到大量时间花在JSON序列化。然后用trace量化每个方法耗时:
trace com.example.RiskControlService * '#cost > 10'发现有个权限校验方法重复计算,加缓存后性能提升30%。更惊喜的是用monitor统计方法调用:
monitor com.example.RuleEngine check -c 60发现某些冷门规则可以延迟加载。最终配合jad和mc热更了加载逻辑,系统吞吐量直接翻倍。
7. 类加载冲突解决
最近遇到个诡异问题:本地开发正常但线上总是报NoSuchMethodError。Arthas的类加载器命令帮了大忙:
先用sc -d查看类来源:
sc -d org.apache.commons.lang3.StringUtils发现线上加载的是老版本,然后用classloader -t看继承树:
classloader -t定位到是某个中间件自带了旧jar包。临时解决方案是用redefine强制加载正确版本:
redefine /path/to/correct-version.jar8. 生产环境安全诊断
最后分享几个安全相关的实用技巧:
检查配置泄露:
sysprop | grep password监控敏感操作:
watch javax.crypto.Cipher * '{params,returnObj}' -x 2跟踪SQL注入风险:
trace java.sql.Statement executeUpdate这些命令可以帮助快速发现安全隐患,但要注意权限控制。我们团队现在把Arthas集成到发布流程,上线前必做安全检查。