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