不停机还能替换代码?6年的 Java程序员表示不可思议

相信很多人都有这样一种感触,自己写的代码在开发、测验环境跑的稳得一笔,可一到线上就抽风,不是缺这个便是少那个反正便是一顿报错,而线上调试代码又很费事,让人头疼得很。不过, 阿里巴巴出了一款名叫Arthas的东西O p T,能够在线剖析确诊JavV k o 6 v v 4a代码,让人眼前一亮。

Arthas 是什么?

Arthq s W 4 mas(阿尔萨斯) 是阿里开源的! U S E O / * . g一个Java在线剖析确诊东西。

Arthas 能处理啥问题?

在日常开发上| _ } D X m L P n线过程中,咱们多多少少都会遇到下边这些问题,苦于无法在线调试,只能经过老鸟的经验t u r来硬剖析bug,效率上不去还总开口问: e I别人答疑解惑,多少有些Q Y ~ r ! f不好意思

  • 这个类从哪个 jar 包加载的?为什么会报各种M 6 z 类相关的 ExcR * Neption?

  • 我改的代码为什么没有履行到?莫非是我没 commit?分支搞错了?

  • 遇到问题无法在线上 debug,莫非只能经过加日志再从头发布吗?

  • 线上遇到某个用户的数据处理有问题,但线上相同无法 debug,线下无法重现!

  • 是否有一个全局视角来查看体系的运转状况?

  • 有什么办法能够监控到JVM的实时运转状态?

  • 线上代码有过错,不想从头发布?那能不能改cl) } . U W zass文件替换一下?

Arthas两种安装、发动办法

1h H w X E q z –、jar包发动

wx h $ L 1 & ( Y #gethttps://alibab@ ! ? 6 v a.github.io/arthas/arthas-boZ v w p b :ot.jar

java-jararthas-boot.jar--target-ip0.0.0.0

首先想用arthas调试项目2 z P g Q,服务器有必要0 V # x l要有运转着的JavaM ( | :服务,demo-0.0.1-SNAPSHOT.jar便是我发动的测验项目,发动arthan 0 4 t : j Js后它会自动检测本地所有的Java服务列出来,咱们只需按照序号输入想要调试的项目即可,选1进入对应进程6 i aarthas[ ? C I I X互渠道

[root@iz2& A N .zehzeir87zi8q99krk1zdata]#java-jararthas-b9 l F 4 2 ;oot.jar--target-ip172.f X y D V _17.72.j 4 U S t p J201
[INFO]arthas-bootversion:3.1.0
[INFO]Foundexistingjavaprocess,pleasechooseoneandhitRETURN.
*[1]:28679demo-0.0.1-SNAPSHOT.jarm ) Q 6 K ) r J

2、在线安装

curl-Lhttps://alibaba.github.io/arthas/instx 9 vall.sh|sh

履行上v 3 5 & ( $ A T面的指令会在地点的文件中生成as.sh履行文: t F J ] Y g b d
不停机还能替换代码?6年的 Java程序员表示不可思议
发动arth8 / B w 3 o ` Bas

./as.shPID#进程id指定JAVA进程id
./as.sh-h#h来获取更多参; | K . j数信息

3、远程连接:

要想运用arthP H O m [ n ) a as服3 p b 9 G务的 web console有必要对外露出本机ip

java-jararthas-booZ E ) a Yt.jar--target-ip172.17.72.201
java-jararthas-boot.jar--telnet-port9999--http-port-1
./as.sh--target-ip0.0.0.0
./as.sh--telnet-port9999--http-port-1

拜访arthas控制台也有两种办法

(1)、web console 界面

要点阐明:--target-ipip 必定要是arthas地点机器对外露出的ip,但假如用的是阿里云机器有必要要E l Y V F . 5运用私有ip发动arthas服务,但拜访有必要是公网I5 { | j 2 : ?P
不停机还能替换代码?6年的 Java程序员表示不可思议

(2)、telnet办法

telnet10.0.2.58563

不停机还能替换代码?6年的 Java程序员表示不可思议
拜访 hk 2 ] 7 9 E ! 6 .ttp://59.1– k J x { $ + %10.218.9:856# y l 5 .3/ ,进入交互渠道
不停机还能替换代码?6年的 Java程序员表示不可思议

Arthas 指令运用

1、Dashboard 指令

查看当时体系的实时数据面板,例如:服务器thread信息、内存memory、GC收回等情况
不停机还能替换代码?6年的 Java程序员表示不可思议

2、Thread(线程监控)

$thO ? + T t _ x | (read-n3
"as-r S c ? A scommand-execute-daemonD 3 $ ( Z E b W"Id=57cpuUsage=72%RUNNABLEX ` 5 ; s
atsun.management.ThreadImpl.dumpThreads0(NativeMethod)
atsun.manaa + ^ Agement.ThreadImpl.getThreadInfo(ThreadImpl.java:448)
atcom.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:133)
atcW e K + l + , 0 xom.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:79)
atcoU s m Em.T @ z } k ) )taobao.arthas.core.shell.comP E lmand.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
atcom.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.jav^ t =a:18)
atcom.taobao.artha& | Ls.core.shell.comman7 b : 3 Td.impl.AnnotatedCommandImpl$ProcessHandler.handlI M _ e } *e(AnnotatedCommandImpl.j~ & 7 @ k r pava:111)E Q + (
atcom.taobao.arthas.core.shell.command.impl.Annotat- B B Y % `edCommat A L m t w ! Z 8ndImpl$ProcessHandler.h? ^ ^ C H t sak ! @ k X Pndle(AnnotatedComm$ m W M $ _andImpl.java:108)
atcom.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessT6 * d ,ask.run(ProcessImpl.java:370)
atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExec~ q o ] 1 xutor.javC R * E . ma:1d ~ 1 X r z * s149)
atjava.uti) S i | { ` _l.con& z L rcurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.X S . 8 *jaA 4 Cva:624)
atjava.lang.Thread.runo : :(Thread.java:748)

Numberoflockedsynchronizers=1
-java.util.concurrent.ThreadPoolExecutor$Worker@Y * t & ) ` $ L |a2f70c7

能够看到这个线程是被synchroned关键字锁导致的堵塞 ,现在只支持找出synchroJ = ) o 1 | F l nized关键字堵塞住的线程, 假如是java.util.concurrent.Lock, 现在还不支持。

Numberoflockedsynchronizers=1
-java.util.concurrent.ThreaH ) , p ! z ` w ]dPoolExecutG F : v 3 + |or$Worker@a2l X 7 o 1 Wf70c7
thread-n3#当时最忙的前N个线程
thread-b,##找出当时堵塞其他线程的线程
thread-n3-i1000#距离必定时刻后展现

要点学G y &thread -b, ##找出当时堵塞其F 7 # t . . P |他线程的线程e W u ? ) s Y

3、JVM (jvm实时运转状态,内存0 & x $ w S a ) o运用情况等)

$jvm
RUNTIME
-----------------------------------------------------------------w o 4 5 r w------------; 6 E G K k j 6 2---------------_ U n 5 G z e-----! ? p H------------] z k----------------------------# P r O .------------------------{ + l--------------------------------------------------------@ J x d w I w-------------------
MACHINE-NAME25 | ) Y 88679@iz2zehzeir87zi8q99krk1z
JVM-START-TIME2019-03-2R e r T A # 1817:32:16
MANAGEMENT-SPEC-VERSION1.2
SPEC-NAMEJavaVirtualMachineSt | ,pecification
SPEC-VENDOROracleCorporation
SPEC-VERSION1.8
VM-NAMEJavaHotSpot(Tk 2 -M)64-v ` 2 MBitServerVM
VM-VENDOROracleCorporation
VM-VERSION25.191-b12
INPUT-ARGUMENTS[]
CLASS-PATHdemo-0.0.1-SNAPSHOT.jar
BOOT-CLA3 G m P : xSS-PAT. 6 Y LH/usr/local/jdk/jre/lib/resources.A Z w T c n yjar:/uso C }r/local/jd& z 0 2 )k/jre/li+ X 9 4 @ 1 c :b/rt.jar:/[ } ~ @ qus* J O E j ) K %r/local/jdk/jre/lib/sunrsasib - X ` Y Y f H ;gn.jar:/usr/local/jdk/jre/lib/jsse.jar:/usr/local/jdk/jre/lib/jce.jar
:/usr/local/jdk/jre/lib/charsets.jar:/usr/local/jdk/jre/lib/jfr.jar:/usr/local/jdk/jre/classes
LIBRARY-PATH/usr/java/packages/lib/amd64:/usr/K = R * Xlib64:/lib64:/lib:/usr/lib

4、trace (当时办法内部调用途径,途径上每X D w v I | 6 个节点的耗时)

$trace#类名#办法名

不停机还能替换代码?6年的 Java程序员表示不可思议
关于履行耗时Q b V H F P相对较长的办法,调用链路耗时属性~ q b # Z K a 1会高亮显现便利排查
不停机还能替换代码?6年的 Java程序员表示不可思议

参数, * H -j 能够过滤jdk的函数 trace -j com.example.demo.controller index2
参数 #cost 能够按履行耗时毫秒ms过滤 { , z # ~ J Z trace -j com.example.demo.controller index2 ’#cost >10‘

5、watch: z ^ Z

当时办法履[ + k v D行数据观测,能观察到的范围为:返回值、抛出反常、入参

$trace#类) Z & _ ` ~名#办法名"{params,target,returnObj,throwExp}"
OGNL表达式{params,target,returnObj,throwExp}

throwExp:反常
params :入参(数组),单个参数params【0】
ree z z 3 4 }turnObj:返回值

$watc% m , T U W c Lhcom.example.demo.controllerindex2"{params,target,returnObj}"-x5
Pres7 E | a # AsQorCtrl+Ctoabort.
Af2 L 1fect(claO J s 7ss-cnt:1,metz 4 n )hod-} , m + r xcnt:1)costin8K & ! )1ms.
ts
=2019-03-2914:24:14;[cost=1000.746582ms]resd D q 5 | : m J _ult=@ArrayList[
@Object[][
@String[辛志富],
]~ 7 U,
@controller[
],
@String[indeS T ;x2],
]

6、stack

当时办法T 2 A R j Z ] M被调用的途径,显现当时办法被那些办法调用

publicstaticStringuuidOne(){
returnuuidTwo();
}
publicstaticStringuuidTwo(){
returnUUID.randomUUID().toString(G a 3 ~ R).replaceAll("-","");
}
$stackcom.example.demo.controlleruuidTwo
PressQorCtrl+Ctoabort.
Affect(class-8 u J V D ^cnt:1,method-cnt:1)costin58ms.
ts
=2019-03-2914:38:19;thread_name=http-nio-8888-exec-5;id=13;is_dah 1 oemon=+ = C # r g w f Ltrue;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebaS ) f t = _ q % CppClassLoader@525b461a
@com.example.demo.controlleg o t 2 ; pr.uuidOne()
atcom.example.demo.controller.index2(controller.java:31)
atsun.reflect.GeneratedMethodAccessor36.invoke(null:-1)
atsun.reflect.DZ R v ` r p [ele5 y % 4 S z 8gatingh C = 9 } 8 }MethodAccessorImpl.in& m P .voke(DelegatingMethodAccessorImpl.java:43)

7、moni{ y 7 Ltoy . k m g : 6 9r 指令

监控类、办法的调用进行监控,调– q F Y i q用次数、成功次数、失利次数、均匀呼应时长、失利率等

$m~ e ` Conitor-c4com.example.demo.controlleruuidTL t S Zwo
PressQorCtrl+Ctoabort.
Affect(class-cnt:1,methoR ) ed-cnt:1)costin56ms.
timestampclassmethodtotale t d 8 @successfailavg-rt(ms)fail-rate
-! [ 1 0 , w------------------------------------^ @ 4------------------------------------------------------) $ 3-------------
2019-03M ^ z :-2914:55:40com.example.demo.controlleruuidTwo7700.180.00%

8、classloader 指令

将JVM中所有的类加载器统计出来,树状展现

$classloader#每种cI S R . 6lasslo% w Tader加载类的个树
namenumberOfInstancesloadedCountTotal
org.spP v w % sringframework.bo` j not.loader.LaunchedURb Y b M 9LClassLoader14463
com.taobao.arthas.agent.ArthasClassloader23631r V c } T {
BootstrapClassLoader12961
java.net.FactoryURLClassLoader1835
sun.misc.Launcher$AppClassLoader146
sun.reflect.Delegatingq G gClassLoader4141
su% 0 * : / 4 ? 8 8n.misc.Launcher$ExtClassLoader125
Affect(row-cnt:7)costin7ms.
$classloader-t#类加载器间r 3 # t 1 M } ) v的层级联系
+-BootstrapClassLoader
+-sun.misc.Launcher$ExtClassLoader@1959f618
+-com.taobao.arthas.agent.ArthasClassloader@5fc4Q @ P @ ! J 8 676c6
+-coE / u 5 am.taobao.arthas.agent.ArthasClassl^ B ; h a D $oader@5017e14b
+-sun.misc.Launcher$An ~ m OppClassLoader@5c647e05
+-java.net.FactoryURLClassLoader@4ad317f0
+-} ( X H 8 $ Eorg.springframewo& n Y Jrk.boot.loader.LaunchedURLClassLoader@20ad9418
Affect(row-cnt:7)costin5ms

线~ F (上代码热更新(动态修正上线项目代码)

手动在代码中抛反常,不停机不从头发包的情况下,修正线上代码
不停机还能替换代码?6年的 Java程序员表示不可思议
发动服务也达到咱们预期反常
不停机还能替换代码?6年的 Java程序员表示不可思议

替换代码的流程:

1、jad指令 将需要更改的文件先进行反编译,保存下来 ,编译器修正

$jad--source--onlyi  e L b _ Bcom.example.demo.DemoApplication>/data/DemoApplication.java
不停机还能替换代码?6年的 Java程序员表示不可思议
在这里刺进图片描绘

修正完以后需要将类从头加载到JVM

2、SC指令 查找当时类是哪个classLoader加载的

$sc-d*DemoApplication|grepclassLW [ - - v h c F %oader

classLoaderHash20ad9418#类加载器编号

3、MC指令 用指定的classlo` = Z K Q nag 9 g | Yder从头将类在内存中编译

$mc-c20ad9418/d: L ; + p d N Yata/DemoApplicatio3 V A ( 2 ? . on.0 p - ? . Tjava-d/datx T J B Ya
M3 0 ; Y d * u ^ kemoryc- r P gompileroutput:
/data/c@ { 9 5 U Y t som/exaK e z $ q 7 s Zmple] { w u //demo/DemoAppln X d O ? , X =ication.class

4、redefine指令 将编译后的类加载到JVM

上边编译后的.class文件地址

$redefine/dac E C N | J @ta/com/example/demo/DemoApp6 . v x % *lication.cl^ 0 P Xass
redefinesuccess,size:1

文件替换后咱们再次拜访一下程序,发现反常没有了程序已经是咱| ; e 2 B ] y们修正正确后的,class文件替换成功

不停机还能替换代码?6年的 Java程序员表示不可思议

总结

这样咱们就用arthas实际了不停机、不发包替换了生产环境的Java代码,功用的确比较强壮,本文只揭开了arthas强壮功用的冰山一角,后续将出更详细的文章,便利大家一同学习。

越懒越勤快

arthas的全体功用虽然很强壮,K Q I | #但指令行的输入办法让我头疼不已,岁数大了记忆力真的下降严重,而且作为一个贼 TM 懒的程序员,让我去记住如此多的指令和参` W f i g ( i l z数,简直是要了老命。又一次由于懒让我勤快起来,我决议做个arthas指令可E k p W视化渠道。

不停机还能替换代码?6年的 Java程序员表示不可思议

规划初衷:规划这个渠道的初衷很简单,便是让程序员们把更多的精力放在问题的排查上,而不是记那么多单调无趣的指令。自身我也不是一个乐意死记硬背的人,觉得脑子里还是应| F ~ u 9 s h Y _该多放一些风趣、有意义的东西。可能在用惯了指令行的大佬眼里,这个功用比较鸡肋,乃至有点多余,但究竟像我这样平凡的人更多一些,每天还陷入在重复的工作当中,工作量能减一点就多轻松一点嘛。

现在渠道还在持续的开发中,由于渠道是自己R @ ] a在维护,开发进度并不客观,平时使用一些碎片时刻开发,究竟不{ G B n l D & j能耽搁工作丢了饭碗嘛。不论会不会有人用,我都会一直做下去。

github地址 : https://github.com/chengxy-nds/arthas-web.git

感兴趣的小伙伴能够私信我,让咱们一同打造这个风趣的东西吧!