欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

logback異步輸出日志過程解讀

 更新時間:2025年07月21日 14:50:36   作者:斗者_2013  
文章介紹logback作為SpringBoot默認日志框架,通過異步輸出(AsyncAppender)顯著提升高并發(fā)場景下的程序性能,性能測試顯示TPS可提高10倍以上,建議生產(chǎn)環(huán)境采用滾動文件輸出與異步機制結(jié)合

前言

logback應該是目前最流行的日志打印框架了,畢竟Spring Boot中默認的集成的日志框架也是logback。

在實際項目開發(fā)過程中,常常會遇到由于打印大量日志而導致程序并發(fā)降低,QPS降低的問題,而通過logback異步日志輸出則能很大程度上解決這個問題。

一、什么是Appender?

官方介紹:

Logback 將編寫日志事件的任務委托給名為 Appenders 的組件,Appenders 必須實現(xiàn)ch.qos.logback.core.Appender的接口。

簡單來說,Appender就是用來處理logback框架下日志輸出事件的組件。

  • Appender接口的核心方法如下:
package ch.qos.logback.core;
  
import ch.qos.logback.core.spi.ContextAware;
import ch.qos.logback.core.spi.FilterAttachable;
import ch.qos.logback.core.spi.LifeCycle;
  

public interface Appender<E> extends LifeCycle, ContextAware, FilterAttachable {

  public String getName();
  
  public void setName(String name);

 //核心方法:處理日志事件
  void doAppend(E event);
  
}

其中doAppend()方法是 logback 框架中最重要的方法。它負責將日志事件以適當?shù)母袷捷敵龅竭m當?shù)妮敵鲈O(shè)備。

二、Appender類圖

說明:

OutputStreamAppender 是另外三個附加程序的超類,即 ConsoleAppender 和 FileAppender,后者又是 RollingFileAppender 的超類。

下一個圖說明了 OutputStreamAppender 及其子類的類圖。

1、控制臺日志輸出 ConsoleAppender

  • 配置示例:
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
       <appender-ref ref="STDOUT" />
  </root>
  </configuration>

說明:

控制臺日志輸出主要是在開發(fā)環(huán)境采用,比如在IDEA中開發(fā)時,可以清楚直觀得在控制臺看到運行日志,更方便程序調(diào)試。

當應用發(fā)布到測試環(huán)境、生產(chǎn)環(huán)境時,建議關(guān)閉控制臺日志輸出,以提高日志輸出的吞吐量,減少不必要的性能開銷。

2、單日志文件輸出 FileAppender

  • 配置示例:
<configuration>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <!-- 日志文件名稱 -->
    <file>testFile.log</file>
    <!-- 是否追加輸出 -->
    <append>true</append>
    <!-- 立即刷新,設(shè)置成false可以提高日志吞吐量 -->
    <immediateFlush>true</immediateFlush>
    <encoder>
     <!-- 日志輸出格式 -->
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
        
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

弊端:

采用單日志文件輸出日志,很容易導致日志文件的體積一直膨脹,不利于日志文件的管理和查看。

一般很少采用。

3、滾動日志文件輸出 RollingFileAppender

  • 配置示例:
<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 日志文件名稱 -->
    <file>logFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- 按天滾動生成歷史日志文件 -->
      <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>

      <!-- 歷史日志文件保存的天數(shù)和容量大小-->
      <maxHistory>30</maxHistory>
      <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>

    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender> 

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

說明:

通過rollingPolicy 配置日志文件的滾動生成策略,以及歷史日志文件保存的天數(shù)和總?cè)萘看笮。?/p>

是測試環(huán)境和生產(chǎn)環(huán)境最推薦的日志輸出方式。

三、同步輸出和異步輸出比較

同步輸出

  • 傳統(tǒng)的日志打印采用的是同步輸出的方式,所謂同步日志,即當輸出日志時,必須等待日志輸出語句執(zhí)行完畢后,才能執(zhí)行后面的業(yè)務邏輯語句。
  • 使用logback的同步日志進行日志輸出,日志輸出語句與程序的業(yè)務邏輯語句將在同一個線程運行。
  • 在高并發(fā)場景下,日志數(shù)量不但激增,作為磁盤IO來說,容易產(chǎn)生瓶頸,導致線程卡頓在生成日志過程中,會影響程序后續(xù)的主業(yè)務,降低程序的性能。

異步輸出

  • 使用異步日志進行輸出時,日志輸出語句與業(yè)務邏輯語句并不是在同一個線程中運行,而是有專門的線程用于進行日志輸出操作,處理業(yè)務邏輯的主線程不用等待即可執(zhí)行后續(xù)業(yè)務邏輯。
  • 這樣即使日志沒有完成輸出,也不會影響程序的主業(yè)務,從而提高了程序的性能。

四、異步日志實現(xiàn)原理AsyncAppender

logback異步輸出日志是通過AsyncAppender實現(xiàn)的。AsyncAppender可以異步的記錄 ILoggingEvents日志事件。

但是這里需要注意,AsyncAppender只充當事件分配器,它必須引用另一個Appender才能完成最終的日志輸出。

示意圖:

Logback的異步輸出采用生產(chǎn)者消費者的模式,將生成的日志放入消息隊列中,并將創(chuàng)建一個線程用于輸出日志事件,有效的解決了這個問題,提高了程序的性能。

logback中的異步輸出日志使用了AsyncAppender這個appender,通過看AsyncAppender源碼,跟到它的父類AsyncAppenderBase,可以看到它有幾個重要的成員變量:

AppenderAttachableImpl<E> aai = new AppenderAttachableImpl<E>();
BlockingQueue<E> blockingQueue;
AsyncAppenderBase<E>.Worker worker = new AsyncAppenderBase.Worker();

lockingQueue是一個隊列,Worker是一個消費線程,基本可以判定是個生產(chǎn)者消費者模式。

  • 再看消費者(work)的主要代碼:
while (parent.isStarted()) {
    try {
        E e = parent.blockingQueue.take();    //單條循環(huán)
        aai.appendLoopOnAppenders(e);
    } catch (InterruptedException ie) {
        break;
    }
}

使用的是while單條循環(huán) ,即logback異步輸出是由一個消費者循環(huán)單條寫入日志文件,工作流程如下圖:

五、異步日志配置

配置示例:

配置異步輸出日志的方式很簡單,添加一個基于異步寫日志的 appender,并指向原先配置的 appender即可。

<configuration>
	  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
	    <file>myapp.log</file>
	    <encoder>
	      <pattern>%logger{35} - %msg%n</pattern>
	    </encoder>
	  </appender>

	  <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
	     <appender-ref ref="FILE" />
         <!-- 設(shè)置異步阻塞隊列的大小,為了不丟失日志建議設(shè)置的大一些,單機壓測時100000是沒問題的,應該不用擔心OOM -->
        <queueSize>10000</queueSize>
        <!-- 設(shè)置丟棄DEBUG、TRACE、INFO日志的閥值,不丟失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 設(shè)置隊列入隊時非阻塞,當隊列滿時會直接丟棄日志,但是對性能提升極大 -->
        <neverBlock>true</neverBlock>
	  </appender>

	  <root level="DEBUG">
	    <appender-ref ref="ASYNC" />
	  </root>
 </configuration>

核心配置參數(shù)說明:

屬性名類型描述
queueSizeintBlockingQueue的最大容量,默認情況下,大小為256。
discardingThresholdint設(shè)置日志丟棄閾值, 默認情況下,當隊列還有20%容量,他將丟棄trace、debug和info級別的日志,只保留warn和error級別的日志。
includeCallerDataboolean提取調(diào)用方數(shù)據(jù)可能相當昂貴。若要提高性能,默認情況下,當事件添加到事件隊列時,不會提取與事件關(guān)聯(lián)的調(diào)用方數(shù)據(jù)。默認情況下,只復制線程名和 MDC 等“廉價”數(shù)據(jù)。通過將 includeecallerdata 屬性設(shè)置為 true,可以指示此附加程序包含調(diào)用方數(shù)據(jù)。
maxFlushTimeint根據(jù)被引用的 appender 的隊列深度和延遲,AsyncAppender 可能需要不可接受的時間來完全刷新隊列。當 LoggerContext 停止時,AsyncAppender stop 方法將等待工作線程完成直到超時。使用 maxFlushTime 指定最大隊列刷新超時(以毫秒為單位)。無法在此窗口內(nèi)處理的事件將被丟棄。此值的語義與 Thread.join (long)的語義相同。
neverBlockboolean默認是false,代表在隊列放滿的情況下是否卡住線程。也就是說,如果配置neverBlock=true,當隊列滿了之后,后面阻塞的線程想要輸出的消息就直接被丟棄,從而線程不會阻塞。

默認情況下,event queue配置最大容量為256個events。如果隊列已經(jīng)滿了,那么應用程序線程將被阻塞,無法記錄新事件,直到工作線程有機會分派一個或多個事件。當隊列不再達到最大容量時,應用程序線程可以再次開始記錄事件。因此,當應用程序在其事件緩沖區(qū)的容量或附近運行時,異步日志記錄就變成了偽同步。

這未必是件壞事,AsyncAppender異步追加器設(shè)計目的是允許應用程序繼續(xù)運行,盡管需要稍微多一點的時間來記錄事件,直到附加緩沖區(qū)的壓力減輕。

優(yōu)化 appenders 事件隊列的大小以獲得最大的應用程序吞吐量取決于幾個因素。

下列任何或全部因素都可能導致出現(xiàn)偽同步行為:

  • 大量的應用程序線程
  • 每個應用程序調(diào)用都有大量的日志事件
  • 每個日志事件都有大量數(shù)據(jù)
  • 子級appenders的高延遲

為了保持事情的進展,增加隊列的大小通常會有所幫助,代價是減少應用程序可用的堆。

為了減少阻塞,在缺省情況下,當隊列容量保留不到20% 時,AsyncAppender 將丟失 TRACE、 DEBUG 和 INFO 級別的事件,只保留 WARN 和 ERROR 級別的事件。

這種策略確保了對日志事件的非阻塞處理(因此具有優(yōu)異的性能) ,同時在隊列容量小于20% 時減少 TRACE、 DEBUG 和 INFO 級別的事件。事件丟失可以通過將丟棄閾值屬性設(shè)置為0(零)來防止。

六、性能測試

這部分自己還沒時間做測試,引用網(wǎng)上的一些測試數(shù)據(jù)。

既然能提高性能的話,必須進行一次測試比對,同步和異步輸出日志性能到底能提升多少倍?

服務器硬件

  • CPU 六核
  • 內(nèi)存 8G

測試工具

  • Apache Jmeter

1、同步輸出日志

  • 線程數(shù):100
  • Ramp-Up Loop(可以理解為啟動線程所用時間) :0 可以理解為100個線程同時啟用
  • 測試結(jié)果:

重點關(guān)注指標 Throughput【TPS】 吞吐量:系統(tǒng)在單位時間內(nèi)處理請求的數(shù)量,在同步輸出日志中 TPS 為 44.2/sec

2、異步輸出日志

  • 線程數(shù) 100
  • Ramp-Up Loop:0
  • 測試結(jié)果:

TPS 為 497.5/sec , 性能提升了10多倍?。?!

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • IntelliJ?IDEA?2021.3永久最新激活至2099年(親測有效)

    IntelliJ?IDEA?2021.3永久最新激活至2099年(親測有效)

    最新版idea2021.3已出來,很多網(wǎng)友迫不及待的要升級idea2021最新版,今天小編抽空給大家整理了一篇教程關(guān)于idea2021.3最新激活教程,本文以idea2021.2.3為例通過圖文并茂的形式給大家分享激活詳細過程,感興趣的朋友參考下吧
    2020-12-12
  • 淺析Java.IO輸入輸出流 過濾流 buffer流和data流

    淺析Java.IO輸入輸出流 過濾流 buffer流和data流

    這篇文章主要介紹了Java.IO輸入輸出流 過濾流 buffer流和data流的相關(guān)資料,本文給大家介紹的非常詳細,具有參考借鑒價值,需要的朋友可以參考下
    2016-10-10
  • 使用Java 實現(xiàn)一個“你畫手機猜”的小游戲

    使用Java 實現(xiàn)一個“你畫手機猜”的小游戲

    這篇文章主要介紹了使用Java 實現(xiàn)一個“你畫手機猜”的小游戲,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • java自定義驗證器的實現(xiàn)示例

    java自定義驗證器的實現(xiàn)示例

    在對外暴露接口中,我們通常會對入?yún)⑦M行驗證,比如一些字符串非空判斷等,本文主要介紹了java自定義驗證器的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • JAVA不可變類(immutable)機制與String的不可變性(推薦)

    JAVA不可變類(immutable)機制與String的不可變性(推薦)

    這篇文章主要介紹了JAVA不可變類(immutable)機制與String的不可變性(推薦)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-08-08
  • Spring中的@Transactional的工作原理

    Spring中的@Transactional的工作原理

    這篇文章主要介紹了Spring中的@Transactional的工作原理,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-06-06
  • Spring Boot+Nginx實現(xiàn)大文件下載功能

    Spring Boot+Nginx實現(xiàn)大文件下載功能

    相信很多小伙伴,在日常開放中都會遇到大文件下載的情況,大文件下載方式也有很多,比如非常流行的分片下載、斷點下載;當然也可以結(jié)合Nginx來實現(xiàn)大文件下載,在中小項目非常適合使用,這篇文章主要介紹了Spring Boot結(jié)合Nginx實現(xiàn)大文件下載,需要的朋友可以參考下
    2024-05-05
  • 查看Spring容器中bean的五種方法小結(jié)

    查看Spring容器中bean的五種方法小結(jié)

    近期在寫Spring項目的時候,需要通過注解的形式去替代之前直接將Bean存放在Spring容器這種方式,以此來簡化對于Bean對象的操作,這篇文章主要給大家介紹了關(guān)于如何查看Spring容器中bean的五種方法,需要的朋友可以參考下
    2024-05-05
  • Java版仿QQ驗證碼風格圖片驗證碼

    Java版仿QQ驗證碼風格圖片驗證碼

    這篇文章主要為大家分享了java圖片驗證碼實例代碼,感興趣的小伙伴們可以參考一下
    2016-04-04
  • 使用Spring Boot+MyBatis框架做查詢操作的示例代碼

    使用Spring Boot+MyBatis框架做查詢操作的示例代碼

    這篇文章主要介紹了使用Spring Boot+MyBatis框架做查詢操作的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-10-10

最新評論