shell脚本监控SpringBoot服务健康状态并重启
创始人
2024-04-07 23:50:06
0

问题

  • 综合客户反馈的现场情况,服务前一天可以使用正常,第二天早晨发现报错; 初步怀疑是晚上什么操作导致的,大概是定时任务
  • 查看服务日志,综合几天日志,发现每晚都会执行一个日志清除的定时任务scheduledtask.CleanLogJob
{"log":"\u001b[2m2022-10-30 00:00:00.001\u001b[0;39m \u001b[32m INFO\u001b[0;39m \u001b[35m1\u001b[0;39m \u001b[2m---\u001b[0;39m \u001b[2m[ne-scheduling-1]\u001b[0;39m \u001b[36mc.newatc.api.scheduledtask.CleanLogJob  \u001b[0;39m \u001b[2m:\u001b[0;39m ----开启定时清理日志文件----2022-10-29T16:00:00.001343Z\n","stream":"stdout","time":"2022-10-29T16:00:00.002200283Z"}
{"log":"\n","stream":"stderr","time":"2022-10-29T16:00:32.158196254Z"}
{"log":"Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread \"Hikari housekeeper\"\n","stream":"stderr","time":"2022-10-29T16:00:32.158216755Z"}
{"log":"\u001b[2m2022-10-30 00:01:22.799\u001b[0;39m \u001b[31mERROR\u001b[0;39m \u001b[35m1\u001b[0;39m \u001b[2m---\u001b[0;39m \u001b[2m[ne-scheduling-1]\u001b[0;39m \u001b[36mo.s.s.s.TaskUtils$LoggingErrorHandler   \u001b[0;39m \u001b[2m:\u001b[0;39m Unexpected error occurred in scheduled task\n","stream":"stdout","time":"2022-10-29T16:01:22.800399506Z"}
{"log":"\n","stream":"stdout","time":"2022-10-29T16:01:22.800414807Z"}
{"log":"java.lang.OutOfMemoryError: Java heap space\n","stream":"stdout","time":"2022-10-29T16:01:22.800417418Z"}
{"log":"\n","stream":"stdout","time":"2022-10-29T16:01:22.800419609Z"}
  • 定时任代码是先根据当前日期查询7天前的所有数据,再全部删除。当某一天数据量特别大,无法全部加载到内存时,就会内存溢出,程序就会假死
/*** 每天零点定时清理日志*/@Scheduled(cron = "0 0 0 * * ?")public void deleteLog(){log.info("----开启定时清理日志文件----{}", Instant.now());try{SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Calendar c = Calendar.getInstance();//过去七天c.setTime(new Date());c.add(Calendar.DATE, -7);String day = format.format(c.getTime());List opLogList = findOpLogByDayNum(day);opLogRepository.deleteAll(opLogList);List signalAlarmList = findSignalAlarmByDayNum(day);signalAlarmRepository.deleteAll(signalAlarmList);}catch (Exception e){log.error("deleteLog error..", e);}}
  • 定时任务执行后,内存溢出java.lang.OutOfMemoryError: Java heap space。查看服务的jvm配置,只分配了 512M 内存,对于大量数据读入内存,确实不够用
  • 查看代码提交记录,综合更新部署时间和问题出现时间,基本确定是此问题
  • 让运维人员协助查询了数据库,发现每天新增10万条信号机报警日志,仍有13天(100多万条)的数据存在,确实是删除日志时内存溢出失败

分析

  • 数据量问题确实是到客户现场,有实际这么多设备和用户才暴露出来的,公司测试无法进行此种场景的压力测试,只能把这款产品的第一个用户作为小白鼠了
  • SpringBoot服务因异常宕机或假死时,不再提供服务,会从注册中心掉线,并且整个应用就不可用了
  • 如果只是某些菜单功能不可用,对于客户来说还可以接受,毕竟试运行阶段,有点小问题客户也能理解
  • 如果是整个服务宕机,界面打不开,客户就会对系统的稳定性产生怀疑,印象会不太好
  • 或者说,某些导致宕机的问题,如果及时处理了,客户就暂时发现不了这个问题,就能减少对客户的负面印象

处理

  • 针对于此,写了个shell脚本,监控SpringBoot服务暴露的端点,服务不可用时,进行重启操作
  • 为了防止网络波动造成的影响,重试三次请求,都得不到健康的结果,才认为不可用
  • 具体脚本如下:
#!/bin/bash# 检查服务是否可用,判断服务状态
function checkHealth() {currTime=`date +"%Y-%m-%d %H:%M:%S"`echo "$currTime $@"; # 以列表的方式一次性打印所有的参数ConsulResult=$(curl -s --connect-timeout 500 --max-time 2  http://$1/actuator/health )target="UP"local health=1if [[ $ConsulResult =~ $target ]]thenecho "$2结果健康";elsesleep 1s;ConsulResult=$(curl -s --connect-timeout 500 --max-time 2  http://$1/actuator/health )if [[ $ConsulResult =~ $target ]]thenecho "$2结果健康";elsesleep 1s;ConsulResult=$(curl -s --connect-timeout 500 --max-time 2  http://$1/actuator/health )if [[ $ConsulResult =~ $target ]]thenecho "$2结果健康";elsehealth=0;echo "$2 结果不健康";fififireturn $health;
}# 检查服务健康状态,并处理异常
function dealCheckResult() {ipport=$1name=$2echo "start $name ======================="checkHealth $ipport $namehealth=$?if [[ $health -eq 1 ]]thenecho "$name 检查完毕,无问题!"elseecho "重启 $name 预计2分钟"# 重启服务docker stop $namesleep 5sdocker start $namesleep 120s# 重新检查一次是否启动成功,不成功则再休眠60scheckHealth $ipport $namehealth=$?currTime=`date +"%Y-%m-%d %H:%M:%S"`if [[ $health -eq 1 ]];thenecho "$currTime $name 服务已重启完成"elseecho "$currTime $name 服务尚未重启完成,再休眠60s等待"sleep 60sfifiecho "end $name 所有处理完毕==========="
}# 获取系统启动时间
uptime=$(cat /proc/uptime)
echo "uptime: $uptime"
uptimeArr=(${uptime//./ })
startTime=${uptimeArr[0]}
echo $startTime
a=`expr $startTime + 1`
b=1800
# 系统启动30分钟内不执行
if [[ "$a" -lt "$b" ]];
thenecho "系统启动30分钟内不执行"exit
fi
echo "启动时间为$startTime秒,正常执行脚本"echo "先关闭定时任务"
/sbin/service crond stopipport1=172.16.1.122:8181
name1=datacenter
dealCheckResult $ipport1 $name1ipport2=172.16.1.122:8282
name2=unit
dealCheckResult $ipport2 $name2ipport3=172.16.1.122:8383
name3=core
dealCheckResult $ipport3 $name3echo "重新启动定时任务"
/sbin/service crond start

相关内容

热门资讯

中证A500ETF摩根(560... 8月22日,截止午间收盘,中证A500ETF摩根(560530)涨1.19%,报1.106元,成交额...
A500ETF易方达(1593... 8月22日,截止午间收盘,A500ETF易方达(159361)涨1.28%,报1.104元,成交额1...
何小鹏斥资约2.5亿港元增持小... 每经记者|孙磊    每经编辑|裴健如 8月21日晚间,小鹏汽车发布公告称,公司联...
中证500ETF基金(1593... 8月22日,截止午间收盘,中证500ETF基金(159337)涨0.94%,报1.509元,成交额2...
中证A500ETF华安(159... 8月22日,截止午间收盘,中证A500ETF华安(159359)涨1.15%,报1.139元,成交额...
科创AIETF(588790)... 8月22日,截止午间收盘,科创AIETF(588790)涨4.83%,报0.760元,成交额6.98...
创业板50ETF嘉实(1593... 8月22日,截止午间收盘,创业板50ETF嘉实(159373)涨2.61%,报1.296元,成交额1...
港股异动丨航空股大幅走低 中国... 港股航空股大幅下跌,其中,中国国航跌近7%表现最弱,中国东方航空跌近5%,中国南方航空跌超3%,美兰...
电网设备ETF(159326)... 8月22日,截止午间收盘,电网设备ETF(159326)跌0.25%,报1.198元,成交额409....
红利ETF国企(530880)... 8月22日,截止午间收盘,红利ETF国企(530880)跌0.67%,报1.034元,成交额29.0...