Logback配置文件這麼寫,TPS提高10倍

通過閱讀本篇文章將瞭解到

  1. 日誌輸出到文件並根據LEVEL級別將日誌分類保存到不同文件
  2. 通過異步輸出日誌減少磁盤IO提高性能
  3. 異步輸出日誌的原理

配置文件logback-spring.xml

SpringBoot工程自帶logback和slf4j的依賴,所以重點放在編寫配置文件上,需要引入什麼依賴,日誌依賴衝突統統都不需要我們管了。

logback框架會默認加載classpath下命名為logback-spring或logback的配置文件。將所有日誌都存儲在一個文件中文件大小也隨著應用的運行越來越大並且不好排查問題,正確的做法應該是將error日誌和其他日誌分開,並且不同級別的日誌根據時間段進行記錄存儲。


 
 
 
 [%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n
 
 
  
 
 
 ERROR
 DENY
 ACCEPT
 
 
 [%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n
 
  
 
  
 ${LOG_INFO_HOME}//%d.log
 30
 
 
 
 
 ERROR
 
 
 [%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n
 
  
 
  
 ${LOG_ERROR_HOME}//%d.log
 30
 
 
 
 
 
 
 

部分標籤說明

標籤,必填標籤,用來指定最基礎的日誌輸出級別

  • 標籤,添加append


標籤,通過使用該標籤指定日誌的收集策略

  • name屬性指定appender命名
  • class屬性指定輸出策略,通常有兩種,控制檯輸出和文件輸出,文件輸出就是將日誌進行一個持久化。ConsoleAppender將日誌輸出到控制檯

標籤,通過使用該標籤指定過濾策略

  • 標籤指定過濾的類型


標籤,使用該標籤下的標籤指定日誌輸出格式

標籤指定收集策略,比如基於時間進行收集

  • 標籤指定生成日誌保存地址,通過這樣配置已經實現了分類分天手機日誌的目標了
Logback配置文件這麼寫,TPS提高10倍

logback 高級特性異步輸出日誌

之前的日誌配置方式是基於同步的,每次日誌輸出到文件都會進行一次磁盤IO。採用異步寫日誌的方式而不讓此次寫日誌發生磁盤IO,阻塞線程從而造成不必要的性能損耗。異步輸出日誌的方式很簡單,添加一個基於異步寫日誌的appender,並指向原先配置的appender即可

  
 
  
 0
  
 256
  
 
 
 
  
 0
  
 256
  
 
 

異步輸出日誌性能測試

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

服務器硬件

  • CPU 六核
  • 內存 8G

測試工具

  • Apache Jmeter


同步輸出日誌

  • 線程數:100
  • Ramp-Up Loop(可以理解為啟動線程所用時間) :0
  • 可以理解為100個線程同時啟用

測試結果

Logback配置文件這麼寫,TPS提高10倍

重點關注指標Throughput【TPS】吞吐量:系統在單位時間內處理請求的數量,在同步輸出日誌中TPS為44.2/sec

異步輸出日誌

  • 線程數 100
  • Ramp-Up Loop:0

測試結果

Logback配置文件這麼寫,TPS提高10倍

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

異步日誌輸出原理

從logback框架下的Logger.info方法開始追蹤。一路的方法調用路徑如下圖所示:

Logback配置文件這麼寫,TPS提高10倍

異步輸出日誌中最關鍵的就是配置文件中ch.qos.logback.classic包下AsyncAppenderBase類中的append方法,查看該方法的源碼:

protected void append(E eventObject) {
 if(!this.isQueueBelowDiscardingThreshold() || !this.isDiscardable(eventObject)) {
 this.preprocess(eventObject);
 this.put(eventObject);
 }
 }

通過隊列情況判斷是否需要丟棄日誌,不丟棄的話將它放到阻塞隊列中,通過查看代碼,這個阻塞隊列為ArrayBlockingQueueu,默認大小為256,可以通過配置文件進行修改。

Logger.info(…)到append(…)就結束了,只做了將日誌塞入到阻塞隊列的事,然後繼續執行Logger.info(…)下面的語句了。

在AsyncAppenderBase類中定義了一個Worker線程,run方法中的關鍵部分代碼如下:

E e = parent.blockingQueue.take();
aai.appendLoopOnAppenders(e);

最主要的兩個方法就是encode和write方法,前一個法方會根據配置文件中encode指定的方式轉化為字節碼,後一個方法將轉化成的字節碼寫入到文件中去。所以寫文件是通過新起一個線程去完成的,主線程將日誌扔到阻塞隊列中,然後又去做其他事情了。

源碼

https://github.com/shuangyueliao/springboot-log


分享到:


相關文章: