作為生產者和消費者之間資料流的一箇中心元件,需要一個 Logstash 例項負責驅動多個並行事件流的情況。預設情況下,這樣的使用場景的配置讓人並不太開心,使用者會遭遇所謂的條件地獄(Conditional hell)。因為每個單獨的 Logstash 例項預設支援一個管道,該管道由一個輸入、若干個過濾器和一個輸出組成,如果要處理多個資料流,就要到處使用條件判斷。
條件地獄(Conditional hell)
已知的在一個管道中實現多個獨立流的方法是使用條件判斷。主要方式是在輸入部分透過標籤標記事件,然後在過濾器中和輸出階段建立條件分支,對貼有不同標籤的事件,應用不同的外掛集。這種方式雖然可以解決問題,但在實際的使用中卻非常的痛苦!下面是一個簡單的 demo 片段:
input { beats { port => 3444 tag => apache } tcp { port => 4222 tag => firewall } } filter { if "apache" in [tags] { dissect { ... } } else if "firewall" in [tags] { grok { ... } } } output { if "apache" in [tags] { elasticsearch { ... } } else if "firewall" in [tags] { tcp { ... } } }
對應的 Logstash 管道配置已經被條件語句包裹的十分臃腫,而它們的唯一目的是保持流的獨立性。
雖然使用條件實現獨立的多個流是可行的,但是很容易看出,由於存在單個管道和處理的單個階段,隨著複雜性的增加,配置會變得非常冗長,很難管理。下圖展示了包含兩個流的簡單管道:
不幸的是,這並不是該方案的唯一缺陷。
缺乏擁塞隔離
如果您熟悉 Logstash 的工作原理,就會知道管道的輸出部分接收到一批事件,並且在所有事件和完成所有輸出之前不會移動到下一批事件。這意味著,對於上面的管道,如果 TCP 套接字目標不可達,Logstash將不會處理其他批次的事件,這也就意味著 Elasticsearch 將不會接收事件,並且會對 TCP 輸入和 Beats 輸入施加反壓力。
不同的資料流需要以不同的方式處理
如果 TCP - > Grok - > TCP 資料流處理大量的小資料,而 Beats -> Dissect -> ES 資料流中的單個資料體積大但是數量少。那麼前一個資料流希望有多個 worker 並行並其每一批次處理更多事件,第二個資料流則期望使用少量的 worker 和每批次處理少量的事件。使用單個管道,無法為單個資料流指定獨立的管道配置。
透過多個 Logstash 例項解決問題
上述問題可以透過在同一臺機器上執行多個 Logstash 例項來解決,然後可以獨立地管理這些例項。但是即使這樣的解決方案也會產生其他問題:
- 需要管理多個例項(透過 init 系統管理多個後臺服務)
- 每個 Logstash 的例項也意味著一個獨立的 JVM
- 需要監視每個 Logstash 例項
這種方式其實很糟糕!
多個管道
從 Logstash 6.0 開始,引入了 Multiple Pipelines,才完美的解決了這個問題。Multiple Pipelines 的配置非常簡單:在配置檔案 pipelines.yml 中新增新的 pipeline 配置並指定其配置檔案就可以了。下面是一個簡單的 demo 配置:
- pipeline.id: apache pipeline.batch.size: 125 queue.type: persisted path.config: "/path/to/config/apache.cfg" queue.page_capacity: 50mb - pipeline.id: test pipeline.batch.size: 2 pipeline.batch.delay: 1 queue.type: memory config.string: "input { tcp { port => 3333 } } output { stdout {} }"
這個 YAML 檔案包含一個雜湊(或字典)列表,其中每個雜湊表示一個管道,鍵和值為該管道設定名稱。被省略的設定值返回到它們的預設值。
配置多個管道
下面來看一個真實點的例子,筆者在 Ubuntu 18.04 Server 中安裝了 Logstash 6.2.4,除了在預設的配置檔案目錄(/etc/logstash/conf.d)中新增配置檔案外,建立新的目錄 /etc/logstash/myconf.d,並在 /etc/logstash/myconf.d 目錄下建立 Logstash 配置檔案 krtest.conf。然後在 /etc/logstash/pipelines.yml 檔案中新增新的 pipeline 配置:
- pipeline.id: main path.config: "/etc/logstash/conf.d/*.conf" - pipeline.id: krtest path.config: "/etc/logstash/myconf.d/krtest.conf"
其中 pipeline.id 為 main 的管道是預設的配置,我們新新增了 id 為 krtest 的管道並指定了對應的配置檔案路徑。啟動 Logstash,如果你安裝的 X-Pack 外掛就可以在 Kibana->Monitoring->Logstash 中看到新新增的名稱為 krtest 的管道:
使用 Multiple Pipelines 後,我們的 Logstash 配置檔案就可以寫得像下面的程式碼一樣簡練(不再需要那麼多的條件語句)了:
input { beats { port => 5064 } } filter { grok { ... } } output { elasticsearch { ... } }
參考:
Multiple Pipelines
Introducing Multiple Pipelines in Logstash