替换jar包未重启引起的系统宕机事件

一、事件背景:

某天凌晨,一阵急促的铃声将我从周公那里拉了过来,接听电话后,一脸懵逼。

什么情况?XX后台宕机了?当日日志也不打印了,前端发起的请求,都报超时,重启后又恢复了,不清楚会不会再次宕机。

出现这种情况,我第一时间想的是为什么是00:00:00宕机?难道后台嫌我这个大龄程序员睡得早了?

然后是通过远程视频,看日志,排查了凌晨之前的日志里的所有异常,均无有效的线索,毫无头绪。

这就大半夜的见鬼了,看来一时半会搞不定,看来得心爱的野摩托出马了,匆匆赶到客户现场,然后巴拉巴拉小魔仙,各种猜测、验证。

 

二、项目情况说明:

根据问题现象,最明显的地方是出现了日志打印异常,怀疑日志打印那块的功能导致的宕机。

于是,我静下心来研究下该后台使用的日志架构。

先看pom.xml文件,然后找日志相关组件,

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>

最后在某jar包里,发现了这个配置:logback-spring.xml

 

三、问题分析思路:

logback-spring.xml关键配置:

<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/dev.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/dev/dev-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>1000MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>

从问题现象来看,凌晨以后,../dev/dev-2023-04-13.0.log能够正常生成,而dev.log不行。

说明宕机可能出现的地方在这个环节之间。那就先分析代码吧。

四、宕机原因分析:

看上述配置文件中,有个比较关键的日志策略类:TimeBasedRollingPolicy,没说的,先找api文档吧。具体见下。

https://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/TimeBasedRollingPolicy.html

其中有一行比较关键:

void rollover() Rolls over log files according to implementation policy.(根据实施策略滚动日志文件。
就他了,看样子是这个方法里出现异常了,反编译瞅瞅吧,试试水有多深。
源码分析:
public void rollover() throws RolloverFailure {
   //timeBasedFileNamingAndTriggeringPolicy有两个实现类:
   //DefaultTimeBasedFileNamingAndTriggeringPolicy.java、SizeAndTimeBasedFNATP.java。
// 对照下logback-spring.xml中的配置,使用的是后者SizeAndTimeBasedFNATP.java,elapsedPeriodsFileName
  //再看这个类里这个字段的初始化,很容易猜出来,elapsedPeriodsFileName
//就是用来生成上一天的日志文件的,此处是:elapsedPeriodsFileName="dev-2023-04-13.0.log"
    String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy.getElapsedPeriodsFileName();
  //此处是去掉结尾的"/",对文件名进行合法性处理
String elapsedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);
   // compressionMode:NONE, GZ, ZIP 有此推测如下IF-ELSE用来实现文件写入,dev-2023-04-13.0.log就是在这个里面完成写入的。
if (compressionMode == CompressionMode.NONE) {
if (getParentsRawFileProperty() != null) {
renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName);
} // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null }
} else {
if (getParentsRawFileProperty() == null) {
compressionFuture = compressor.asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elapsedPeriodStem);
} else {
compressionFuture = renameRawAndAsyncCompress(elapsedPeriodsFileName, elapsedPeriodStem);
}
}
   //看来问题最容易出现的地方是这里:下面应该是要生成dev.log文件,而实际没有生成
if (archiveRemover != null) {
     //此变量的生成应该不容易引起宕机,推测是下下一步导致的宕机
Date now = new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime());
this.cleanUpFuture = archiveRemover.cleanAsynchronously(now);
}
}

TimeBasedArchiveRemover.java public Future<?> cleanAsynchronously(Date now) { ArhiveRemoverRunnable runnable = new ArhiveRemoverRunnable(now); ExecutorService executorService = context.getScheduledExecutorService(); Future<?> future = executorService.submit(runnable); return future; }
重点在这里:ArhiveRemoverRunnable。
这个类是内部类,用途是实现了个线程类,初看没啥问题,仔细想想,类的加载是有顺序的,有没有可能是这个内部类加载的时候,报错了?
好好的为啥加载不上了呢?谁动了他的奶酪?
各种检查、分析,发现了个奇怪的现象:
日志中打印的jar启动的时间是10点,然后jar包的最后修改时间是17点。什么鬼?难道是替换了新包没有重启,导致这个内部类加载有问题,系统宕机了?
抓紧验证一下,构造一个类似的场景:
1.修改系统时间为23:55:00.使用java -jar ***.jar启动服务。
2.准备个微调的jar包,待之前的服务启动好后,替换掉他,然后坐等零点到来。
3.激动人心的时刻到了,零点后,dev.log不见了,dev-2023-04-13.0.log有生成。抓紧看下控制台。一堆报错,最关键的信息也打印了。
替换jar包未重启引起的系统宕机事件

  到此,本次系统宕机的根因找到了,是jar包替换没有重启,导致日志打印那块出现中断,最后跟实时的同事要求升级包要规范,不能这样随意的操作。

五、总结:

这个问题太邪门了,尤其是凌晨暴雷,简直是要了程序员的老命,果然不管什么问题,重启试试是最有效的武器。

本次系统宕机的问题就分享到这里,谢谢大家批评指正。

 

timeBasedFileNamingAndTriggeringPolicy

原文链接:https://www.cnblogs.com/y-h-c/p/17314156.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:替换jar包未重启引起的系统宕机事件 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • Java Apache Commons报错“InstantiationException”的原因与解决方法

    当使用Java的Struts框架时,可能会遇到“ActionServletMappingException”错误。这个错误通常由以下原因之一起: ActionServlet配置错误:如果ActionServlet配置错误,则可能会出现此错误。在这种情况下,需要检查ActionServlet配置以解决此问题。 ActionServlet无效:如果ActionS…

    Java 2023年5月5日
    00
  • Java创建对象之显示创建与隐式创建

    Java创建对象之显示创建与隐式创建 在Java语言中,创建对象有两种方式:显示创建和隐式创建。本文将对这两种方式进行详细讲解。 显示创建 1. 使用new关键字 使用new关键字创建对象是最常见的方式。new关键字会在堆内存中为对象分配空间,并返回对象的引用。示例如下: // 创建 String 对象 String str1 = new String(&q…

    Java 2023年5月26日
    00
  • Mybatis映射文件规则实例详解

    首先,Mybatis映射文件规则实例详解包括以下要点: 配置文件的命名和存放位置; 映射语句的命名和编写; 参数和返回值的配置。 接下来,我们逐一讲解每个要点: 1. 配置文件的命名和存放位置 在Mybatis中,我们需要创建一个XML文件来存放我们的映射配置。这个XML文件的命名不是固定的,但是一般情况下我们会把它命名为“映射的实体类名Mapper.xml…

    Java 2023年5月20日
    00
  • 简单了解JAVA构造方法

    简单了解JAVA构造方法 什么是构造方法 Java中每个类都有构造方法,构造方法是用来初始化对象的方法,即在使用new操作符创建对象时调用的一种特殊方法。构造方法与类名相同,无需返回类型,且不能被重载。 构造方法的特点 构造方法名要与类名相同,且区分大小写; 构造方法没有返回值类型; 构造方法没有具体的返回值,但需要使用return语句结束构造方法; 构造方…

    Java 2023年5月26日
    00
  • tk-mybatis整合springBoot使用两个数据源的方法

    下面是“tk-mybatis整合springBoot使用两个数据源的方法”的完整攻略及两条示例: 一、准备工作 在进行整合之前,我们需要做以下准备工作: 创建两个数据库,分别为db1和db2,并分别创建表user,表结构如下: CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name`…

    Java 2023年5月20日
    00
  • SpringBoot快速构建应用程序方法介绍

    SpringBoot快速构建应用程序方法介绍 SpringBoot是一个快速构建应用程序的工具。它可以帮助开发人员快速创建基于Spring框架的应用程序,而不需要手动配置很多琐碎的细节。 1. 环境搭建 要开始使用SpringBoot,需要先搭建Java开发环境和Gradle/Maven构建工具。 1.1. 安装Java JDK SpringBoot需要Ja…

    Java 2023年5月15日
    00
  • 关于RequestMapping注解的作用说明

    关于@RequestMapping注解的作用说明 @RequestMapping注解是Spring框架中最常用的注解之一,它可以用来映射URL和处理HTTP请求,是控制器中的一个方法级别的注解。下面将详细介绍@RequestMapping的作用和使用说明。 基本作用 @RequestMapping注解用于将指定的URL映射到处理请求的控制器方法上。当请求UR…

    Java 2023年6月15日
    00
  • spring学习之创建项目 Hello Spring实例代码

    创建 Spring 项目 Hello Spring 实例代码的完整攻略包括以下步骤: 1. 创建 Maven 项目 使用 Maven 作为构建工具,创建一个 Spring 项目。可以使用 mvn archetype:generate 命令快速创建一个 Maven 项目,输入 maven-archetype-webapp 可以创建一个 Java Web 项目。…

    Java 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部