返回文章列表

Fluentd 效能調校與擴充套件性最佳化

本文探討 Fluentd 的效能調校與擴充套件性最佳化策略,涵蓋工作程式、資源管理、多節點橫向擴充套件、高用性佈署以及與微服務架構的整合。文章詳細說明瞭如何利用工作執行緒、Fan-in/Fan-out 模式、Forward 外掛等技術,提升 Fluentd

DevOps 系統管理

Fluentd 作為一款開源的日誌收集器,在處理大量日誌資料時,效能和擴充套件性是關鍵。本文將探討如何透過調整 Fluentd 的設定,例如工作程式數量、緩衝區大小和輸出外掛的執行緒數量,來最佳化其效能。此外,文章還會介紹如何使用多個 Fluentd 節點進行橫向擴充套件,以分散工作負載並提高系統的容錯能力。更進一步,我們將探討如何利用 Forward 外掛實作 Fan-in 和 Fan-out 模式,以及如何在微服務架構中有效地佈署和管理 Fluentd。最後,文章將提供一些實用的組態範例和最佳實踐,幫助讀者更好地理解和應用這些技術。

效能與擴充套件

在前面的章節中,我們只使用了一個Fluentd例項。然而,在現實世界中,特別是在分散式、虛擬化和容器化的環境中,通常需要多個例項。除了考慮分散式佈署外,我們還需要透過擴充套件(增加CPU或記憶體以支援更多程式和執行緒)和擴充套件(佈署額外的伺服器例項以透過負載平衡分配工作負載)來滿足波動的需求。企業級應用需要具備彈性,以處理故障和災難場景。為了提供良好的可用性,我們至少應該佈署一個主動伺服器和一個備用伺服器,並保持組態檔案的同步。這樣,當主動伺服器發生故障時,可以快速啟動備用伺服器(主動-被動模式)。在更為嚴苛的情況下,需要採用主動-主動佈署模式,將伺服器分散在多個資料中心,這是一種非常常見的佈署模式。在企業級應用中,單一伺服器解決方案是非常罕見的。

本章將探討可用的技術和功能,以使用工作程式和資源管理來擴充套件Fluentd,並使用多個Fluentd節點進行橫向擴充套件。透過橫向擴充套件,我們還可以提高彈性。由於Fluentd只需要很小的資源佔用,我們甚至可以在桌面上實作一些擴充套件技術。

使用執行緒和程式進行擴充套件

擴充套件Fluentd佈署的一種方法是利用其產生額外子程式(工作程式)的能力,以充分利用現代機器擁有多個CPU核心的事實。在組態任何擴充套件之前,瞭解Fluentd如何受到其Ruby實作的影響以及Ruby如何處理執行緒是非常重要的。Ruby具有全域性直譯器鎖(GIL),這意味著當一個程式不是I/O密集型時,它將阻塞其他作業(有關GIL和Ruby執行緒的更多詳細資訊,請參見附錄E)。因此,任何計算密集型任務最好在單獨的作業系統程式中執行,並利用作業系統提供更有效的資源分享。一些外掛會為您做到這一點(例如,使用gzip壓縮時的AWS S3外掛),但並非所有外掛都如此,因此我們必須非常注意這一點,以進行效能最佳化。如果沒有這種分離,Fluentd程式將有效地被鎖定,直到程式完成或釋放執行緒為止。通常,Fluentd作為日誌事件路由的工具,更可能是I/O密集型的——無論是根據網路的I/O還是最終的儲存(即使是間接透過物理儲存來實作某種資料函式庫)。

Fluentd透過啟動單獨的程式(稱為工作程式)來解決執行緒鎖定約束。預設情況下,Fluentd有一個工作程式和一個控制器程式,但我們可以組態工作程式的數量。這有效地利用了作業系統通常將程式分配給CPU並在程式之間進行切換的事實,以給予它們公平的CPU計算能力。如圖7.1所示,每個工作程式將根據組態拾取並執行源、過濾器和匹配指令。

注意

當程式數量超過CPU核心數量時,處理器將在程式之間進行切換。更多的程式意味著更多的切換。切換活動需要少量的努力。如果您有太多正在執行的程式,您將花費更多的精力在切換程式上,而不是執行任何有意義的工作。


### 圖示:Fluentd 工作程式示意圖
此圖示描述了 Fluentd 如何利用多個工作程式來處理日誌事件。

內容解密:

圖7.1展示了Fluentd如何利用多個工作程式來提高處理日誌事件的能力。每個工作程式都可以獨立地執行源、過濾器和匹配指令,從而充分利用多核CPU的優勢。

# 示例組態:使用多個工作程式
<system>
  workers 4 # 設定工作程式數量為4
</system>

內容解密:

上述組態示例展示瞭如何設定Fluentd使用4個工作程式。透過增加工作程式的數量,Fluentd可以更好地利用多核CPU,提高日誌事件的處理能力。這種組態對於處理大量日誌資料的場景非常有用。

本章涵蓋了以下主題:

  • 使用工作程式最佳化Fluentd以最大化資源利用
  • 採用扇入和扇出模式佈署Fluentd
  • 使用佈署模式進行擴充套件
  • 實作高用性和佈署
  • 將Fluentd與微服務模式結合使用

透過本章的學習,我們將能夠深入瞭解如何擴充套件Fluentd以滿足企業級需求,並掌握相關的最佳實踐。

使用工作執行緒(Workers)進行擴充套件

在 Fluentd 中,使用多個工作執行緒(workers)可以提升處理日誌事件的能力。預設情況下,Fluentd 會根據設定的工作執行緒數量來分配資源。

觀察工作執行緒的運作

要了解工作執行緒的行為,最直接的方法是組態一個範例並觀察實際的運作結果。我們將建立多個工作執行緒,並將虛擬來源外掛(dummy source plugin)分配給這些工作執行緒。

組態多個工作執行緒

system 指令中,我們可以透過設定 workers 屬性來定義工作執行緒的數量。同時,我們使用 <worker x> 指令來指定每個工作執行緒的組態。


### 組態範例
以下是一個組態範例,展示瞭如何定義四個工作執行緒並分配不同的來源外掛給它們。

fluentd 組態檔案

<system>
  log_level info
  workers 4
</system>

<worker 0>
  <source>
    @type dummy
    tag w0
    auto_increment_key counter
    dummy {"hello":"from worker 0"}
  </source>
</worker>

<worker 1-2>
  <source>
    @type dummy
    tag w1
    auto_increment_key counter
    dummy {"hello":"from worker 1-2"}
  </source>
</worker>

<worker 3>
  <source>
    @type dummy
    tag w2
    auto_increment_key counter
    dummy {"hello":"from worker 3"}
  </source>
</worker>

<source>
  @type dummy
  tag w-any
  auto_increment_key counter
  dummy {"hello":"from workerless"}
</source>

<filter *>
  @type record_transformer
  enable_ruby
  <record>
    worker_id ${ENV['SERVERENGINE_WORKER_ID']}
  </record>
</filter>

<match *>
  @type stdout
</match>

#### 內容解密:

此組態定義了四個工作執行緒,並將不同的虛擬來源外掛分配給它們。每個工作執行緒將產生不同的日誌事件,並透過 record_transformer 過濾器新增 worker_id 到日誌事件中。最終,日誌事件將被輸出到控制檯。

檢視程式資訊

要檢視 Fluentd 的程式資訊,可以使用以下命令:

  • Windows:tasklist /fi "IMAGENAME eq Ruby.exe"
  • Linux:ps -ef | grep ruby

這些命令將顯示 Ruby 的程式資訊,包括 Fluentd 的程式。由於我們組態了四個工作執行緒,因此應該會看到五個程式(四個工作執行緒和一個控制程式)。

#### 內容解密:

使用 process_name 屬性可以在 <system> 組態中自定義程式名稱,使程式更容易被識別。

結束 Fluentd 程式

要結束 Fluentd 的程式,可以使用以下命令:

  • Windows:taskkill /IM Ruby.exe /F
  • Linux:pkill -f ruby

需要注意的是,如果有其他 Ruby 程式正在執行,需要手動隔離並結束 Fluentd 的程式。

結果分析

執行 Fluentd 後,檢視控制檯輸出結果,可以觀察到以下現象:

  • 具有 w-any 標籤的日誌事件將出現在任意 worker_id 的輸出中。
  • w0w1w2 相關的日誌事件將分別對應到特定的 worker_id

工作執行緒的限制

在使用工作執行緒時,需要考慮一些限制,例如資源分享的問題。如果多個工作執行緒寫入同一個檔案,可能會導致檔案損壞或日誌事件丟失。為瞭解決這個問題,可以在檔案路徑中包含 worker_id,例如:path "logs/#{worker_id}/${tag}/%Y/%m/%d/logfile.out"

#### 內容解密:

此設定可以確保每個工作執行緒寫入不同的檔案,避免資源衝突。

效能調校與擴充套件性最佳化

在處理大量日誌事件時,Fluentd 的效能和擴充套件性是至關重要的。本章將探討如何透過調整設定來最佳化 Fluentd 的效能,以及如何透過擴充套件來處理日益增長的日誌量。

分享埠與工作程式管理

在多工作程式的環境下,分享埠的管理是一個挑戰。當外掛使用伺服器輔助外掛或原生支援埠分享時,可以實作埠的分享。例如,forward 外掛就原生支援埠管理。由於每個程式不能使用相同的埠,因此需要一個可靠的機制來選擇合適的埠。

伺服器輔助外掛的埠分配

當使用伺服器輔助外掛時,它會為每個工作程式分配連續的埠。例如,如果指定使用四個工作程式,並定義了一個 monitor_agent 外掛,其埠設定為 30000,那麼工作程式 0 使用埠 30000,工作程式 1 使用 30001,依此類別推。確保使用的埠之間有足夠的間隔,以避免因演算法將相同的埠分配給不同外掛例項而導致的埠衝突。

控制輸出外掛執行緒

輸出外掛的執行緒行為可以透過 num_threads 屬性進行控制。預設情況下,該值為 1。增加執行緒數量可以提高效能,因為它允許在執行緒被阻塞時進行上下文切換,從而更有效地利用任何內部延遲。但是,這並不能克服 GIL(Global Interpreter Lock)的限制。

何時增加輸出外掛的執行緒數量

考慮在輸出外掛的組態中分配工作負載到多個不同的目的地時增加執行緒數量。這樣,當一個執行緒正在工作或等待 I/O 操作完成時,下一個執行緒可以繼續工作,從而提高整體效能。

調校執行緒使用的挑戰

調校執行緒使用是一項挑戰,因為需要了解程式的效能特徵,以便識別執行緒等待 I/O 操作完成的潛力。同時,也需要考慮執行緒切換的開銷。因此,正確地調校執行緒通常需要執行真實的工作負載並測量效能,然後比較不同執行緒組態下的測試結果,以確定效能開始下降的點。

記憶體管理最佳化

另一個可以調校的領域是 Ruby VM 層。這涉及到調整垃圾回收和記憶體區塊分配。要在這個層次上進行調校,需要對 Ruby 的實作細節有深入的瞭解,以及使用工具來分析組態對效能的影響。

擴充套件與工作負載遷移

除了緩衝區和執行緒、程式的調校之外,擴充套件選項還包括工作負載的分佈。可以透過以下方式實作:

  • 將日誌事件饋送到像 Kafka 這樣的事件流技術中。
  • 使用 Redis 或 Memcached 等工具進行大規模快取。
  • 利用 Fluentd 將日誌事件傳遞給其他 Fluentd 節點的能力。

這使得我們可以將工作負載遷移到專門的 Fluentd 節點上,無論是透過 fan-out(當工作負載需要額外的計算能力時)還是 fan-in(將多個小節點的日誌事件集中到一兩個 Fluentd 例項中)。

Fan-in/日誌聚合與整合

在容器化環境中,佈署多個 Fluentd 和 Fluent Bit 節點以支援集中器網路(fan-in)是最常見的場景。這種模型描述了兩個或多個 Fluentd 節點收集日誌事件並將其傳遞給中央 Fluentd/Fluent Bit 例項。

Fan-in 與應用架構和佈署

在處理高容量或需要高彈性的環境中,應用軟體通常會分佈在多個伺服器上。可以組態伺服器,使單個 Fluentd 例項可以存取每個伺服器的日誌檔案,或者在每個伺服器上佈署一個 Fluentd(或 Fluent Bit)例項。後者是一個更強壯和安全的模型,因為資料從 Fluentd 流向它知道的位置,並且只分享被認為可以分享的日誌事件。

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title Fan-in 與應用架構和佈署

rectangle "Fan-in" as n1
rectangle "應用架構" as n2
rectangle "佈署" as n3

n1 --> n2
n2 --> n3

@enduml

此圖示說明瞭多個伺服器上的日誌事件如何透過各自的 Fluentd 節點收集並傳遞給中央 Fluentd 例項。

效能與擴充套件:開發可擴充套件的系統架構

全端模型擴充套件:單一伺服器的完整解決方案

在現代的軟體系統中,效能與擴充套件性是至關重要的考量因素。為了滿足不斷增長的使用者需求,系統必須能夠靈活地擴充套件,以確保高效能和可靠性。圖7.2展示了使用全端模型的擴充套件方式,每個伺服器都佈署了所有功能。

圖7.2 全端模型擴充套件示意圖

在全端模型中,每個伺服器都具備完整的解決方案堆積疊,包括表示層、中間層,甚至後端儲存。這種架構使得呼叫序列更有可能保持在單一伺服器內,從而簡化了請求和回應的追蹤。

擴充套件實作方法

擴充套件可以透過以下兩種主要方式實作:

  1. 每個伺服器持有完整的解決方案堆積疊:這種方式使得追蹤單個請求和回應變得更加容易,因為它們通常在單一伺服器的日誌中。然而,這種方法可能導致伺服器親和性(server affinity),即特定客戶端的請求總是被路由到相同的後端伺服器,這可能會影響動態擴充套件的有效性。

  2. 將解決方案分割成邏輯部分,並將這些部分分配到一或多個特定的伺服器:這種方式通常被稱為N層模型,不同的伺服器專門執行特定的層,例如表示層、業務邏輯層和持久層等。圖7.3展示了一個N層或三層佈署的例子。

圖7.3 N層佈署示意圖

在N層模型中,不同顏色的垂直欄代表不同的層,從左到右分別是UI層、中間層和報告層。這種架構使得伺服器親和性對使用者會話的影響較小,因為相同的伺服器可能會處理同一使用者會話的不同片段。

日誌集中處理的優勢

無論採用哪種擴充套件方式,將日誌集中處理都是非常有益的。這種做法可以帶來多個優勢,包括:

  • 專用節點處理特定工作負載,允許對資源進行針對性的調優。
  • 集中化的邏輯使得組態和管理變得更加簡單,尤其是在複雜的環境中。
  • 減少了需要存取憑證的節點數量,從而提高了安全性。
  • 更容易證明安全性,因為資料的來源點是可控的。

使用Fluentd實作日誌集中處理

圖7.4展示了一個使用Fluentd實作日誌集中處理的例子。應用伺服器上執行著輕量級的Fluentd節點,這些節點將日誌事件轉發給一個專門的Fluentd伺服器進行進一步處理。

圖7.4 Fluentd集中處理日誌事件示意圖

此圖示說明瞭如何使用多個Fluentd例項將日誌事件饋送到一個中央Fluentd例項,該例項執行在專門的伺服器上,負責大部分的工作。

Fluentd組態詳解

要設定這樣一個集中式的日誌處理系統,我們需要兩個Fluentd組態檔案。一個組態檔案用於源伺服器,使用forward外掛作為輸出;另一個組態檔案用於中央節點,使用forward外掛作為輸入,以接收來自源伺服器的日誌事件。

<system>
  log_level info
</system>

清單7.2 Chapter7/Fluentd/dummy-forward1.conf—展示了使用forward輸出外掛的組態

在源伺服器的組態中,我們使用了一個過濾器來將環境變數NodeName的值新增到日誌事件中,以便於識別日誌事件的來源。

Filter stdout
Dummy plugin
Forward

內容解密:

  1. 系統日誌級別設定:設定Fluentd的日誌級別為info,以控制日誌輸出的詳細程度。
  2. 使用dummy外掛生成測試資料:在組態中使用dummy外掛來生成模擬的日誌事件,以便於測試和演示。
  3. forward外掛組態:組態forward外掛作為輸出,將日誌事件轉發給中央Fluentd節點。
  4. 過濾器組態:使用過濾器將環境變數NodeName的值新增到日誌事件中,以標識日誌事件的來源。

提升Fluentd的效能與擴充套件性

7.2.1 使用Forward Plugin擴充套件Fluentd

要實作Fluentd的擴充套件,我們首先需要了解如何使用forward外掛來轉發日誌事件。這種方法允許我們將日誌收集和處理分散到多個Fluentd節點上。

組態範例

首先,我們需要在每個源節點上組態Fluentd,以生成日誌事件並將其轉發到中央Fluentd節點。下面是一個範例組態:

<source>
  @type dummy
  tag "#{ENV["NodeName"]}"
  auto_increment_key counter
  dummy {"hello":"world"}
</source>
<filter *>
  @type stdout
  <inject>
    tag_key fluentd_tag
  </inject>
</filter>
<match *>
  @type forward
  buffer_type memory
  flush_interval 2s
  <server>
    host 127.0.0.1
    port 28080
  </server>
  <secondary>
    @type stdout
  </secondary>
</match>

組態解說

  • 來源組態:使用dummy外掛生成假的日誌事件,並根據環境變數NodeName動態設定標籤(tag)。
  • 過濾器組態:使用stdout外掛將標籤注入日誌事件中,以便在控制檯輸出中顯示。
  • 匹配組態:使用forward外掛將日誌事件轉發到指定的中央Fluentd節點。
    • buffer_type memory:使用記憶體作為緩衝區型別。
    • flush_interval 2s:每2秒重新整理緩衝區。
    • <server>區塊:定義目標伺服器的主機和埠。
    • <secondary>區塊:如果無法將日誌事件傳送到中央節點,則將其輸出到控制檯。

啟動Fluentd

在啟動Fluentd之前,需要在執行Fluentd的shell中設定環境變數NodeName,例如:

export NodeName=Node1
fluentd -c Chapter7/Fluentd/dummy-forward1.conf

重複上述步驟,可以啟動多個Fluentd源節點,將日誌事件轉發到中央節點。

中央Fluentd節點組態

中央Fluentd節點的組態如下:

<system>
  log_level info
</system>
<source>
  @type forward
  port 28080
  bind 127.0.0.1
</source>
<match *>
  @type stdout
</match>

中央節點組態解說

  • 系統組態:設定日誌級別為info
  • 來源組態:使用forward外掛監聽指定的埠和地址,以接收來自源節點的日誌事件。
  • 匹配組態:將接收到的日誌事件輸出到控制檯。

啟動中央Fluentd節點後,您將看到來自不同源節點的日誌事件被合併輸出到控制檯。

#### 使用msgpack最佳化網路傳輸

使用msgpack外掛可以減少網路流量,因為forward外掛可以設定為使用msgpack格式進行事件傳輸,而接收端的forward外掛可以自動解封裝這些事件。

7.2.2 Fan-out與工作負載分佈

除了簡單地將工作負載解除安裝到專門的Fluentd伺服器之外,還可以採用fan-out模式,將日誌事件分發到多個處理節點。這種方法可以進一步擴充套件Fluentd的處理能力。

Fluent Bit的應用

在某些情況下,可以使用Fluent Bit作為應用程式的本地日誌收集器,因為它更輕量且資源佔用較少。然後,將收集到的日誌事件轉發到下游的Fluentd進行進一步處理。

圖示說明

此圖示展示了兩種不同的工作負載分佈策略:

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 圖示說明

rectangle "日誌事件" as node1
rectangle "轉發" as node2
rectangle "處理" as node3

node1 --> node2
node2 --> node3

@enduml

圖示解說

  • 應用服務生成日誌事件。
  • 本地Fluentd/Fluent Bit收集這些日誌事件。
  • 本地Fluentd/Fluent Bit將日誌事件轉發到中央Fluentd節點專用Fluentd主機
  • 中央Fluentd節點或多台專用Fluentd主機對日誌事件進行處理,並將結果輸出到分享持久化/分析平台

這種架構允許更靈活地擴充套件和分配工作負載,從而提高整體系統的效能和可靠性。