作為生產者和消費者之間數據流的一個中心組件,需要一個 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