Filebeat 收集日誌的那些事兒

360雲端計算發表於2020-06-18

女主宣言






最近因為雲原生日誌收集的需要,我們打算使用Filebeat作為容器日誌收集工具,並對其進行二次開發,因此筆者將談談 Filebeat 收集日誌的那些事兒。本文不涉及過具體的原始碼分析,希望通過閱讀您可以瞭解filebeat的基本使用方法和原理,姑且算是filebeat的入門吧。

PS:豐富的一線技術、多元化的表現形式,盡在“360雲端計算”,點關注哦!

1

前言

開源日誌收集元件眾多,之所以選擇Filebeat,主要基於以下幾點:

  • 功能上能滿足我們的需求:收集磁碟日誌檔案,傳送到Kafka叢集;支援多行收集和自定義欄位等;

  • 效能上相比執行於jvm上的logstash和flume優勢明顯;

  • Filebeat基於golang 技術棧,二次開發對於我們來說有一定的技術積累;

  • 部署方便,沒有第三方依賴;

2

Filebeat 能做什麼

簡單來說Filebeat就是資料的搬運工,只不過除了搬運還可以對資料作一些深加工,為業務增加一些附加值。

  • Filebeat可以從多種不同的上游input 中接受需要收集的資料,其中我們最常用的就是 log input,即從日誌中收集資料;

  • Filebeat對收集來的資料進行加工,比如:多行合併,增加業務自定義欄位,json等格式的encode; 

  • Filebeat將加工好的資料傳送到被稱為output的下游,其中我們最常用的就是 Elasticsearch 和 Kafka;

  • Filebeat具有ACK反饋確認機制,即成功傳送到output後,會將當前進度反饋給input, 這樣在程式重啟後可以斷點續傳;

  • Filebeat在傳送output失敗後,會啟動retry機制,和上一次ACK反饋確認機制一起,保證了每次訊息至少傳送一次的語義;

  • Filebeat在傳送output時,由於網路等原因發生阻塞,則在input上游端會減慢收集,自適應匹配下游output的狀態。

Filebeat 收集日誌的那些事兒

一圖以蔽之。

3

Filebeat 背後的“老大”

說到Filebeat,它其實只是 beats 家族眾多成員中的一個。除了Filebeat, 還有很多其他的beat小夥伴:

beat
功能
Filebeat收集日誌檔案
Metricbeat收集各種指標資料
Packetbeat收集網路資料包
Auditbeat收集審計資料
Heartbeat收集服務執行狀態監測資料
...
...

如果你願意的話,你也可以按照beat的規範來寫自己的beat。

能實現以上這些beat,都離不開beats家族真正的“老大”—— libbeat, 它是beat體系的核心庫。我們接下來看一下libbeat到底都做了些什麼:

  • libbeat提供了publisher元件,用於對接input;

  • 收集到的資料在進入到libbeat後,首先會經過各種 processor的加工處理,比如過濾新增欄位,多行合併等等;

  • input元件通過publisher元件將收集到的資料推送到publisher內部的佇列;

  • libbeat本身實現了前面介紹過的多種output, 因此它負責將處理好的資料通過output元件傳送出去;

  • libbeat本身封裝了retry的邏輯;

  • libbeat負責將ACK反饋通過到input元件 ;

由此可見,大部分活兒都是libbeat來做,當“老大”不容易啊~。

input僅需要兩件事:

  • 從不同的介質中收集資料後投遞給libbeat; 

  • 接收libbeat反饋回來的ACK, 作相應的持久化;

4

Filebeat 的簡單使用示例

Filebeat本身的使用很簡單,我們只需要按需寫好相應的input和output配置就好了。下面我們以一個收集磁碟日誌檔案到Kafka叢集的例子來講一下。

1. 配置inputs.d目錄

在filebeat.yml新增如下配置,這樣我們可以將每一種等收集的路徑寫在單獨的配置檔案裡,然後將這些配置檔案統一放到inputs.d目錄,方便管理





filebeat.config.inputs:enabled: truepath: inputs.d/*.yml

2. 在inputs.d目錄下建立test1.yml,內容如下









  - type: log                       # Change to true to enable t    enabled: true                   # Paths that should be crawl    paths:                            - /home/lw/test/filebeat/*.log    fields:                       log_topic: lw_filebeat_t_2

這個配置說明會收集所有匹配/home/lw/test/filebeat/*.log的檔案內容,並且我們新增了一個自定義的filed:  log_topic: lw_filebeat_t_2, 這個我們後面會講到。

3. 在filebeat.yml中配置kafka output:












output.kafka:                                                                hosts: ["xxx.xxx.xxx.xxx:9092", "xxx.xxx.xxx.xxx:9092", "xxx.xxx.xxx.xxx:9092"] version: 0.9.0.1                                                           topic: '%{[fields.log_topic]}'                                             partition.round_robin:                                                     reachable_only: true                                                     compression: none                                                          required_acks: 1                                                           max_message_bytes: 1000000                                                 codec.format:                                                                    string: '%{[host.name]}-%{[message]}'

其中:

  • hosts是kafka叢集的broker list;

  • topic: '%{[fields.log_topic]}'  : 這項指定了我們要寫入kafka叢集哪個topic, 可以看到它實現上是引用了上面test.yml配置中我們自定義的filed欄位,通過這種方式我們就可以將收集的不同路徑的資料寫入到不同的topic中,但是這個有個限制就是隻能寫到一個kafka叢集,因為當前版本的filebeat不允許同時配置多個output。

  • codec.format: 指定了寫入kafka叢集的訊息格式,我們在從日誌檔案中讀取的每行內容前面加上了當前機器的hostname。

啟動就很簡單了,filebeat和filebeat.yml, inputs.d都在同一目錄下,然後 ./filebeat run就好了。


filebeat本身有很多全域性的配置,每種input和output又有很多各自的配置,關乎日誌收集的記憶體使用,是不是會丟失日誌等方方面面,大家在使用時還需要仔細閱讀,這裡不贅述。


5

Log input 是如何從日誌檔案中收集日誌的

input的建立:

  • 根據配置檔案內容建立相應的Processors, 用於前面提到的對從檔案中讀取到的內容的加工處理;

  • 建立Acker, 用於持久化libbeat反饋回來的收集傳送進度;

  • 使用libbeat提供的Pipeline.queue.Producer建立producer,用於將處理好的檔案內容投遞到libbeat的內部佇列;

收集檔案內容:

  • input會根據配置檔案中的收集路徑(正則匹配)來輪詢是否有新檔案產生,檔案是否已經過期,檔案是否被刪除或移動;

  • 針對每一個檔案建立一個Harvester來逐行讀取檔案內容;

  • 將檔案內容封裝後通過producer傳送到libbeat的內部佇列;

Filebeat 收集日誌的那些事兒

處理檔案重新命名,刪除,截斷:

  • 獲取檔案資訊時會獲取檔案的device id + indoe作為檔案的唯一標識;

  • 前面我們提過檔案收集進度會被持久化,這樣當建立Harvester時,首先會對檔案作openFile, 以 device id + inode為key在持久化檔案中檢視當前檔案是否被收集過,收集到了什麼位置,然後斷點續傳;

  • 在讀取過程中,如果檔案被截斷,認為檔案已經被同名覆蓋,將從頭開始讀取檔案;

  • 如果檔案被刪除,因為原檔案已被開啟,不影響繼續收集,但如果設定了CloseRemoved, 則不會再繼續收集;

  • 如果檔案被重新命名,因為原檔案已被開啟,不影響繼續收集,但如果設定了CloseRenamed , 則不會再繼續收集;

6

日誌如何被髮送

傳送流程簡述:

  • input將日誌內容寫入libbeat的內部佇列後,剩下的事件就都交由libbeat來做了;

  • libbeat會建立consumer, 復現作libbeat的佇列裡消費日誌event, 封裝成Batch物件;

  • 針對每個Batch物件,還會建立ack Channel, 用來將ACK反饋資訊寫入這個channel; 

  • Batch物件會被源源不斷地寫入一個叫workQueue的channel中;

  • 以kafka output為例,在創kafka output時首先會建立一個outputs.Group,它內部封裝了一組kafka client, 同時啟動一組goroutine; 

  • 上面建立的每個goroutine都從workQueue佇列裡讀取Batch物件,然後通過kafka client傳送出去,這裡相當於多執行緒併發讀佇列後傳送;

  • 若kafka client傳送成功,寫入資訊到ack channel, 最終會通過到input中;

  • 若kafka client傳送失敗,啟動重試機制;

Filebeat 收集日誌的那些事兒

重試機制:

  • 以kafka output為例,如果msg傳送失敗,通過讀取 ch <-chan *sarama.ProducerError可以獲取到所有傳送失敗的msg;

  • 針對ErrInvalidMessage, ErrMessageSizeTooLarge 和 ErrInvalidMessageSize這三種錯誤,無需重發;

  • 被髮送的 event都會封裝成 Batch, 這裡重發的時候也是呼叫Batch.RetryEevnts; 

  • 最後會呼叫到retryer.retry將需要重新的events再次寫入到上圖中黃色所示的 workQueue中,重新進入傳送流程;

  • 關於重發次數,可以設定max retries, 但從程式碼中看這個max retries不起作用,目前會一直重試,只不過在重發次數減少到為0時,會挑選出設定了Guaranteed屬性的event來傳送; 

  • 如果重發的events數量過多,會暫時阻塞住從正常傳送流程向workQueue中寫入資料,優先傳送需要重發的資料;

7

後記

 
在本文裡,我們沒有深入到原始碼層次,為了講清filebeat運作的原理,我們也忽略了一些實現細節,後續將會從原始碼層面作進一步剖析。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69966971/viewspace-2699089/,如需轉載,請註明出處,否則將追究法律責任。

相關文章