天天看点

经典日志系统异步打印配置清单

作者:技术联盟总坛

一、前言

在高并发高流量响应延迟要求比较小的系统中同步打日志已经满足不了需求了,同步打日志会阻塞调用打日志的线程,而打日志本身是需要写磁盘的,所以会造成rt增加。异步日志就是为了解决这个问题,本文我们探讨场景的几种日志系统的异步log配置方案。

二、日志打印模型

  • 同步日志模型
经典日志系统异步打印配置清单

如上图,多个业务线程打印日志时候要等把内容写入磁盘后才会返回,所以打日志的rt就是写入磁盘的耗时。

  • 异步日志模型
经典日志系统异步打印配置清单

如上图多个业务线程打印日志时候是把打印任务放入内存队列后就直接返回了,而具体打印日志是有日志系统的一个日志线程去队列里面获取然后执行,可见这种打印rt就是写入内存队列的耗时。其实是一个多生产者单消费者模型。

三、LogBack异步配置

<!--1.同步appender -->
<appender name="syncAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
   ...
</appender>

<!--2.异步appender -->
<appender name="ASYNC-LOG" class="ch.qos.logback.classic.AsyncAppender">
    <!--内部实现是一个有界ArrayBlockingQueue,queueSize是队列大小。该值会影响性能.默认值为256-->
    <queueSize>512</queueSize>
    <!--当队列的剩余容量小于这个阈值并且当前日志level TRACE, DEBUG or INFO,则丢弃这些日志。默认为queueSize大小的20%。-->
    <discardingThreshold>102</discardingThreshold>
    <!--neverBlock=true则写日志队列时候会调用阻塞队列的offer方法而不是put,如果队列满则直接返回,而不是阻塞,即日志被丢弃。-->
    <neverBlock>true</neverBlock>
    <!--实际负责写日志的appender,最多只能添加一个-->
    <appender-ref ref="syncAppender" />
</appender>

<!--3.log对象 -->
<logger name="errorLog" additivity="false">
    <appender-ref ref="ASYNC-LOG"/>
    ...
</logger>           
  • 代码1是我们正常的同步syncAppender的配置
  • 代码2创建一个异步appender,然后使用appender-ref引用同步的syncAppender。注意,这里把neverBlock=true则写日志队列时候会调用阻塞队列的offer方法而不是put,如果队列满则直接返回,业务调用线程不会被阻塞,即日志被丢弃。并且异步队列大小为512。
  • 代码3设置异步appender到log对象。

四、Log4j异步配置

<appender name="ASYNC-ERROR"class="org.apache.log4j.AsyncAppender">
    <!--内部实现是一个列表,BufferSize是列表大小。该值会影响性能.默认值为128-->
    <param name="BufferSize" value="1024" />
    <!--Blocking=false则写日志队列满时候不会阻塞调用线程。默认是true-->
    <param name="Blocking" value="false" />
    <appender-ref ref="ERROR" />
</appender>           

其中BufferSize为队列的大小,默认128;Blocking=false则写日志队列满时候不会阻塞调用线程。默认是true,标识队列满时候会阻塞调用线程。

五、Log4j2异步配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <File name="MyFile" fileName="logs/app.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
  <!--4.1 设置异步appender-->
    <Async name="Async">
      <AppenderRef ref="MyFile"/>
      <bufferSize>2048</bufferSize>
      <blocking>false</blocking>
    </Async>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="Async"/>
    </Root>
  </Loggers>
</Configuration>           
  • 如上代码4.1设置异步appender.bufferSize:队列的大小为默认1024 blocking,默认为true,如果队列满了当前线程会被阻塞等待队列有空间为止 , false则如果队列满了则丢弃。

六、总结

本文简单介绍了异步日志打印原理,可知三种主流日志系统都是使用队列来实现异步解耦,让业务线程及时返回,但是需要注意当队列满时候设置的策略是丢弃还是阻塞调用线程,另外讲解了如何配置异步appender,从而启动异步日志打印。

继续阅读