TIPS
- 本文基于JDK 11编写,理论支持JDK 7及更高版本
- 此命令是实验性的,不受支持。
jstatd官方文档
- Java 8:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstatd.html
- Java 11:https://docs.oracle.com/en/java/javase/11/tools/jstatd.html
jstatd是一个基于RMI(Remove Method Invocation)的服务程序,它用于监控基于HotSpot的JVM中资源的创建及销毁,并且提供了一个远程接口,从而允许监控工具远程地连接到本地的JVM
一、配置安全策略
TIPS:远程服务器上执行
默认情况下,Java的安全策略比较严格,并不允许jstatd直接启动,因此,需要设置下安全策略。不同的JDK版本配置方式不同,主要是由于JDK 9开始,已经不再有tools.jar导致的。
创建安全策略文件,命名为:jstatd.all.policy,下面是各个版本的配置方式:
JDK 8及更低版本
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
当然也可使用绝对路径。
参考文档:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstatd.html
JDK 9及更高版本
grant codebase "jrt:/jdk.jstatd" {
permission java.security.AllPermission;
};
grant codebase "jrt:/jdk.internal.jvmstat" {
permission java.security.AllPermission;
};
参考文档:
- https://docs.oracle.com/en/java/javase/11/security/permissions-jdk1.html
获得codebase名称的方法及配置:可参考https://stackoverflow.com/questions/51032095/starting-jstatd-in-java-9
二、启动jstatd
TIPS
远程服务器上执行
- 执行jstatd命令的用户和你jstatd想连接的应用必须拥有相同的用户凭证
在jstatd.all.policy所在目录,执行如下命令:
jstatd -J-Djava.security.policy=./jstatd.all.policy \n -J-Djava.rmi.server.hostname=www.itmuch.com \n -J-Djava.rmi.server.logCalls=true \n -p 1231
其中:
- java.security.policy:指定上面策略文件的路径,使用相对路径或绝对路径均可
- java.rmi.server.hostname:指定成允许连接的IP地址、主机名或域名
- java.rmi.server.logCalls:打印日志
- -p:用来指定注册端口,默认1099
三、防火墙设置
TIPS:远程服务器上执行
由于jstat使用了RMI,而RMI尽管可指定注册端口,但通信端口是却是rmi server随机生成的——这意味着,每次启动jstatd,使用的端口都不一样。如果能够接受关闭防火墙带来的风险,也可直接关闭掉防火墙。
如果不想关闭防火墙(systemctl stop firewalld.service),可按照如下步骤,配置防火墙规则即可: ```shell1. 使用如下命令,获得jstatd监听的端口
➜ netstat -antp | grep jstatd tcp6 0 0 :::1231 ::: LISTEN 13546/jstatd
tcp6 0 0 :::43201 ::: LISTEN 13546/jstatd
2. 开放1231(取决于启动jstatd的-p参数)、43201端口(随机,依赖于netstat -antp | grep jstatd的结果)
➜ firewall-cmd —zone=public —add-port=1231/tcp —permanent ➜ firewall-cmd —zone=public —add-port=43201/tcp —permanent
3. 重载防火墙规则
➜ firewall-cmd —reload
4. 查看当前开放的端口,确认端口已成功开放
➜ firewall-cmd —zone=public —list-ports
另外,也可参考《 [rmi穿越防火墙](https://www.iteye.com/blog/wangse-191797) 》的描述,自己编写代码,实现穿透防火墙。大致思路是自定义一个RMISocketFactory并指定固定的通信端口,然后人工设置一个固定的端口(比如2098),再为防火墙配置开放该端口即可。不过这种方式需要侵入源码,个人并不建议使用。
<a name="CReUf"></a>
## 四、本地机器配置连接远程服务器
<a name="iLHc7"></a>
### VisualVM
![](https://cdn.nlark.com/yuque/0/2022/png/1602593/1653638856252-e2204fd8-f3da-4f32-952b-c8de8059f60a.png#clientId=ua22e84a0-9ed5-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u216bad96&margin=%5Bobject%20Object%5D&originHeight=754&originWidth=1172&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u4417d8fc-3f1c-4e51-b53d-447aee21c35&title=)
<a name="P2UGC"></a>
### jps
```shell
jps rmi://www.itmuch.com:1231