集中式日志分析平臺 - ELK Stack - 關于 Logstash 的持久化隊列

概括下本文的內容:

我們可以使用 Logstash 的持久化隊列技術盡量保證數據可靠傳輸至 output;

適用場景:傳輸可靠性要求稍低的場景下(和 Kafka 類比),替換架構中的 Kafka 或者加固 Logstash 本身的可靠性,因為即使 queue.checkpoint.writes:1,也有可能因為磁盤故障(檢查點文件 和 queue 文件同時損壞)丟至多 1 條數據,核心的問題是在于沒有多副本和選舉相關的實現;

Deliver 策略:at-least-once;

默認情況下,Logstash在 pipeline stages(inputs → pipeline workers)之間使用內存有界隊列來緩沖事件。 這些內存中隊列的大小是固定的,不可配置。 如果 Logstash 遇到臨時機器故障,則內存中隊列的內容將丟失。 臨時機器故障是指 Logstash 或其主機異常終止但能夠重新啟動的情況。

為了防止異常終止期間的數據丟失,Logstash 具有持久性隊列功能,將消息隊列存儲在磁盤上。 持久隊列在 Logstash 中提供數據的持久性。

持久隊列對于需要大型緩沖區的 Logstash 部署也很有用。 換言之,可以啟用持久性隊列來緩存磁盤上的事件而無需使用較重的組件(如 Redis,RabbitMQ 或 Apache Kafka)來實現緩沖的發布訂戶模型。

總而言之,啟用持久隊列的好處如下:

  • 處理突發事件,而不需要像 Redis 或 Apache Kafka 這樣的外部緩沖機制;
  • 在正常關機期間以及 Logstash 異常終止時,提供 at-least-once 傳輸保證,防止消息丟失。 如果 Logstash 在事件傳遞時(我理解是事務執行過程中,in-flight)重新啟動,Logstash 將嘗試傳遞存儲在持久性隊列中的消息,直到傳送成功至少一次。

持久隊列的限制

以下是持久隊列功能未解決的問題:

  • 不使用 request-response 協議的 input 插件無法避免數據丟失。 例如:tcp,udp,zeromq push + pull和許多其他輸入沒有機制來確認 receipt 的發送方。 具有確認功能的插件(如 beats 和 http)受到此隊列的良好保護。
  • 它不會處理永久性的機器故障,如磁盤損壞,磁盤故障和機器丟失,持續到磁盤的數據不會被復制。

持久隊列如何工作

隊列位于同一進程的 input 和 filter 階段之間:

input → queue → filter + output

當 input 有事件準備好處理時,它將事件寫入隊列。當寫入隊列成功時, input 可以向其數據源發送 ack。

Logstash 只會在 filter 和 output 完成事件處理后,確認事件已完成。隊列保留 pipeline 已處理的事件的記錄。事件被記錄為已處理(acked),當且僅當事件已由 Logstash pipeline 完全處理。

Ack 這意味著事件已由所有配置的 filter 和 output 處理。例如,如果只有一個到 Elasticsearch的輸出,當 Elasticsearch output 已成功將此事件發送到 Elasticsearch 時,事件將被 ack。

在正常關機(Kill 或 SIGTERM)期間,Logstash 將停止從隊列中讀取,并完成由 filter 和 output 處理的 in-flight 事件。重新啟動后,Logstash 將恢復處理持久性隊列中的事件以及從 input 接受新事件。

如果 Logstash 異常終止,任何 in-flight 事件將不會被 ack,并且當 Logstash 重新啟動時將被 filter 和 output 重新處理。 Logstash 分批處理事件,因此對于任何給定的批處理,有可能已經成功完成了該批次,但是在發生異常終止時不能被記錄為已確認,所以可以解釋為什么會有重復發送。

如何配置持久化隊列

要配置持久性隊列,可以在Logstash設置文件中指定以下選項:

queue.type:指定持久化以啟用持久性隊列。默認情況下,持久隊列被禁用(默認:queue.type:memory)。
path.queue:數據文件將被存儲的目錄路徑。默認情況下,文件存儲在path.data/queue中。
queue.page_capacity:隊列頁面的最大大小(以字節為單位)。隊列數據由僅附加文件稱為“頁面”組成。默認大小為250MB。更改此值不太可能具有性能優勢。
queue.max_events:隊列中允許的最大事件數。默認值為0(無限制)。該值在內部用于Logstash測試。
queue.max_bytes:隊列的總容量,以字節為單位。默認值為1024MB(1GB)。確保磁盤驅動器的容量大于此處指定的值。
如果同時指定了queue.max_eventsqueue.max_bytes,則Logstash將使用首先達到的條件。。

還可以指定控制檢查點文件何時更新的選項(queue.checkpoint.acksqueue.checkpoint.writes)。

示例配置:

queue.type:persisted
queue.max_bytes:4gb

處理 Back Pressure

當隊列已滿時,Logstash 會對 input 端施加壓力,以阻止流入 Logstash 的數據。這種機制有助于 Logstash 在 input 階段控制數據流量,而不會向比如 Elasticsearch 類似的 output 端瘋狂輸出。

使用queue.max_bytes設置配置磁盤上隊列的總容量。以下示例將隊列的總容量設置為8gb:

queue.type:persisted
queue.max_bytes:8gb

指定這些設置后,Logstash 將緩存磁盤上的事件,直到隊列的大小達到8gb。當隊列充滿 unACKed 的事件,并且已達到大小限制時,Logstash 將不再接受新的事件。

每個 input 單獨處理 Back Pressure。例如,當 beats input 遇到 back pressure 時,它不再接受新連接并等待,直到隊列有空間來接受更多的事件。filter 和 output 階段完成處理隊列中的現有事件并確認它們后,Logstash 會自動開始接受新的事件。

控制 Durability

Durability 是存儲寫入的一種特性,可確保數據在寫入后可用。

當啟用持久性隊列功能時,Logstash 會將事件存儲在磁盤上。 Logstash以稱為檢查點的機制提交到磁盤。

為了討論 Durability,我們需要介紹一些關于如何實現持久隊列的細節。

首先,隊列本身是一組 pages。有兩種 page:head page 和 tail page。head page 是新事件寫入的地方,只有一個。當 head page 達到上限(參見queue.page_capacity)時,它將成為一個 tail page,并創建一個新的 page。tail page 是不修改的,head page 是只能追加內容的。其次,隊列將記錄自己的詳細信息(pages,ack 確認信息等)記錄在一個名為checkpoint 文件的單獨文件中。

記錄檢查點時,Logstash將:

  • 在 head page 上調用 fsync。
  • 原子地寫入隊列的當前狀態至磁盤。

以下設置可用于調整持久性:

  • queue.checkpoint.writes:Logstash 在寫入指定條數事件后,進行 checkpoint。目前,一個事件計為一個寫入,但這可能會在將來的版本中更改。
  • queue.checkpoint.acks:Logstash 在指定條數事件 acked 后,進行 checkpoint。此配置用來控制 Logstash 處理(filter + output)環節的 Durability。

磁盤寫入具有資源成本。調整上述值或更高值將會調整 durability。例如,如果您想要所有 input 事件具備最高 durability,可以設置queue.checkpoint.writes:1

檢查點的過程是原子的,這意味著如果成功,將保存文件的任何更新。

如果 Logstash 終止,或者如果存在硬件級別故障,那么在持久性隊列中緩存但尚未檢查點的任何數據都將丟失。為了避免這種可能性,您可以設置 queue.checkpoint.writes:1,但請記住,此設置會嚴重影響性能。

磁盤垃圾回收

在磁盤上,隊列存儲為一組 page,其中每個 page 是一個文件。 每個 page 最多可以是 queue.page_capacity的大小。 在該 page 中的所有事件都被確認之后,page 被刪除(垃圾回收)。 如果較舊的 page 至少有一個尚未確認的事件,則整個 page 將保留在磁盤上,直到該 page 中的所有事件成功處理。 包含未處理事件的每個 page 將對queue.max_bytes字節大小進行計數。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容