Filebeat如何保證在日誌檔案被切割(或滾動rolling)時依然正確讀取檔案
我們的日誌收集系統使用Filebeat來收集日誌檔案,部署時並沒有多想,只配置了一下監控的日誌檔名。上線幾個月,日誌監控從沒出過問題。後來想想其實這裡面有很多點需要考慮的,沒出問題真是感謝Filebeat預設配置下想的就很周全。
業務系統使用logback作為日誌框架。通過檢視原始碼,發現logback日誌切割用的是JDK裡File#renameTo()
方法。如果該方法失敗,就再嘗試使用複製資料的方式切割日誌。查詢該方法相關資料得知,只有當原始檔和目標目錄處於同一個檔案系統、同volumn(即windows下的C, D盤)下該方法才會成功,切不會為重新命名的後的檔案分配新的inode值。也就是說,如果程式裡一直儲存著該檔案的描述符,那麼當程式再寫日誌時,就會向重新命名後的檔案中寫。那麼問題來了,filebeat是會一直開啟並儲存檔案描述符的,那麼它是怎麼得知日誌被切割這件事的呢?
如果只用當前檔案描述符一路監控到天黑的話,那麼當logback把日誌重新命名後,filebeat仍然會監控重新命名後的日誌,新建立的日誌檔案就看不到了。實際上,filebeat是通過close_inactive
和scan_frequency
兩個引數(機制)來應對這種情況的:
close_inactive
該引數指定當被監控的檔案多長時間沒有變化後就關閉檔案控制代碼(file handle)。官方建議將這個引數設定為一個比檔案最大更新間隔大的值。比如檔案最長5s更新一次,那就設定成1min。預設值為5min.scan_frequency
該引數指定Filebeat搜尋新檔案的頻率(時間間隔)。當發現新的檔案被建立時, Filebeat會為它再啟動一個 harvester 進行監控。預設為10s。
綜合以上兩個機制,當logback完成日誌切割後(即重新命名),此時老的harvester仍然在監控重新命名後的日誌檔案,但是由於該檔案不會再更新,因此會在close_inactive
時間後關閉這個檔案的 harvester。當scan_frequency
時間過後,Filebeat會發現目錄中出現了新檔案,於是為該檔案啟動 harvester 進行監控。這樣就保證了切割日誌時也能不丟不重的傳輸資料。(不重是通過為每個日誌檔案儲存offset實現的)