This repository has been archived by the owner on Jun 26, 2022. It is now read-only.
forked from alibaba/arthas
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add mc-redefine command scenario. alibaba#847
Signed-off-by: hollowman6 <hollowman186@vip.qq.com>
- Loading branch information
1 parent
c0b3272
commit 1172ab6
Showing
20 changed files
with
491 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
|
||
|
||
|
||
在新的`Terminal 2`里,下载`arthas-boot.jar`,再用`java -jar`命令启动: | ||
|
||
`wget https://alibaba.github.io/arthas/arthas-boot.jar | ||
java -jar arthas-boot.jar`{{execute T2}} | ||
|
||
`arthas-boot`是`Arthas`的启动程序,它启动后,会列出所有的Java进程,用户可以选择需要诊断的目标进程。 | ||
|
||
选择第一个进程,输入 `1`{{execute T2}} ,再`Enter/回车`: | ||
|
||
Attach成功之后,会打印Arthas LOGO。输入 `help`{{execute T2}} 可以获取到更多的帮助信息。 | ||
|
||
![Arthas Boot](/arthas/scenarios/common-resources/assets/arthas-boot.png) |
85 changes: 85 additions & 0 deletions
85
tutorials/katacoda/command-mc-redefine-cn/case-jad-mc-redefine.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
下面介绍通过`jad`/`mc`/`redefine` 命令实现动态更新代码的功能。 | ||
|
||
目前,访问 http://localhost/user/0 ,会返回500异常: | ||
|
||
`curl http://localhost/user/0`{{execute T3}} | ||
|
||
``` | ||
{"timestamp":1550223186170,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"} | ||
``` | ||
|
||
下面通过热更新代码,修改这个逻辑。 | ||
|
||
### jad反编译UserController | ||
|
||
`jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java`{{execute T2}} | ||
|
||
jad反编译的结果保存在 `/tmp/UserController.java`文件里了。 | ||
|
||
再打开一个`Terminal 3`,然后用vim来编辑`/tmp/UserController.java`: | ||
|
||
`vim /tmp/UserController.java`{{execute T3}} | ||
|
||
比如当 user id 小于1时,也正常返回,不抛出异常: | ||
|
||
```java | ||
@GetMapping(value={"/user/{id}"}) | ||
public User findUserById(@PathVariable Integer id) { | ||
logger.info("id: {}", (Object)id); | ||
if (id != null && id < 1) { | ||
return new User(id, "name" + id); | ||
// throw new IllegalArgumentException("id < 1"); | ||
} | ||
return new User(id.intValue(), "name" + id); | ||
} | ||
``` | ||
|
||
### sc查找加载UserController的ClassLoader | ||
|
||
`sc -d *UserController | grep classLoaderHash`{{execute T2}} | ||
|
||
```bash | ||
$ sc -d *UserController | grep classLoaderHash | ||
classLoaderHash 1be6f5c3 | ||
``` | ||
|
||
可以发现是 spring boot `LaunchedURLClassLoader@1be6f5c3` 加载的。 | ||
|
||
请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`。 | ||
|
||
注意:请使用你的classLoaderHash值覆盖 `<classLoaderHash>` ,然后手动执行下面所有所述命令: | ||
|
||
### mc | ||
|
||
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader: | ||
|
||
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp` | ||
|
||
```bash | ||
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp | ||
Memory compiler output: | ||
/tmp/com/example/demo/arthas/user/UserController.class | ||
Affect(row-cnt:1) cost in 346 ms | ||
``` | ||
|
||
### redefine | ||
|
||
再使用`redefine`命令重新加载新编译好的`UserController.class`: | ||
|
||
`redefine /tmp/com/example/demo/arthas/user/UserController.class`{{execute T2}} | ||
|
||
``` | ||
$ redefine /tmp/com/example/demo/arthas/user/UserController.class | ||
redefine success, size: 1 | ||
``` | ||
|
||
### 热修改代码结果 | ||
|
||
`redefine`成功之后,再次访问 https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com/user/0 ,结果是: | ||
|
||
``` | ||
{ | ||
"id": 0, | ||
"name": "name0" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
|
||
在“mc-redefine”中,我们演示了了Arthas的mc-redefine命令。如果有更多的技巧或者使用疑问,欢迎在Issue里提出。 | ||
|
||
* Issues: https://github.com/alibaba/arthas/issues | ||
* 文档: https://alibaba.github.io/arthas | ||
|
||
|
||
如果您在使用Arthas,请让我们知道,您的使用对我们非常重要:[查看](https://github.com/alibaba/arthas/issues/111) | ||
|
||
欢迎关注公众号,获取Arthas项目的信息,源码分析,案例实践。 | ||
|
||
![Arthas公众号](/arthas/scenarios/common-resources/assets/qrcode_gongzhonghao.jpg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
{ | ||
"title": "Arthas mc-redefine命令", | ||
"description": "Arthas mc-redefine命令", | ||
"difficulty": "精通者", | ||
"time": "10-20 分钟", | ||
"details": { | ||
"steps": [ | ||
{ | ||
"title": "启动demo", | ||
"text": "start-demo.md" | ||
}, | ||
{ | ||
"title": "启动arthas-boot", | ||
"text": "arthas-boot.md" | ||
}, | ||
{ | ||
"title": "mc命令", | ||
"text": "mc.md" | ||
}, | ||
{ | ||
"title": "redefine命令", | ||
"text": "redefine.md" | ||
}, | ||
{ | ||
"title": "热更新代码", | ||
"text": "case-jad-mc-redefine.md" | ||
} | ||
], | ||
"intro": { | ||
"text": "intro.md" | ||
}, | ||
"finish": { | ||
"text": "finish.md" | ||
}, | ||
"assets": { | ||
"host01": [] | ||
} | ||
}, | ||
"environment": { | ||
"uilayout": "terminal", | ||
"showdashboard": true, | ||
"dashboards": [ | ||
{ | ||
"name": "Web Port 80", | ||
"port": 80 | ||
} | ||
] | ||
}, | ||
"backend": { | ||
"imageid": "java", | ||
"environmentsprotocol": "http" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
|
||
|
||
|
||
![Arthas](https://alibaba.github.io/arthas/_images/arthas.png) | ||
|
||
`Arthas` 是Alibaba开源的Java诊断工具,深受开发者喜爱。在线排查问题,无需重启;动态跟踪Java代码;实时监控JVM状态。 | ||
|
||
`Arthas` 支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 `Tab` 自动补全功能,进一步方便进行问题的定位和诊断。 | ||
|
||
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: | ||
|
||
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? | ||
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了? | ||
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗? | ||
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现! | ||
- 是否有一个全局视角来查看系统的运行状况? | ||
- 有什么办法可以监控到JVM的实时运行状态? | ||
- 怎么快速定位应用的热点,生成火焰图? | ||
|
||
本教程会以一个普通的Spring Boot应用为例,演示mc-redefine命令。 | ||
|
||
* Github: https://github.com/alibaba/arthas | ||
* 文档: https://alibaba.github.io/arthas/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
|
||
> Memory Compiler/内存编译器,编译`.java`文件生成`.class`。 | ||
|
||
可以通过`-c`参数指定classloader,`-d`参数指定输出目录 | ||
|
||
编译生成`.class`文件之后,可以结合`redefine`命令实现热更新代码。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
|
||
> 加载外部的`.class`文件,redefine jvm已加载的类。 | ||
参考:[Instrumentation#redefineClasses](https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html#redefineClasses-java.lang.instrument.ClassDefinition...-) | ||
|
||
> 注意, redefine后的原来的类不能恢复,redefine有可能失败(比如增加了新的field),参考jdk本身的文档。 | ||
> `reset`命令对`redefine`的类无效。如果想重置,需要`redefine`原始的字节码。 | ||
> `redefine`命令和`jad`/`watch`/`trace`/`monitor`/`tt`等命令会冲突。执行完`redefine`之后,如果再执行上面提到的命令,则会把`redefine`的字节码重置。 | ||
> 原因是jdk本身redefine和Retransform是不同的机制,同时使用两种机制来更新字节码,只有最后修改的会生效。 | ||
### 参数说明 | ||
|
||
|参数名称|参数说明| | ||
|---:|:---| | ||
|[c:]|ClassLoader的hashcode| | ||
|[p:]|外部的`.class`文件的完整路径,支持多个| | ||
|
||
|
||
### redefine的限制 | ||
|
||
* 不允许新增加field/method | ||
* 正在跑的函数,没有退出不能生效。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
|
||
|
||
|
||
下载`demo-arthas-spring-boot.jar`,再用`java -jar`命令启动: | ||
|
||
`wget https://github.com/hengyunabc/spring-boot-inside/raw/master/demo-arthas-spring-boot/demo-arthas-spring-boot.jar | ||
java -jar demo-arthas-spring-boot.jar`{{execute T1}} | ||
|
||
`demo-arthas-spring-boot`是一个很简单的spring boot应用,源代码:[查看](https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-arthas-spring-boot) | ||
|
||
启动之后,可以访问80端口: https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com | ||
|
||
![Demo Web](/arthas/scenarios/common-resources/assets/demo-web.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
|
||
|
||
|
||
In the new `Terminal 2`, download `arthas-boot.jar` and start with the `java -jar` command: | ||
|
||
`wget https://alibaba.github.io/arthas/arthas-boot.jar | ||
java -jar arthas-boot.jar`{{execute T2}} | ||
|
||
`arthas-boot` is the launcher for `Arthas`. It lists all the Java processes, and the user can select the target process to be diagnosed. | ||
|
||
Select the first process, type `1`{{execute T2}} ,then type `Enter`: | ||
|
||
After the Attach is successful, Arthas LOGO is printed. Enter `help`{{execute T2}} for more help. | ||
|
||
![Arthas Boot](/arthas/scenarios/common-resources/assets/arthas-boot.png) |
88 changes: 88 additions & 0 deletions
88
tutorials/katacoda/command-mc-redefine-en/case-jad-mc-redefine.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
This case introduces the ability to dynamically update code via the `jad`/`mc`/`redefine` command. | ||
|
||
Currently, visiting http://localhost/user/0 will return a 500 error: | ||
|
||
`curl http://localhost/user/0`{{execute T3}} | ||
|
||
``` | ||
{"timestamp":1550223186170,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"} | ||
``` | ||
|
||
This logic will be modified by `redefine` command below. | ||
|
||
### Use jad command to decompile UserController | ||
|
||
`jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java`{{execute T2}} | ||
|
||
The result of jad command will be saved in the `/tmp/UserController.java` file. | ||
|
||
|
||
Then open `Terminal 3`, use `vim` to edit `/tmp/UserController.java`: | ||
|
||
`vim /tmp/UserController.java`{{execute T3}} | ||
|
||
For example, when the user id is less than 1, it also returns normally without throwing an exception: | ||
|
||
```java | ||
@GetMapping(value={"/user/{id}"}) | ||
public User findUserById(@PathVariable Integer id) { | ||
logger.info("id: {}", (Object)id); | ||
if (id != null && id < 1) { | ||
return new User(id, "name" + id); | ||
// throw new IllegalArgumentException("id < 1"); | ||
} | ||
return new User(id.intValue(), "name" + id); | ||
} | ||
``` | ||
|
||
### Use sc command to find the ClassLoader that loads the UserController | ||
|
||
`sc -d *UserController | grep classLoaderHash`{{execute T2}} | ||
|
||
```bash | ||
$ sc -d *UserController | grep classLoaderHash | ||
classLoaderHash 1be6f5c3 | ||
``` | ||
|
||
It can be found that it is loaded by spring boot `LaunchedURLClassLoader@1be6f5c3`. | ||
|
||
Please write down your classLoaderHash here, in the case here, it's `1be6f5c3`. It will be used in the future steps. | ||
|
||
Note: Please replace `<classLoaderHash>` with your classLoaderHash above, then execute the commands manually in the following steps: | ||
|
||
### mc | ||
|
||
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `-c` option: | ||
|
||
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp` | ||
|
||
```bash | ||
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp | ||
Memory compiler output: | ||
/tmp/com/example/demo/arthas/user/UserController.class | ||
Affect(row-cnt:1) cost in 346 ms | ||
``` | ||
|
||
### redefine | ||
|
||
Then reload the newly compiled `UserController.class` with the `redefine` command: | ||
|
||
`redefine /tmp/com/example/demo/arthas/user/UserController.class`{{execute T2}} | ||
|
||
``` | ||
$ redefine /tmp/com/example/demo/arthas/user/UserController.class | ||
redefine success, size: 1 | ||
``` | ||
|
||
### Check the results of the hotswap code | ||
|
||
After the `redefine` command is executed successfully, visit https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com/user/0 again. | ||
|
||
The result is: | ||
|
||
``` | ||
{ | ||
"id": 0, | ||
"name": "name0" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
|
||
The `mc-redefine Tutorial` demonstrates the usage of mc-redefine. If you have more tips or questions, please feel free to ask in Issue. | ||
|
||
* Issues: https://github.com/alibaba/arthas/issues | ||
* Documentation: https://alibaba.github.io/arthas | ||
|
||
|
||
If you are using Arthas, please let us know. Your use is very important to us: [View](https://github.com/alibaba/arthas/issues/111) |
Oops, something went wrong.