EasyExcel打印日志过多,导致程序变慢
1.发现问题
项目中用到EasyExcel读取和写出excel,最开始数据量不多的时候线上没有发现问题,且在本地读取excel的时候也非常快,但是将其放在服务器上的时候,发现特别慢,620条数据在本地读取耗时5s左右,但是在服务器花了520-600s左右。
2.分析问题
最开始分析的时候,我分别打印了业务处理时间和整体时间,我发现真正处理数据的时间也就一分钟半左右,但是整体时间需要耗费8-10分钟,这就让我非常疑惑了。
最开始我以为是网络的原因,我特意打印了一下从网络流中获取数据的时间,发现只需要1s左右,后来发现是从excel读取数据比较慢,以为是docker容器的问题,后来让运维看了一下,不是容器相关问题,在网上搜到一篇文章,大概意思就是说logback的日志过多,会导致很慢。
运维在k8s上发现打印的日志中,EasyExcel疯狂输出Empty Row ! 运维将除了ERROR级别日志都给禁止输出了,发现EasyExcel读取Excel的速度从500多秒,一下子变成3s到5s左右。至此,程序慢的原因找到了。
3.解决问题
为了解决日志输出过程中过滤掉EasyExcel产生的日志,我在logback.xml文档中,使用了过滤器,具体如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- 全局参数 -->
<!-- 日志输出位置 -->
<property name="FILE_PATH" value="./logs/" />
<!-- 日志大小 -->
<property name="MAX_FILE_SIZE" value="100MB" />
<!-- 日志存放天数:注意需启动自动清除 cleanHistoryOnStart = true -->
<property name="MAX_HISTORY" value="180" />
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<property name="FORMAT" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{RequestId}] [%thread] %-5level %logger{50} - %msg%n" />
<!-- 全局日志级别 -->
<springProperty scope="context" name="LEVEL" source="spring.log4j.level" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<matcher>
<name>excel_filter</name>
<regex>(c.a.excel*)|(com.alibaba.excel.*)</regex>
</matcher>
<expression>excel_filter.matches(logger)</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FORMAT}</pattern>
</encoder>
</appender>
<!-- TRACE日志 -->
<appender name="TRACE_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>TRACE</level>
</filter>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<matcher>
<name>excel_filter</name>
<regex>(c.a.excel*)|(com.alibaba.excel.*)</regex>
</matcher>
<expression>excel_filter.matches(logger)</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${FILE_PATH}/%d{yyyy-MM-dd}.TRACE.%i.log</FileNamePattern>
<MaxHistory>${MAX_HISTORY}</MaxHistory>
<MaxFileSize>${MAX_FILE_SIZE}</MaxFileSize>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FORMAT}</pattern>
</encoder>
</appender>
<!-- DEBUG日志 -->
<appender name="DEBUG_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<matcher>
<name>excel_filter</name>
<regex>(c.a.excel*)|(com.alibaba.excel.*)</regex>
</matcher>
<expression>excel_filter.matches(logger)</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${FILE_PATH}/%d{yyyy-MM-dd}.DEBUG.%i.log</FileNamePattern>
<MaxHistory>${MAX_HISTORY}</MaxHistory>
<MaxFileSize>${MAX_FILE_SIZE}</MaxFileSize>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FORMAT}</pattern>
</encoder>
</appender>
<!-- IOFO日志 -->
<appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<matcher>
<name>excel_filter</name>
<regex>(c.a.excel*)|(com.alibaba.excel.*)</regex>
</matcher>
<expression>excel_filter.matches(logger)</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${FILE_PATH}/%d{yyyy-MM-dd}.INFO.%i.log</FileNamePattern>
<MaxHistory>${MAX_HISTORY}</MaxHistory>
<MaxFileSize>${MAX_FILE_SIZE}</MaxFileSize>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FORMAT}</pattern>
</encoder>
</appender>
<!-- WARN日志 -->
<appender name="WARN_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<matcher>
<name>excel_filter</name>
<regex>(c.a.excel*)|(com.alibaba.excel.*)</regex>
</matcher>
<expression>excel_filter.matches(logger)</expression>
<!-- <expression>return message.contains("c.a.e.read.processor.DefaultAnalysisEventProcessor");</expression> -->
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${FILE_PATH}/%d{yyyy-MM-dd}.WARN.%i.log</FileNamePattern>
<MaxHistory>${MAX_HISTORY}</MaxHistory>
<MaxFileSize>${MAX_FILE_SIZE}</MaxFileSize>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FORMAT}</pattern>
</encoder>
</appender>
<!-- ERROR日志 -->
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<matcher>
<name>excel_filter</name>
<regex>(c.a.excel*)|(com.alibaba.excel.*)</regex>
</matcher>
<expression>excel_filter.matches(logger)</expression>
<!-- <expression>return message.contains("c.a.e.read.processor.DefaultAnalysisEventProcessor");</expression> -->
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${FILE_PATH}/%d{yyyy-MM-dd}.ERROR.%i.log</FileNamePattern>
<MaxHistory>${MAX_HISTORY}</MaxHistory>
<MaxFileSize>${MAX_FILE_SIZE}</MaxFileSize>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FORMAT}</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="${LEVEL}">
<appender-ref ref="STDOUT" />
<!-- <appender-ref ref="TRACE_LOG" />-->
<!-- <appender-ref ref="DEBUG_LOG" /> -->
<!-- <appender-ref ref="INFO_LOG" />-->
<!-- <appender-ref ref="WARN_LOG" />-->
<!-- <appender-ref ref="ERROR_LOG" />-->
</root>
</configuration>
但是使用这个过滤器的时候需要,增加对应的依赖,否则或报错
依赖文件
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.2</version>
</dependency>