天天看点

本地jdk自带的jvisualvm工具通过jstatd服务监控远程java程序,分享jstatd启动脚本,简单快速启动jstad

jvisualvm分析java应用内存需要远程服务上启动jstatd服务(jmx也有内存监控信息,不过没有jstatd内存信息详细),网上各种相关文章大部分都是介绍的简单模糊,很多要注意的地方没介绍,真正按着操作的话,各种连不上没反应,让人着急!

下面分享个我在项目中分析内存时服务器上启动jstatd服务的脚本工具,自动安装jstatd环境,能够快速启动关闭jstatd服务。一些需要注意和容易出错的地方我也会下面指出。

我在服务器上安装的是openjdk1.8 ,所以jstatd.sh 脚本里面自动安装的jstatd工具也是1.8的,如果是别的版本自己看着改下。

下面进入正题

创建jstatd 脚本

jstatd脚本有2个文件: 启动脚本文件 jstatd.sh 和 权限配置文件 jstatd.all.policy

[[email protected] jstatd]# ll
total 8
-rwxr-xr-x 1 root root  107 Sep 28 16:03 jstatd.all.policy
-rwxr-xr-x 1 root root 1546 Sep 28 15:51 jstatd.sh
           
本地jdk自带的jvisualvm工具通过jstatd服务监控远程java程序,分享jstatd启动脚本,简单快速启动jstad
jstatd.all.policy

vi 编辑jstatd.all.policy 权限文件,内容如下:

grant codebase "file:${java.home}/../lib/tools.jar" {
   permission java.security.AllPermission;
};
           

保存退出

注意:如果没有这个文件,启动jstatd.sh时会报错:Could not create remote object ,具体如下:

Could not create remote object
access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")
java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
	at java.security.AccessController.checkPermission(AccessController.java:886)
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
	at java.lang.System.setProperty(System.java:792)
	at sun.tools.jstatd.Jstatd.main(Jstatd.java:139)
           
jstatd.sh

vi编辑 jstatd.sh 脚本文件内容如下: (注意,把 xxx.x.xxx.xxx 替换你们自己的服务器外网ip地址)

#!/bin/bash

CMD=$(basename $0)
OK="[ \e[32mOK\e[0m ]";
FAIL="[\e[31mfail\e[0m]";

# 属性
HOSTNAME="xxx.x.xxx.xxx";
PORT="1099";

# 运行环境
if [ -z `which jstatd 2>/dev/null` ] ; then
  echo -e "backgrounder : yum install -y java-1.8.0-openjdk-devel";
  yum install -y java-1.8.0-openjdk-devel >/dev/null && \
  echo -e "$OK yum java-1.8.0-openjdk-devel"
fi

help(){
echo -e "[\e[32m[-?|-help\e[0m]"
echo -e "    帮助"
echo -e "[\e[32m[-h host]\e[0m]"
echo -e "    host"
echo -e "[\e[32m[-p port]\e[0m]"
echo -e "    port"
echo -e "[\e[32m[start|stop]\e[0m]"
echo -e "    启动|停止"
}

# 获取参数
while getopts :h:p: opt;
do
  case $opt
  in
  h)HOSTNAME="$OPTARG";
  ;;
  p)PORT="$OPTARG";
  ;;
  ?)
    help;
    exit -1;
  ;;
  esac;
done;

kill_cmd(){
timeout=20
i=0
PID=$(pgrep jstatd|awk -v p=$$ 'p!=$1{print}')
if [[ `kill -0 $PID &>/dev/null;echo $?` = 0 ]] ;then
  kill -15 $PID &>/dev/null
  echo -n "stop  $CMD"
  while [[ `kill -0 $PID &>/dev/null;echo $?` = 0 ]] ; do
    if [ $i -ge $timeout ] ;then
      echo -e $FAIL
      return 0
    else
      echo -n "."
      sleep 1
      i=`expr $i + 1`
    fi
  done
  echo -e $OK
fi
return 0
}

start_cmd(){
  setsid jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=$HOSTNAME -p$PORT &
  echo "start $CMD"
  return 0
}

##############################################
case "$1" in
  'start')
    start_cmd
  ;;
  'stop')
    kill_cmd
  ;;
  'restart' | '')
    kill_cmd && start_cmd
  ;;
  '-?' | '-h' | '-help' | *)
    help
  ;;
esac
           

注意 权限问题,操作时最好切换到root用户权限 sudo su,然后记得给启动脚本执行权限 chmod 755 jstatd.sh

用脚本启动jstatd服务

确认拥有各种操作权限后,切换到 jstatd.sh 所在目录

1、启动jstatd 服务

./jstatd.sh

[[email protected] tools]# ./jstatd.sh 
backgrounder : yum install -y java-1.8.0-openjdk-devel
[ OK ] yum java-1.8.0-openjdk-devel
start jstatd.sh
[[email protected] tools]# 
           

如果没有安装过jstatd工具,第一次执行脚本 会提示在后台自动安装java-1.8.0-openjdk-devel

2、查看jstatd 的进程id

ps -aux | grep jstatd

[[email protected] tools]# ps -aux | grep jstatd
root     20537  0.5  1.1 2987296 43044 ?       Ssl  14:55   0:00 jstatd -J-Djava.security.policy=bin/jstatd.all.policy -J-Djava.rmi.server.hostname=xxx.x.xxx.xxx -p1099
root     20557  0.0  0.0 112708   980 pts/0    R+   14:58   0:00 grep --color=auto jstatd
           

查看到jstatd的进程id即 pid的值为 20537

3、通过jstatd的进程id查看jstatd服务绑定的端口

netstat -nap | grep [pid]

[[email protected] jstatd]# netstat -nap | grep 20537
tcp6       0      0 :::1099                 :::*                    LISTEN      20537/jstatd        
tcp6       0      0 :::43381                :::*                    LISTEN      20537/jstatd        
tcp6       0      0 192.168.1.58:1099       27.46.6.154:54788       ESTABLISHED 20537/jstatd        
tcp6       0      0 127.0.0.1:1099          127.0.0.1:43212         ESTABLISHED 20537/jstatd        
tcp6       0      1 192.168.1.58:51700      xxx.x.xxx.xxx:43381     SYN_SENT    20537/jstatd        
tcp6       0      0 127.0.0.1:43212         127.0.0.1:1099          ESTABLISHED 20537/jstatd        
unix  2      [ ]         STREAM     CONNECTED     29306374 20537/jstatd
           

注意: 前面2个监听端口,1099 是jstatd默认对外连接端口,第二个端口是每次启动jstatd 服务随机注册的端口(为什么随机,可能是出于安全考虑),这个2个tcp端口都需要开放端口权限,如果开了防火墙,需要在防火墙中开放这2端口个tcp权限,如果是云服务器,一般都会有安全组,需要在安全组中开放这2个端口的tcp权限,否则jstatd 远程无法连接!

前面2个监听端口下面出现的一些ESTABLISHED 连接信息 是jstatd 连接本机系统上所有jvm应用获取监控数据的信息,过一段时间后(几十秒吧,由本机上运行的java应用数决定),再次执行 netstat -nap | grep [pid] 会发现这些连接信息没有了,如下:

[[email protected] jstatd]# netstat -nap | grep 20537
tcp6       0      0 :::1099                 :::*                    LISTEN      20537/jstatd        
tcp6       0      0 :::43381                :::*                    LISTEN      20537/jstatd        
unix  2      [ ]         STREAM     CONNECTED     29306374 20537/jstatd         
[[email protected] jstatd]# 
           

这表示jstatd 服务启动准备好了

打开 jvisualvm 监控工具

本地windows打开 安装jdk时自带的监控工具 jvisualvm (在jdk安装目录下的bin下面去找 jvisualvm.exe)

本地jdk自带的jvisualvm工具通过jstatd服务监控远程java程序,分享jstatd启动脚本,简单快速启动jstad

jvisualvm 文件 -> 添加远程主机

本地jdk自带的jvisualvm工具通过jstatd服务监控远程java程序,分享jstatd启动脚本,简单快速启动jstad

右键 远程主机 -> 添加 jstatd 连接

本地jdk自带的jvisualvm工具通过jstatd服务监控远程java程序,分享jstatd启动脚本,简单快速启动jstad

就能看到 远程主机下面一列的jvm应用 点击其中想要监控的应用,右侧就可以看到jstatd监控信息了。

本地jdk自带的jvisualvm工具通过jstatd服务监控远程java程序,分享jstatd启动脚本,简单快速启动jstad

如果右侧 没有Visual GC 工具栏的话,需要手动添加 Visual GC插件,看下我写的这篇文章: jvisualvm 离线下载安装插件

jststd监控jvm应用内存分析问题 非常有用(可以分析jvm应用的新生代、老年代、永久代内存使用,分析如何优化内存参数,如:-XX:NewRatio),但是jmx监控信息有一些jststd 监控信息里面并没有的 ,我们可以在jvisualvm 连接 jvm应用 jmx监控,jvisualvm怎么连接jmx 可以看下我的这篇文章: 在本地windows用jConsole jmc jvisualvm监控图形客户端 连接远程服务器java程序jmx监控服务。解决jmx无法连接问题

关闭jstatd 服务

./jstatd.sh stop

[[email protected] tools]# ./jstatd.sh stop
stop  jstatd.sh.[ OK ]
           

最后

再次强调一些 需要注意的地方,一个地方出错可能就会导致最后连接不上,到处找不到原因。

jstatd.sh 脚本里面 xxx.x.xx.xxx 替换你们自己的服务器外网ip地址

启动 jstatd 和 jmx 服务 除了能指定的固定端口外 还会随机生成绑定端口,这些随机生成的绑定端口,如何找到 在上面有介绍,需要开放随机绑定的端口权限,否则就会连不上,并且没什么明显的提示。