-
综合客户反馈的现场情况,服务前一天可以使用正常,第二天早晨发现报错; 初步怀疑是晚上什么操作导致的,大概是定时任务
-
查看服务日志,综合几天日志,发现每晚都会执行一个日志清除的定时任务
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());
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<OpLog> opLogList = findOpLogByDayNum(day);
opLogRepository.deleteAll(opLogList);
List<SignalAlarm> 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=1
if [[ $ConsulResult =~ $target ]]
echo "$2结果健康";
sleep 1s;
ConsulResult=$(curl -s --connect-timeout 500 --max-time 2 http://$1/actuator/health )
if [[ $ConsulResult =~ $target ]]
echo "$2结果健康";
sleep 1s;
ConsulResult=$(curl -s --connect-timeout 500 --max-time 2 http://$1/actuator/health )
if [[ $ConsulResult =~ $target ]]
echo "$2结果健康";
health=0;
echo "$2 结果不健康";
return $health;
function dealCheckResult() {
ipport=$1
name=$2
echo "start $name ======================="
checkHealth $ipport $name
health=$?
if [[ $health -eq 1 ]]
echo "$name 检查完毕,无问题!"
echo "重启 $name 预计2分钟"
docker stop $name
sleep 5s
docker start $name
sleep 120s
checkHealth $ipport $name
health=$?
currTime=`date +"%Y-%m-%d %H:%M:%S"`
if [[ $health -eq 1 ]];then
echo "$currTime $name 服务已重启完成"
echo "$currTime $name 服务尚未重启完成,再休眠60s等待"
sleep 60s
echo "end $name 所有处理完毕==========="
uptime=$(cat /proc/uptime)
echo "uptime: $uptime"
uptimeArr=(${uptime//./ })
startTime=${uptimeArr[0]}
echo $startTime
a=`expr $startTime + 1`
b=1800
if [[ "$a" -lt "$b" ]];
echo "系统启动30分钟内不执行"
echo "启动时间为$startTime秒,正常执行脚本"
echo "先关闭定时任务"
/sbin/service crond stop
ipport1=172.16.1.122:8181
name1=datacenter
dealCheckResult $ipport1 $name1
ipport2=172.16.1.122:8282
name2=unit
dealCheckResult $ipport2 $name2
ipport3=172.16.1.122:8383
name3=core
dealCheckResult $ipport3 $name3
echo "重新启动定时任务"
/sbin/service crond start
功能需求:
包括健康数据、健康科普、健康讨论、个人中心四个模块。
健康数据:用户输入数据,如体重(和身高一起计算体重指数BMI)、体温、血压、血糖、心率、步数(跑步步数)、视力、肺活量等,这些数据不是都一定要填,用户填自己已知的,把填写的数据与男性或女性的正常数据范围做对比,不在正常范围内的数据,系统指出并给用户建议,给出的建议和其它数据一起显示在屏幕上。
健康科普:高级用户(通过客服申请,后台认证)可以发布科普类文章,文章要显示用户作者,可以点赞和收藏。该模块有个搜索功能,用户输入关键字,搜索显示带关键字的文章。多个文章在界面上的排序方式有最新和最热两种,最新是根据文章的发布时间依次排序,最热是根据帖子的收藏+点赞共同决定。
健康讨论:用户都可以发布帖子讨论,类似豆瓣帖,可以留言、点赞、转发、收藏。该模块有个搜索功能,用户输入关键字,搜索显示带关键字的帖子。多个帖子在界面上的排序方式有最新和最热两种,最新是根据帖子的发布时间依次排序,最热是根据帖子的收藏+转发+点赞+评论数共同决定。
个人中心:基本信息(昵称、性别、年龄、身高等)、历史健康数据(系统提出的建议也保留)、讨论
最近公司需要在Linux下监控tomcat的服务,一旦tomcat服务存在异常或者宕机,重启tomcat保证服务的正常运行,由于Linux下有Shell脚本可以实现此效果,下面是Linux下shell脚本监控Tomcat的状态并实现自动启动的步骤。
1.编写Shell脚本monitor.sh
#!/bin/sh
# func:自动监控tomcat脚本并且执行重启操作
# author:EagleHao
# date:2018-04-08
# DEFINE
# 获取tomcat进程ID(其中[grep -w 'tomcat']代码中的tomcat需要替换为你的tomcat文件夹名)
Tomca
1.我的文件格式:cr-out.1.0.0.jar
2.开发使用的是springboot进行开发,这里脚本也是利用springboot中health来获得监控信息
3.shell目录结构
|-- bin #存放所有脚本路径
| |-- EnVariable.sh
| |-- out.sh
|-- conf #脚本配置文件
| |-- filejar.txt
|-- logs #日志
SpringBoot提供了CommandLineRunner、ApplicationRunner两个监听接口,通过这两个接口可以在应用启动时做特殊处理。
使用两者的好处在于,可以方便的使用应用启动参数,根据参数不同做不同的初始化操作。
自定义启动监听由程序实现,并且标识@Component注解,交于IOC管理。在SpringBoot启动成功后就会执行实现类的回调。
第一步: 自定义CommandLineRunner:
@Component
public class CommandLineStartu
对于服务器来说在线率很重要,出现问题要能及时解决,但系统管理员不能一直守在电脑旁边,通过脚本监控网站出现问题及时通过mail通知管理员,如果是139邮箱还可免费手机短信通知。注:通过系统直接发送mail容易被拦截,可使用mail连接第三方smtp发送邮件。
shell脚本实现代码: 代码如下:#!/bin/bash#set -xwhile truedo list=(www.jb51.net s.jb51.net) mail=jmj@jb51.net date=$(date -d “today” +”%Y-%m-%d-%H:%M:%S”) i=0 id=${#list[*]} while [ $
前面 部署springboot的文章中介绍了 启动和停止项目的方法,如果需要替换包重启,或者查看状态,会有很多不方便的地方。
以此我们可以通过编写一个shell脚本来进行启动(start)停止(stop)重启(restart)操作,一步到位,方便高效。
在项目同级目录下 创建 lgn.sh 脚本,编辑内容如下。
#!/bin/bash
#这里可替换为你自己的jar包名称,其他代码无需更改。
APP...
公司经过野蛮生长阶段,系统稳定性,CI,CD持续集成交付,基于Spring Cloud 微服务系统使用Spring Boot健康检查工具,提高发布的效率和全方位监控。在没有监控之前,比如说一个Feign微服务项目,我们可能在SpringBoot项目启动之后通过一个Rest接口比如说 127.0.0.1:8888/ok 这个种接口的形式,集成在自动化脚本里面去校验发布时候正常,或者人工去做一些校验。
其实这些都可以通过 Actuator 工具包去做。
官方文档: docs.spring.io/sp