使用Monit监控Java进程:实现故障自恢复与JVM内存溢出自动处理

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

        最近在搞一个Java服务的运维,发现服务偶尔会挂掉,手动重启太麻烦了,于是研究了一下 Monit,发现这玩意儿真是神器!今天就来分享一下怎么用Monit监控Java进程,实现故障自动恢复,顺便还能处理JVM内存溢出的问题。

Monit是啥?

        简单来说,Monit就是一个轻量级的监控工具,能帮你盯着系统里的进程、文件、目录啥的。如果发现哪个服务挂了,它能自动帮你重启,甚至还能发邮件告警。对于我们这些搞运维的来说,简直是省心利器!

我要干啥?

        这次的目标很简单:

  1. 监控Java进程:确保服务挂了能自动重启。

  2. 处理JVM内存溢出:内存爆了的时候,自动杀掉进程,顺便生成Heap Dump文件,方便后续分析。

  3. 配置Monit:让Monit帮我盯着多个Java服务,省得我天天手动检查。

具体怎么搞?

1. 先写个停止脚本 stop.sh

        首先,得有个脚本来停止Java进程。这个脚本的作用很简单:找到进程,杀掉它,顺便清理一下PID文件。

#!/bin/sh 
APP_NAME="app_name"  # 这里改成你的应用名
SERVICE_DIR="/home/appuser/app/$APP_NAME" 
PID=$APP_NAME\.pid 

# 先尝试正常停止
kill `cat $SERVICE_DIR/$PID` 
rm -rf $SERVICE_DIR/$PID 
echo "=== stop $APP_NAME" 
sleep 5 

# 如果还没停掉,就强制杀死
P_ID=`ps -ef | grep -w "$APP_NAME" | grep -v "grep" | awk '{print $2}'` 
if [ "$P_ID" == "" ]; then 
  echo "=== $APP_NAME 进程已经停止了" 
else 
  echo "=== $APP_NAME 进程还在,PID是: $P_ID" 
  echo "=== 开始强制杀死进程..." 
  kill -9 $P_ID 
fi

        注意:记得把 APP_NAME 和 SERVICE_DIR 改成你实际的值,然后给脚本加个执行权限:

chmod +x stop.sh

2. 改一下启动脚本 run.sh

        接下来,得让Java进程在内存溢出的时候自动调用上面的 stop.sh。修改启动脚本,加上一些JVM参数:

JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/appuser/logs/jvmlogs_`date +%Y-%m-%d-%N` -XX:ErrorFile=/home/appuser/logs/jvmlogs_`date +%Y-%m-%d-%N`/hs_error.log -XX:OnOutOfMemoryError=\"/home/appuser/app/stop.sh\""

解释一下

  • -XX:+HeapDumpOnOutOfMemoryError:内存溢出时生成Heap Dump文件。

  • -XX:HeapDumpPath:指定Heap Dump文件的存放路径。

  • -XX:OnOutOfMemoryError:内存溢出时执行 stop.sh,杀掉进程。

完整的启动脚本示例

JAVA_OPTS='-Xms1024m -Xmx1024m -XX:MetaspaceSize=128m'

JAVA_OPTS="$JAVA_OPTS -Ddisconf.conf=/data/config/disconf.properties"

JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/appuser/logs/jvmlogs_`date +%Y-%m-%d-%N` -XX:ErrorFile=/home/appuser/logs/jvmlogs_`date +%Y-%m-%d-%N`/hs_error.log -XX:OnOutOfMemoryError=\"/data/app/ems-fec-ds/stop.sh\""
JAVA_OPTS="$JAVA_OPTS -Dpinpoint.applicationName=online-ems-fec-ds"

#JAVA_OPTS="$JAVA_OPTS -Dio.netty.leakDetectionLevel=advanced"

#JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=172.16.168.103 -Dcom.sun.management.jmxremote.port=18888 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.managementote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"

#JAVA_OPTS="$JAVA_OPTS -XX:+DisableExplicitGC"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintGCApplicationStoppedTime -Xloggc:gc.log"

#!/bin/sh

## java env
export JAVA_HOME=/data/app/jdk1.8.0_191
export JRE_HOME=$JAVA_HOME/jre

APP_NAME=water-ds

SERVICE_DIR=/data/app/ems-fec-ds
JAR_NAME=$APP_NAME\.jar
PID=$APP_NAME\.pid

cd $SERVICE_DIR
#mv  $JAR_NAME $JAR_NAME.$(date +%Y%m%d)
#rm -f $JAR_NAME
#cp /home/appuser/target/$JAR_NAME .

case "$1" in
    deploy)
        $0 stop
        sleep 2
        echo "=== deploy $APP_NAME"
        cd $SERVICE_DIR
        cp  $JAR_NAME $JAR_NAME.$(date +%Y%m%d)
        rm -f $JAR_NAME
        cp /home/appuser/target/$JAR_NAME .
        $0 start
        ;;

    start)
        #nohup java $JAVA_OPTS -jar $JAR_NAME >$APP_NAME\.out 2>&1 &
        nohup java $JAVA_OPTS -jar $JAR_NAME >/dev/null 2>&1 &
        echo $! > $SERVICE_DIR/$PID
        echo "=== start $APP_NAME"
        ;;

    stop)
        kill `cat $SERVICE_DIR/$PID`
        rm -rf $SERVICE_DIR/$PID
        echo "=== stop $APP_NAME"

        sleep 5
        P_ID=`ps -ef | grep -w "$APP_NAME" | grep -v "grep" | awk '{print $2}'`
        if [ "$P_ID" == "" ]; then
            echo "=== $APP_NAME process not exists or stop success"
        else
            echo "=== $APP_NAME process pid is:$P_ID"
            echo "=== begin kill $APP_NAME process, pid is:$P_ID"
            kill -9 $P_ID
        fi
        ;;

    restart)
        $0 stop
        sleep 2
        $0 start
        echo "=== restart $APP_NAME"
        ;;

    *)
        ## restart
        $0 stop
        sleep 2
        $0 start
        ;;
esac
exit 0

3. 安装和配置Monit

3.1 安装Monit

        如果你的系统还没装Monit,可以用以下命令安装:

#!/bin/sh
DIR=/home/appuser/monit
sudo yum install monit -y
if [ ! -d $DIR ]
        then
                mkdir  -p $DIR
                sudo cp /etc/monitrc  $DIR/  && sudo cp -r /etc/monit.d  $DIR/
                sudo chown -R appuser:appuser $DIR
                sed -i "s#/var/log#"$DIR"#" /$DIR/monit.d/logging
                sed -i "s#include /etc#include "$DIR"#" /$DIR/monitrc
        else
                echo ""$DIR" is  already  exists!"
fi
3.2 配置Monit日志

        Monit的日志很重要,出了问题可以查。我们指定一下日志文件的位置:

[appuser@daqin monit]$ cat monit.d/logging 
# log to monit.log 
set logfile /data/appuser/monit/m.log
3.3 配置Monit监控规则

        接下来就是重头戏了,配置Monit来监控Java进程。比如我们有多个Java服务,可以这样写:

# 监控 charging-open 服务
check process iot-open with pidfile /data/app/iot-open/iot-open.pid  every 11 cycles
        start program = "/bin/bash -c '/data/app/iot-open/run.sh start'" with timeout 30 seconds
        stop program = "/bin/bash -c '/data/app/iot-open/run.sh stop'"
        if failed port 7171 type tcp for 11 cycles then restart
        if changed pid then alert

# 监控 ems-share-api 服务
check process iot-share-api with pidfile /data/app/iot-share-api/ems-share.pid  every 2 cycles
        start program = "/bin/bash -c '/data/app/iot-share-api/run.sh start'" with timeout 80 seconds
        stop program = "/bin/bash -c '/data/app/iot-share-api/run.sh stop'"
        if changed pid then alert

# 其他服务类似...

说明

  • 每个 check process 块对应一个服务的监控规则。

  • start program 和 stop program 分别是启动和停止脚本。

  • if failed port 是检测端口是否可用,如果失败了就重启服务。

4. 重新加载Monit配置

        配置写好了,别忘了让Monit重新加载一下:

#测试配置文件是否正确
monit -c  /data/appuser/monit/monitrc  -t
 
#启动
monit -c  /data/appuser/monit/monitrc
 
#退出
monit -c  /data/appuser/monit/monitrc quit
 
#重新加载配置
monit -c  /data/appuser/monit/monitrc reload

        然后Monit就会开始监控你的服务了。如果某个服务挂了,它会自动帮你重启,省得你手动操作。

总结

        用了Monit之后,感觉整个人都轻松了不少。Java服务挂了?Monit帮你重启!内存溢出了?Monit帮你杀掉进程,还能生成Heap Dump文件!简直是运维小能手。

如果你也在为Java服务的稳定性发愁,不妨试试Monit,真的香!有啥问题或者更好的建议,欢迎留言讨论

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值