Log4j的AsyncAppender能否提升性能?

    近日在寫多線程方面的東西,需要對多線程進行日誌監控就重新翻出了log4j,看到了log4j下居然還有一個AsyncAppender,異步記日誌?覺得挺不錯,網上搜了一下也有一些討論,JavaEye上也有很多討論。但是這個AsyncAppender到底能否提升日誌性能呢?我們還是先看看log4j本身文檔裏的性能測試說明吧,詳細測試數據見如下URL:http://www.ingrid.org/jajakarta/log4j/jakarta-log4j-1.1.3/docs/api/org/apache/log4j/performance/Logging.html

 

       由此可見AsyncAppender雖然是異步的,但是並不能提升性能,爲什麼呢?何謂異步?異步就是另外開了個線程用來專門記錄日誌,然而既然引入了多線程,線程間的同步開銷就不能不考慮了,看AsyncAppender的源代碼中到處充斥着synchronized就能看到了。

 

用獨立線程處理日誌會引入以下幾個問題:

  1. 中斷(如果一個阻塞在日誌操作的線程被中斷,還出現什麼情況?)
  2. 服務擔保(logger能保證成功加入隊列的消息都能在服務終止前被記錄麼?)
  3. 飢餓策略(當生產者記錄消息比logger線程的處理能力更快的時候會如何?)
  4. 服務的生命週期(如何關閉logger,如何就服務的狀態與生產者進行溝通?)

      由此的需要討論就是,爲什麼要使用異步?何時使用異步?如何使用異步?我們先來看同步和異步到底有何不同:

 

 

同步情況

各線程直接獲得輸出流進行輸出(線程間不需要同步)。

異步情況

  1. 各線程將日誌寫到緩存,繼續執行下面的任務(這裏是異步的)
  2. 日誌線程發現需要記日誌時獨佔緩存(與此同時各線程等待,此時各線程是被阻塞住的),從緩存中取出日誌信息,獲得輸出流進行輸出,將緩存解鎖(各線程收到提醒,可以接着寫日誌了)

       衆所周知,磁盤IO操作、網絡IO操作、JDBC操作等都是非常耗時的,日誌輸出的主要性能瓶頸也就是在寫文件、寫網絡、寫JDBC的時候。日誌是肯定要記的,而要採用異步方式記,也就只有將這些耗時操作從主線程當中分離出去才能真正的實現性能提升,也只有在線程間同步開銷小於耗時操作時使用異步方式才真正有效!現在我們接着分別來看看這幾種記錄日誌的方式。

將日誌記錄到本地文件

      同樣都是寫本地文件Log4j本身有一個buffer處理入庫,採用異步方式並不一定能提高性能(主要是如何配置好緩存大小);而線程間的同步開銷則是非常大的!因此在使用本地文件記錄日誌時不建議使用異步方式。

將日誌記錄到JMS

      JMS本身是支持異步消息的,如果不考慮JMS消息創建的開銷,也不建議使用異步方式。

將日子記錄到SOCKET

      將日誌通過Socket發送,純網絡IO操作不需要反饋,因此也不會耗時

將日誌記錄到數據庫

      衆所周知JDBC是幾種方式中最耗時的:網絡、磁盤、數據庫事務,都使JDBC操作異常的耗時,在這裏採用異步方式入庫倒是一個不錯的選擇。

將日誌記錄到SMTP

      同JDBC

 

性能測試

      在同步和異步方式下,同時起1000個線程,分別測試記錄到文件和數據庫中的時間消耗,每類測試連測5遍避免誤差。

 

測試環境

1、WINDOWS XP SP2、JDK 1.5、ORACLE 9i2(本地)、log4j-1.2.14.jar

2、MutiTest.java用來測試同步方式,讀取配置文件:log4j.properties

     MutiTestAsyncAppender.java用來測試異步方式,讀取配置文件:log4j.xml

3、每次測試先刪除日誌文件或清空表,確保測試獨立性

 

 

測試結果如下:

FileAppender
同步方式 最晚線程執行時間 最早線程執行時間 消耗時間
1 1.23209E+12 1.23209E+12 156  
2 1.23209E+12 1.23209E+12 172  
3 1.23209E+12 1.23209E+12 172  
4 1.23209E+12 1.23209E+12 188  
5 1.23209E+12 1.23209E+12 157  
         
異步方式 最晚線程執行時間 最早線程執行時間 消耗時間
1 1.23209E+12 1.23209E+12 157  
2 1.23209E+12 1.23209E+12 188  
3 1.23209E+12 1.23209E+12 156  
4 1.23209E+12 1.23209E+12 187  
5 1.23209E+12 1.23209E+12 172  
         
JDBCAppender
同步方式 最晚線程執行時間 最早線程執行時間 消耗時間
1 1.23209E+12 1.23209E+12 281  
2 1.23209E+12 1.23209E+12 172  
3 1.23209E+12 1.23209E+12 172  
4 1.2321E+12 1.2321E+12 171  
5 1.2321E+12 1.2321E+12 203  
         
異步方式 最晚線程執行時間 最早線程執行時間 消耗時間
1 1.2321E+12 1.2321E+12 94  
2 1.2321E+12 1.2321E+12 94  
3 1.2321E+12 1.2321E+12 94  
4 1.2321E+12 1.2321E+12 94  
5 1.2321E+12 1.2321E+12 125  

結論

      由以上測試結果可以得出異步方式記錄日誌並不是什麼情況下都能提升性能的,相反由於線程間的同步開銷,甚至可能降低性能;只有像在JDBC操作或是SMTP之類的記錄耗時比較長的情況下,使用異步入庫方式纔是個好選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章