log4j与log4j2性能对比及log4j升级至log4j2方案
1.前言
之前某个服务在压测环境中出现了问题,分析之后得知是log4jLogger对象争用厉害,很多线程阻塞在此。
以上问题证明log4j在高并发高QPS情况下,是存在性能问题的。
之后把log4j升级成了log4j2,并采取异步日志模式,解决了因日志造成的性能问题。
2.性能对比
关于log4j与log4j2的性能对比文章有很多,本文不过多描述,给出几张结论图及原文链接,作为参考。
Log4j1、Logback 以及 Log4j2 性能测试对比:
logback log4j log4j2 性能实测:
高性能队列——Disruptor
3、相关知识
和日志相关的概念有:log4j、log4j2、logback、commons-logging、slf4j。其中,log4j、log4j2、logback、commons-logging都是日志的具体实现包。slf4j是一个门面,一个适配器,所有的日志代码都可以用slf4j来写,它会根据项目具体依赖的日志实现包进行日志操作。通过slf4j写日志的好处是,当更换日志的实现方案时,无需修改日志代码,只需修改pom.xml即可。
推荐:通过slf4j写日志。
推荐:通过lombok的@Slf4j注解写日志。
4.log4j升级至log4j2
4.1.排除旧的日志实现包
<exclusions>
<!-- log4j 相关包 -->
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<!-- log4j 的springboot starter -->
<exclusion>
<artifactId>spring-boot-starter-log4j</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
<!-- logback 相关包 -->
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>logback-core</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<!-- slf4j 相关包 -->
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-to-slf4j</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
4.2.增加log4j2的依赖包
<!-- log4j2的api、core和web包 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.11.1</version>
</dependency>
<!-- slf4j与log4j2的连接包 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.1</version>
</dependency>
<!-- log4j与log4j2的连接包 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.11.1</version>
</dependency>
<!-- log4j2支撑完全异步模式的关键api -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
<!-- slf4j本身的api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<configuration status="error" monitorInterval="30">
<Properties>
<Property name="baseDir">log</Property>
</Properties>
<!--先定义所有的appender-->
<appenders>
<!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d %5p %c:%L - %m %throwable{}%n"/>
</Console>
<!--异步日志配置,指向配置引用AppenderRef-->
<Async name="ASYNC" bufferSize="262144" includeLocation="true">
<AppenderRef ref="RollingFile"/>
</Async>
<!--日志文件配置,filePattern为日志文件名称的格式-->
<RollingFile name="RollingFile" fileName="${baseDir}/info.log" filePattern="${baseDir}/info.log.%d{yyyy-MM-dd}">
<!--日志内容格式-->
<PatternLayout pattern="%d %5p %c:%L - %m %throwable{separator( --> )}%n"/>
<!--依据时间创建新的日志文件:1d-->
<TimeBasedTriggeringPolicy interval="1"/>
<DefaultRolloverStrategy>
<!-- 在轮转时,删除7天之前的,命名符合规则的文件 -->
<Delete basePath="${baseDir}">
<IfFileName glob="info.log.*"/>
<IfLastModified age="7d"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFile"/>
</root>
<!--这里配置 过滤日志 -->
<logger name="org.hibernate.validator" level="ERROR"/>
</loggers>
</configuration>
扫
码
关
注