天天看點

經典日志系統異步列印配置清單

作者:技術聯盟總壇

一、前言

在高并發高流量響應延遲要求比較小的系統中同步打日志已經滿足不了需求了,同步打日志會阻塞調用打日志的線程,而打日志本身是需要寫磁盤的,是以會造成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,進而啟動異步日志列印。

繼續閱讀