Hulu如何擴展InfluxDB使其支持每秒百萬TPS
導讀:InfluxDB是最常用的時間序列數據庫之一,大家廣泛使用其開源版本。然而其開源版本缺乏一些高可用相關的特性,本文介紹Hulu在使用InfluxDB的過程中碰見的問題和解決方案,十分值得一讀。
隨著Hulu的持續增長,時間序列數據庫已成為公司監控系統的關鍵部分。 這可以像機器性能指標或應用程序本身的數據一樣簡單處理。 由于我們擁有的數據量很大,因此創建一個支持冗余和可擴展的體系結構至關重要。
為什么時間序列數據很重要?
時間序列數據使我們能夠評估趨勢,以便發現問題并采取措施。
下圖用于確定最近的內存泄漏,該問題會影響在特定數據中心運行的應用程序版本。
Graphite 架構
最初,每個開發團隊都有自己的時間序列數據解決方案。 由于大多數團隊都有類似的需求,這種情況無疑是浪費資源的。 為了解決這個問題,我們建立了原始的時間序列數據管道,該管道為整個工程團隊提供了時間序列數據庫。
該管道基于Graphite,并將數據存儲到OpenTSDB。 在高峰時,該Graphite集群的吞吐量為每秒140萬個指標。 在維持這一流程的同時,我們遇到了許多問題,這些問題隨著我們繼續增長而變得越來越常見。
其中許多問題源于為Hulu所有開發團隊提供數據管道共享服務, 這樣就需要支持巨大吞吐量和基數,其他問題是來自于可伸縮性的固有問題。
數據管道遇到的挑戰
使用方經常且無意間會在其標準名稱空間中發送唯一數據,例如時間戳或另一個唯一標識符。 例如:
- stats.application.dc1.1557471341.count 1 1557471341
- stats.application.dc1.1557471345.count 1 1557471345
- stats.application.dc1.1557471346.count 1 1557471346
這導致了命名空間中基數爆炸式增長,從而影響了接收速度和整個管道的穩定性。盡管可以阻止這些行為,但是這樣做非常困難,因為需要匹配有問題的指標,而不能影響合法指標。
由于吞吐量的限制,我們在創建規則的復雜性和數量方面受到限制,因為必須針對接收到的每個指標使用所有規則進行評估。這需要在指標數據涉及的許多節點上以滾動的方式完成。因此通常很少會添加條件來阻止有問題的指標,一般傾向于讓應用程序停止發送指標。不幸的是,在大多數情況下,花費的時間導致數據丟失。
檢索數據時,許多用戶會無意中運行很長時間或占用大量資源的查詢,這最終將導致為其提供數據的后端超時并宕機。沒有叫停這種行為的限制,這也影響了整個系統的穩定性。
發送的指標也是有問題的。由于格式并沒有標準化,因此找出哪個服務正在發送特定指標需要進行大量猜測,而在我們實際需要這樣做時非常困難。
最后,由于我們的設置,所有指標都被發送到了兩個數據中心之一。如果發生故障,則整個數據中心的指標將無法訪問。此外,由于我們只有一個統一的接口來檢索這些指標,因此我們優先于一個數據中心。這是有問題的,因為如果用戶向第一個優先級數據中心發送了一個指標,但隨后決定使用另一個數據中心,由于第一個數據中心已經存在命名空間,因此將無法訪問他們的新指標,從而導致問題。
InfluxDB初始架構
為了解決這些問題,我們決定基于InfluxDB從頭開始重新構建統計數據管道。 對于我們的第一次嘗試,我們創建了兩個集群,在兩個主要數據中心(DC1和DC2)中各有一個。 兩個群集將包含相同的數據。
在此基礎上構建了一個指標中繼群集。 所有指標都將發送到中繼群集。 該集群的唯一目的是將收到的所有指標推送到兩個InfluxDB集群中。 這樣就可以從任何數據中心檢索所有指標,從而完全消除了在Graphite體系結構中遇到的指標可用性問題。 我們在每個數據中心都有指標中繼層。
在此指標中繼層上,我們還實現了必需標簽,這是Hulu中每個應用程序的唯一標識符。這使我們可以輕松地追溯每個指標的來源。沒有此必需標簽的所有指標都會被刪除。
Hulu的所有機器上都運行了Telegraf守護程序(https://github.com/influxdata/telegraf)。 我們已將該守護程序配置為報告所有計算機統計信息,并且還監聽localhost上的指標。我們鼓勵所有開發人員將指標發送到localhost,因為我們已將Telegraf配置為自動為其接收的所有指標添加標準標簽。這些標簽包括原始數據中心,計算機名稱和計算機ID。
此設置效果很好。我們測試過大于每秒200萬個指標的吞吐量,沒有任何問題。然而我們很快遇到了一個問題,導致我們重新評估了當前設置。
具體來說,我們的一個集群在一段時間內不可用,導致所有指標僅被推送到單個(在線)數據中心,然后在被復制到另一個集群之前被丟棄。一旦有問題的群集再次可用,數據就會出現差異,需要手動重新同步群集。我們意識到我們需要一種方法來更優雅地解決此類問題,并減少人工干預。
InfluxDB改進架構
我們在設計中創建了兩個新層,其中包括每個數據中心內的Kafka隊列,以及一個InfluxDB writer層以解決此問題。
指標仍會發送到原始中繼群集,但不再從那里直接路由到InfluxDB群集。而是將其發送到數據中心內的Kafka隊列。
InfluxDB writer層是在InfluxDB群集所在的每個數據中心中創建的。該層的唯一目的是連接到所有數據中心中的Kafka隊列,并將它們寫入其本地InfluxDB集群。如果其中一個InfluxDB集群發生故障,則該數據中心內的writer將停止向該集群寫入數據,但另一個數據中心將繼續提取其指標。一旦有問題的群集重新聯機后,該數據中心內的writer將繼續工作,并寫入本地的群集。最終兩個群集將再次處于一致狀態。
這種設計還使我們能夠完全禁用大部分基礎設施(甚至整個數據中心),并將它們路由到另一個數據中心,而對最終用戶沒有任何影響。
雖然此設計解決了我們的許多問題,但是依然有兩個問題沒有解決。
查詢限制
我們仍然遇到長時間運行的查詢或者說有問題查詢的問題。 使用者有時會進行很長時間的查詢(通常是偶然的),這會導致其他用戶使用時的性能下降。 我們為此目的創建了一個新的微服務Influx Imposer。
該應用程序登錄到我們的兩個InfluxDB集群,并每分鐘檢查一次正在運行的查詢。 如果超過某些閾值(例如60秒)或是危險/資源密集型查詢,則將其殺死。 我們還實現了終止查詢的日志記錄,并且已經大大提高了系統穩定性。
阻止/過濾“不良”指標
使用者可能仍會在命名空間中發送帶有時間戳的指標,或者發送一些可能導致數據集基數非常大的數據。 為了解決這個特定問題,我們創建了另一個名為Barricade的微服務。
Barricade是由數據庫支持的API,其中包含動態黑名單。 如果任何時候需要將標簽,指標或幾乎任何其他信息列入黑名單,都會將其添加到此數據庫中。數據庫更改將同步到InfluxDB writer上的所有本地配置。 這些機器不斷輪詢Barricade以獲取其更新的黑名單規則。 如果檢測到更改,則writer將重新生成其本地備用配置。 之所以在InfluxDB writer層執行此操作,是因為該層上的任何更改都不會導致指標獲取中斷,因此添加新的黑名單對上層查詢是沒有影響的。
時間序列數據一直是并將繼續是Hulu評估趨勢并對之做出反應的能力的重要組成部分。 我們能夠解決先前管道中的所有問題,現在正在將所有用戶移出舊平臺。 在撰寫本文時,我們的新統計信息流已經處理超過每秒一百萬個指標,并且這個數據每天都在增長。