高性能logback

logback使用中,会因为日志量过大,导致请求响应时间太长。本文介绍几种常见提升logback性能的办法

异步Appender

异步是降低日志对请求耗时影响的最有效方法,首推使用!

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="logDir" value="${catalina.base}/logs" />
    <property name="commonPattern" value="[%thread][%level][%class{0}:%line]: %msg%n" />

    <appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logDir}/all.log</file>
        <encoder>
            <pattern>${commonPattern}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${logDir}/all.%d{yyyy-MM-dd}.log.zip</FileNamePattern>
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>
   <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <includeCallerData>true</includeCallerData>
        <discardingThreshold>-1</discardingThreshold>
        <queueSize>1024</queueSize>
        <appender-ref ref="ALL" />
    </appender>

    <root level="DEBUG">
        <appender-ref ref="ASYNC" />
    </root>
</configuration>
  • queueSize 默认值256,不过该值首次建议设置大一些,后续根据自己业务的特点去调优,降低日志丢失的概率。
  • discardingThreshold:默认情况下,当blockingQueue的容量高于阈值时(80%),会丢弃ERROR以下级别的日志,如果不希望丢弃日志(既每次都是全量保存),那可以设置为0,但是如果队列满的时候,会丢弃所有插入队列的日志信息,所以建议设置为-1(默认值)。 如正常日志可以丢弃,那可以极大的提升性能,并保存关键的ERROR日志。
  • AsyncAppender中只能配置一个appender-ref,配置多个就会无效

不同环境不同配置

开发环境一般都把日志输出到ConsoleAppender,但是其他环境是不需要的,可以使用动态配置。

<root level="DEBUG">
    <appender-ref ref="ASYNC"/>
    <if condition='property("os.name").toUpperCase().contains("WINDOWS") || property("os.name").toUpperCase().contains("MAC")'>
        <then>
            <appender-ref ref="STDOUT"/>
        </then>
    </if>
</root>

pom.xml中需要添加依赖

<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>3.0.11</version>
</dependency>

过滤异常栈

异常栈可以非常有效地帮助定位问题,但是也会因为异常栈太长,包含了太多几乎无价值的信息,比如反射、动态代理、Spring、tomcat等调用信息。过滤掉这部分信息,既减少了日志量,也减少大对象的数量,降低Full GC的次数。常用配置如下:

<property name="commonPattern" value="[%thread][%level][%class{0}:%line]: %msg%n%rEx{full,
     java.lang.reflect.Method,
     sun.reflect,
     org.apache.catalina,
     org.springframework.aop,
     org.springframework.security,
     org.springframework.transaction,
     org.springframework.web,
     org.springframework.beans,
     org.springframework.cglib,
     net.sf.cglib,
     org.apache.tomcat.util,
     org.apache.coyote,
     ByCGLIB,
     BySpringCGLIB,
     com.google.common.cache.LocalCache$
}"/>

常见问题

  • 日志中的%class%line中没有显示正确的值,而是两个问号?
    解决办法:一般出现在AsyncAppender中,需要添加属性<includeCallerData>true</includeCallerData>

参考

推荐阅读更多精彩内容