Bioyino - 分散式、可擴展的指標聚合器

所以你收集指標。 正如我們一樣。 我們也收集指標。 當然是做生意所必需的。 今天我們要講的是我們監控系統的第一個環節-相容statsd的聚合伺服器 生物伊諾,我們為什麼寫它以及為什麼我們放棄布魯貝克。

Bioyino - 分散式、可擴展的指標聚合器

從我們之前的文章(1, 2)您可以發現,直到某個時候我們使用以下方式收集分數 布魯貝克。 它是用C 語言編寫的。從程式碼的角度來看,它就像一個插件一樣簡單(當您想要做出貢獻時,這一點很重要),最重要的是,它可以在峰值時處理每秒2 萬個指標(MPS) 的資料量沒有任何問題。 該文檔聲明支援 4 萬 MPS,並帶有星號。 這意味著如果您在 Linux 上正確配置網絡,您將獲得所述數字。 (我們不知道如果您保持網路不變,您可以獲得多少 MPS)。 儘管有這些優點,我們對布魯貝克還是有一些嚴重的抱怨。

權利要求1。 該專案的開發者 Github 停止了支援:發布補丁和修復程序,接受我們的和(不僅僅是我們的)PR。 在過去幾個月(2018 年 2 月至 XNUMX 月),活動已恢復,但在此之前有近兩年的完全平靜。 此外,該項目正在開發中 滿足 Gihub 內部需求,這可能成為引入新功能的嚴重障礙。

權利要求2。 計算的準確性。 Brubeck總共收集了65536個值進行聚合。 在我們的例子中,對於某些指標,在聚合期間(30秒),可能會到達更多的值(峰值為1)。 這次採樣的結果是,最大值和最小值顯得毫無用處。 例如,像這樣:

Bioyino - 分散式、可擴展的指標聚合器
一如既往

Bioyino - 分散式、可擴展的指標聚合器
本來應該怎樣

基於同樣的原因,金額通常計算不正確。 在這裡添加一個帶有 32 位元浮點溢出的 bug,當接收到看似無辜的指標時,它通常會將伺服器發送到段錯誤,然後一切都會變得很好。 順便說一句,該錯誤尚未修復。

最後, 索賠X。 在撰寫本文時,我們已準備好將其呈現給我們能夠找到的所有 14 個或多或少可用的 statsd 實作。 讓我們想像一下,某些單一基礎設施已經發展得如此之快,以至於接受 4 萬 MPS 已經不夠了。 或者,即使它還沒有增長,但這些指標對你來說已經如此重要,即使是圖表中短暫的 2-3 分鐘的下降也可能變得至關重要,並導致經理們陷入難以克服的抑鬱情緒。 由於治療憂鬱症是一項吃力不討好的任務,因此需要技術解決方案。

首先是容錯,這樣伺服器突然出現的問題不會導致辦公室出現精神病殭屍大災難。 其次,擴展至能夠接受超過 4 萬 MPS,無需深入挖掘 Linux 網路堆疊並平靜地「廣度」增長到所需的大小。

由於我們有擴展空間,因此我們決定從容錯開始。 「關於! 容錯! 很簡單,我們能做到。」我們這樣想並啟動了 2 台伺服器,在每台伺服器上提供了一份 brubeck 副本。 為此,我們必須將帶有指標的流量複製到兩台伺服器,甚至為此編寫 小實用程式。 我們用這個解決了容錯問題,但是......不是很好。 起初一切看起來都很棒:每個 brubeck 收集自己版本的聚合,每 30 秒將資料寫入 Graphite 一次,覆蓋舊的間隔(這是在 Graphite 端完成的)。 如果一台伺服器突然發生故障,我們總會有第二台伺服器擁有自己的聚合資料副本。 但問題是:如果伺服器發生故障,圖表上就會出現「鋸子」。 這是因為 brubeck 的 30 秒間隔不同步,並且在崩潰時其中一個間隔不會被覆蓋。 當第二個伺服器啟動時,也會發生同樣的事情。 相當可以忍受,但我想要更好! 可擴展性問題也沒有消失。 所有指標仍然「飛行」到單一伺服器,因此我們僅限於相同的 2-4 百萬 MPS,具體取決於網路層級。

如果你稍微思考一下這個問題,同時用鏟子挖雪,那麼你可能會想到以下明顯的想法:你需要一個可以在分散式模式下工作的 statsd。 即實現節點之間在時間和指標上的同步。 「當然,這樣的解決方案可能已經存在,」我們說,然後去了谷歌...... 他們什麼也沒找到。 在瀏覽了不同 statsd 的文檔後(https://github.com/etsy/statsd/wiki#server-implementations 截至11.12.2017年XNUMX月XNUMX日),我們什麼也沒發現。 顯然,這些解決方案的開發人員和用戶都還沒有遇到這麼多指標,否則他們肯定會想出一些東西。

然後我們想起了在 Just for Fun 黑客馬拉鬆上編寫的「玩具」statsd - Bioyino(專案名稱是在黑客馬拉松開始前由腳本生成的),並意識到我們迫切需要自己的 statsd。 為了什麼?

  • 因為世界上的 statsd 克隆太少了,
  • 因為可以提供期望的或接近期望的容錯性和可擴展性(包括同步伺服器之間的聚合指標並解決發送衝突的問題),
  • 因為可以比 brubeck 更準確地計算指標,
  • 因為你可以自己收集更詳細的統計數據,而布魯貝克實際上沒有向我們提供這些數據,
  • 因為我有機會編寫自己的超高性能分佈式規模實驗室應用程序,該應用程式不會完全重複另一個類似的超高性能的架構......好吧,就是這樣。

寫什麼? 當然,在 Rust 中。 為什麼?

  • 因為已經有了原型解決方案,
  • 因為文章的作者當時已經了解 Rust,並渴望在其中寫一些東西用於生產,並有機會將其開源,
  • 因為由於接收到的流量的性質(幾乎是實時),帶有 GC 的語言不適合我們,並且 GC 暫停實際上是不可接受的,
  • 因為您需要與 C 相當的最大性能
  • 因為 Rust 為我們提供了無所畏懼的並發性,如果我們開始用 C/C++ 寫它,我們會比 brubeck 遇到更多的漏洞、緩衝區溢位、競爭條件和其他可怕的字詞。

還有一個反對 Rust 的論點。 該公司沒有使用 Rust 創建專案的經驗,現在我們也不打算在主專案中使用它。 因此,我們非常擔心一切都不會成功,但我們決定冒險嘗試。

時間飛逝...

最後,經過幾次失敗的嘗試,第一個工作版本就準備好了。 發生了什麼事? 這就是發生的事情。

Bioyino - 分散式、可擴展的指標聚合器

每個節點接收自己的指標集並累積它們,並且不會聚合最終聚合需要完整集合的那些類型的指標。 這些節點透過某種分散式鎖定協定相互連接,該協定允許您在其中選擇唯一一個(我們在這裡哭了)值得向偉大的節點發送指標的節點。 這個問題目前正在解決 領事,但未來作者的野心延伸到 自己的 執行 Raft,其中最有價值的當然是共識領導節點。 除了共識之外,節點經常(默認情況下每秒一次)向其鄰居發送它們在那一秒設法收集的預聚合指標的那些部分。 事實證明,擴展性和容錯能力得到了保留——每個節點仍然擁有一整套指標,但這些指標已經通過 TCP 聚合發送並編碼成二進制協議,因此與 UDP 相比,重複成本顯著降低。 儘管傳入的指標數量相當大,但累積所需的記憶體非常少,甚至需要更少的 CPU。 對於我們高度可壓縮的指標來說,這只是幾十兆位元組的資料。 作為額外的好處,我們在 Graphite 中不會像 burbeck 那樣進行不必要的資料重寫。

具有度量的UDP封包透過簡單的循環在網路設備上的節點之間不平衡。 當然,網路硬體不會解析資料包的內容,因此每秒可以拉取超過 4M 的資料包,更不用說它根本不知道的指標了。 如果我們考慮到指標並不是在每個資料包中一次出現一個,那麼我們就不會預見到此位置會出現任何效能問題。 如果伺服器崩潰,網路設備會快速(1-2 秒內)偵測到這一事實,並將崩潰的伺服器從輪換中刪除。 因此,被動(即非領導者)節點實際上可以打開和關閉,而不會注意到圖表上的下降。 我們損失的最大值是最後一秒傳入的指標的一部分。 領導者的突然丟失/關閉/切換仍然會造成輕微異常(30秒間隔仍然不同步),但是如果節點之間存在通信,則可以將這些問題最小化,例如透過發送同步資料包。

關於內部結構的一些資訊。 當然,該應用程式是多執行緒的,但執行緒架構與 brubeck 中使用的不同。 brubeck 中的線程是相同的 - 每個線程都負責資訊收集和聚合。 在bioyino中,工作人員分為兩類:負責網路的人員和負責聚合的人員。 這種劃分可以讓您根據指標類型更靈活地管理應用程式:在需要密集聚合的地方,可以添加聚合器,在網路流量較大的地方,可以添加網路流量的數量。 目前,我們的伺服器在 8 個網路和 4 個聚合流中運作。

計數(負責聚合)部分非常無聊。 網路流填充的緩衝區分佈在計數流中,隨後在計數流中進行解析和聚合。 根據請求,給予發送到其他節點的指標。 所有這些,包括在節點之間發送資料以及與 Consul 一起工作,都是非同步執行的,在框架上運行 東京.

開發過程中的更多問題是由負責接收指標的網路部分引起的。 將網路流分成單獨的實體的主要目標是希望減少流所花費的時間 沒有 從套接字讀取資料。 使用非同步UDP和常規recvmsg的選項很快就消失了:第一個消耗太多的用戶空間CPU用於事件處理,第二個需要太多的上下文切換。 因此現在使用 接收訊息 有很大的緩衝區(先生們,緩衝區對你們來說沒什麼!)。 對常規 UDP 的支援保留用於不需要 recvmmsg 的輕型情況。 在多訊息模式下,可以實現主要的事情:絕大多數時間,網頁執行緒抓取作業系統佇列- 從套接字讀取資料並將其傳輸到用戶空間緩衝區,只是偶爾切換到將已填充的緩衝區提供給聚合器。 套接字中的佇列實際上不會累積,丟棄的資料包數量實際上不會增加。

注意

在預設設定中,緩衝區大小設定得相當大。 如果您突然決定自己嘗試該伺服器,您可能會遇到這樣的情況:發送少量指標後,它們將不會到達 Graphite,而是保留在網路流緩衝區中。 要使用少量指標,您需要在配置中將 bufsize 和 task-queue-size 設定為較小的值。

最後,為圖表愛好者提供一些圖表。

統計每台伺服器傳入的metrics數量:超過2萬MPS。

Bioyino - 分散式、可擴展的指標聚合器

禁用節點之一併重新分配傳入指標。

Bioyino - 分散式、可擴展的指標聚合器

傳出指標統計:只有一個節點總是發送-raid boss。

Bioyino - 分散式、可擴展的指標聚合器

統計每個節點的運作情況,考慮到各個系統模組的錯誤。

Bioyino - 分散式、可擴展的指標聚合器

傳入指標的詳細資訊(隱藏指標名稱)。

Bioyino - 分散式、可擴展的指標聚合器

接下來我們打算如何處理這一切? 當然是寫程式啦,媽的……! 該專案最初計劃是開源的,並將在其整個生命週期中保持如此。 我們近期的計劃包括切換到我們自己的 Raft 版本、將對等協議更改為更便攜的協議、引入額外的內部統計數據、新類型的指標、錯誤修復和其他改進。

當然,歡迎大家為專案的開發提供協助:創建 PR、Issue,如果可能的話我們會回應、改進等。

話雖這麼說,那就是了,夥計們,買我們的大象吧!



來源: www.habr.com

添加評論