logback中常用的appender有ch.qos.logback.core.ConsoleAppender和ch.qos.logback.core.rolling.RollingFileAppender兩種,前者作為控制台輸出在生產環境中可關閉。后者滾動文件輸出,作為磁盤IO來說,在高並發場景下必然容易作為瓶頸,所幸,logback提供了AsyncAppender異步輸出方式來提高性能。
實現異步有很多方式,Logback用的是隊列+多線程,類似用隊列實現了生產者消費者模式。使用方法是只需要在logback.xml配置一下就好:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- %m輸出的信息,%p日志級別,%t線程名,%d日期,%c類的全名,%i索引【從數字0開始遞增】,,, --> <!-- appender是configuration的子節點,是負責寫日志的組件。 --> <!-- ConsoleAppender:把日志輸出到控制台 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>[ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- RollingFileAppender:滾動記錄文件,先將日志記錄到指定文件,當符合某個條件時,將日志記錄到其他文件 --> <appender name="syslog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- <File>logs/log.log</File> --> <!-- rollingPolicy:當發生滾動時,決定 RollingFileAppender 的行為,涉及文件移動和重命名。 --> <!-- TimeBasedRollingPolicy: 最常用的滾動策略,它根據時間來制定滾動策略,既負責滾動也負責出發滾動 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 活動文件的名字會根據fileNamePattern的值,每隔一段時間改變一次 --> <!-- 文件名:log/sys.2017-12-05.0.log --> <fileNamePattern>logs/log-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>60MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <!-- pattern節點,用來設置日志的輸入格式 --> <pattern> [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n </pattern> <!-- 記錄日志的編碼 --> <charset>UTF-8</charset> </encoder> </appender>
<appender name="ASYNC_ROLLING_FILE" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>256</queueSize> <!-- 隊列長度,默認256-->
<includeCallerData>true</includeCallerData>
<appender-ref ref="syslog"/>
</appender>
<!-- 控制台輸出日志級別 --> <root level="INFO"> <!-- <appender-ref ref="STDOUT"/> --> <appender-ref ref="ASYNC_ROLLING_FILE"/> </root> </configuration>
需要注意的是,為了保證性能,AsyncAppender會在隊列長度達到80%的時候丟棄error以外的正常日志,而隨意加大隊列長度進行緩沖又會影響性能和加大日志的延遲,所以這個又是一個需要根據實際情況而具體問題具體分析的指標。
屬性名 |
類型 |
默認值 |
描述 |
queueSize |
int |
256 |
內置BlockingQueue的最大容量 |
discardingThreshold |
int |
-1 |
默認情況下,當blockingQueue的容量高於閾值時(80%),會丟棄ERROR以下級別的日志,如果不希望丟棄日志(既每次都是全量保存),那可以設置為0,但是如果隊列滿的時候,會丟棄所有插入隊列的日志信息,所以建議設置為-1(默認值)。 如正常日志可以丟棄,那可以極大的提升性能,並保存關鍵的ERROR日志。
|
includeCallerData |
boolean |
false |
提取調用者數據的代價是相當昂貴的。為了提升性能,默認情況下,當event被加入到queue時,event關聯的調用者數據不會被提取。默認情況下,只有"cheap"的數據,如線程名。比如日志中的代碼行號如果需要輸出則應將該值設為true。實測includeCallerData=true會帶來一定性能下降,但高並發下仍遠比同步日志方式的tps要高。 |
經實測,在我的window系統筆記本,1000並發壓測同樣的springboot框架,AsyncAppender可帶來300tps到2000tps的提升。 而在linux服務器下測試結果對比更加明顯,2000並發下的600tps一躍至14000tps !
<includeCallerData>true</includeCallerData>