使用 Monit 监控 Java 进程:实现故障自恢复与 JVM 内存溢出自动处理
使用 Monit 监控 Java 进程:实现故障自恢复与 JVM 内存溢出自动处理
最近在搞一个 Java 服务的运维,发现服务偶尔会挂掉,手动重启太麻烦了,于是研究了一下 Monit,发现这玩意儿真是神器!今天就来分享一下怎么用 Monit 监控 Java 进程,实现故障自动恢复,顺便还能处理 JVM 内存溢出的问题。
Monit 是什么?
简单来说,Monit 就是一个轻量级的监控工具,能帮你盯着系统里的进程、文件、目录啥的。如果发现哪个服务挂了,它能自动帮你重启,甚至还能发邮件告警。对于我们这些搞运维的来说,简直是省心利器!
本次目标
- 监控 Java 进程:确保服务挂了能自动重启。
- 处理 JVM 内存溢出:内存爆了的时候,自动杀掉进程,顺便生成 Heap Dump 文件,方便后续分析。
- 配置 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/your-app/stop.sh\""
JAVA_OPTS="$JAVA_OPTS -Dpinpoint.applicationName=your-app-name"
#!/bin/sh
## java env
export JAVA_HOME=/data/app/jdk1.8.0_191
export JRE_HOME=$JAVA_HOME/jre
APP_NAME=your-app
SERVICE_DIR=/data/app/your-app
JAR_NAME=$APP_NAME\.jar
PID=$APP_NAME\.pid
cd $SERVICE_DIR
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 >/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"
;;
*)
$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 的日志很重要,出了问题可以查。我们指定一下日志文件的位置:
# cat monit.d/logging
# log to monit.log
set logfile /data/appuser/monit/m.log
3.3 配置 Monit 监控规则
接下来就是重头戏了,配置 Monit 来监控 Java 进程。比如我们有多个 Java 服务,可以这样写:
# 监控 iot-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
# 监控 iot-share-api 服务
check process iot-share-api with pidfile /data/app/iot-share-api/iot-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,真的香!有啥问题或者更好的建议,欢迎留言讨论。
转载声明
本文转载自 CSDN 博主 road4918 的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。