天天看點

本地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 服務 除了能指定的固定端口外 還會随機生成綁定端口,這些随機生成的綁定端口,如何找到 在上面有介紹,需要開放随機綁定的端口權限,否則就會連不上,并且沒什麼明顯的提示。