作者簡(jiǎn)介
運(yùn)小堯? ? 百度高級(jí)研發(fā)工程師
負(fù)責(zé)百度運(yùn)維大數(shù)據(jù)存儲(chǔ)平臺(tái)的設(shè)計(jì)和研發(fā)吨瞎,致力于追求大規(guī)模存儲(chǔ)系統(tǒng)的高性能和高可用。
干貨概覽
在百度大規(guī)模時(shí)序數(shù)據(jù)存儲(chǔ)(一)| 監(jiān)控場(chǎng)景的時(shí)序數(shù)據(jù)文章中拥峦,我們簡(jiǎn)要地介紹了百度監(jiān)控場(chǎng)景時(shí)序數(shù)據(jù)的特點(diǎn),且分析了在每天萬(wàn)億級(jí)的數(shù)據(jù)規(guī)模下,時(shí)序數(shù)據(jù)的存儲(chǔ)所面臨著的諸多挑戰(zhàn)翻斟。本篇將介紹 TSDB 在方案選型和存儲(chǔ)模型設(shè)計(jì)上的實(shí)踐吮廉。
一苞尝、簡(jiǎn)介
TSDB(Time Series Database,時(shí)間序列數(shù)據(jù)庫(kù))是一種日趨流行的數(shù)據(jù)庫(kù)宦芦,從 DB-Engines 提供的最近一年各類(lèi)數(shù)據(jù)庫(kù)流行趨勢(shì)來(lái)看野来,最近一年TSDB 的增長(zhǎng)勢(shì)頭強(qiáng)勁,遠(yuǎn)超其它類(lèi)型的數(shù)據(jù)庫(kù)踪旷。
圖1 ? ?數(shù)據(jù)庫(kù)分類(lèi)流行趨勢(shì)
二曼氛、底層存儲(chǔ)選型
為了更好地適應(yīng)業(yè)務(wù)需求,我們選擇自研 TSDB令野,由于時(shí)序數(shù)據(jù)的規(guī)模很大舀患,我們?cè)诘讓哟鎯?chǔ)的選型上需要慎重考量。在百萬(wàn)級(jí)指標(biāo)的規(guī)模下气破,用 MySQL 來(lái)實(shí)現(xiàn)就可以滿(mǎn)足需求聊浅,如開(kāi)源監(jiān)控系統(tǒng) Zabbix 的底層存儲(chǔ)方案。
隨著業(yè)務(wù)的快速發(fā)展现使,我們的數(shù)據(jù)規(guī)模也從百萬(wàn)級(jí)漲到了千萬(wàn)級(jí)以至于現(xiàn)在的萬(wàn)億級(jí)低匙,此時(shí)傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)愈顯乏力。我們嘗試過(guò)的一些集群方案在讀/寫(xiě)延遲上并沒(méi)有顯著的提升碳锈,其擴(kuò)展能力也只是差強(qiáng)人意顽冶,這迫使我們尋求新的方案。
重新審視我們對(duì)存儲(chǔ)系統(tǒng)的核心需求:高吞吐售碳、低延遲强重、可擴(kuò)展绞呈。對(duì)于監(jiān)控場(chǎng)景來(lái)說(shuō),關(guān)系型數(shù)據(jù)庫(kù)的強(qiáng)一致模型间景、事務(wù)機(jī)制以及聯(lián)合查詢(xún)等強(qiáng)項(xiàng)并不是我們關(guān)注的重點(diǎn)佃声,單個(gè)數(shù)據(jù)點(diǎn)的丟失并不影響監(jiān)控指標(biāo)的整體趨勢(shì),數(shù)據(jù)的偶發(fā)延遲也可以接受倘要。
近兩年開(kāi)源的 TSDB 項(xiàng)目不斷涌現(xiàn)(見(jiàn)圖 2)圾亏,許多優(yōu)秀的項(xiàng)目也成為我們調(diào)研和學(xué)習(xí)的對(duì)象,我們發(fā)現(xiàn)這些項(xiàng)目在底層存儲(chǔ)的選型上各有偏好封拧,這里列舉一些:
OpenTSDB:著名的老牌 TSDB召嘶,底層存儲(chǔ)最初只支持 HBase,后來(lái)增加了對(duì) Cassandra 的支持
InfluxDB:基于自研的 TSM 存儲(chǔ)引擎哮缺,集群方案未開(kāi)源
KairosDB:發(fā)源于 OpenTSDB弄跌,早期底層選用 HBase,目前主打使用 Cassandra尝苇,還支持H2(用于非生產(chǎn)環(huán)境)
Prometheus:Google 監(jiān)控系統(tǒng) Borgmon 的開(kāi)源版本铛只,基于 LevelDB和本地存儲(chǔ)
圖2 ? ?TSDB排名變化趨勢(shì)
然而無(wú)論是 HBase、Cassandra糠溜、LevelDB 還是 InfluxDB 的 TSM 存儲(chǔ)引擎淳玩,他們的一個(gè)重要共同點(diǎn)就是都基于?LSM-tree?實(shí)現(xiàn)(Log-Strutured Merge-tree,日志結(jié)構(gòu)合并樹(shù))非竿。如圖 3 所示蜕着,LSM-tree 這種樹(shù)形結(jié)構(gòu)可以像打印日志一般,以追加的方式順序?qū)懭霐?shù)據(jù)红柱,并且不斷地將較小的數(shù)據(jù)塊合并成更大的塊承匣,最終將數(shù)據(jù)批量地刷寫(xiě)到磁盤(pán)。
圖3 ? ?LSM-tree
使用 LSM-tree 有什么實(shí)際的意義锤悄?在上一篇文章中我們提到韧骗,監(jiān)控?cái)?shù)據(jù)的寫(xiě)入量非常大(每秒數(shù)千萬(wàn)數(shù)據(jù)點(diǎn)),存儲(chǔ)時(shí)長(zhǎng)最長(zhǎng)可達(dá)數(shù)年零聚,從成本角度考慮袍暴,廉價(jià)的磁盤(pán)自然是合適的選擇。然而隶症,磁盤(pán)的機(jī)械結(jié)構(gòu)使得其隨機(jī) I/O 性能在面對(duì)每秒數(shù)千萬(wàn)的寫(xiě)入請(qǐng)求時(shí)顯得力不從心政模。LSM-tree正是能夠借助內(nèi)存緩沖將大量的隨機(jī)寫(xiě)入轉(zhuǎn)化成批量的順序?qū)懭?/b>,使得最終磁盤(pán)承載的寫(xiě)入次數(shù)對(duì)數(shù)級(jí)減少蚂会,極大地提升了寫(xiě)入吞吐量淋样。
綜合來(lái)看,NoSQL 數(shù)據(jù)庫(kù)是更合適的選擇颂龙。在諸多 NoSQL 數(shù)據(jù)庫(kù)中习蓬,我們選擇了基于 LSM 實(shí)現(xiàn)的 HBase 纽什,主要出于如下考慮:
高吞吐措嵌、低延遲躲叼,滿(mǎn)足讀/寫(xiě)性能需求
數(shù)據(jù)存儲(chǔ)在 HDFS,支持多副本冗余企巢,滿(mǎn)足可靠性需求
表格存儲(chǔ)枫慷,模型簡(jiǎn)單、業(yè)務(wù)開(kāi)發(fā)較為方便
支持橫向擴(kuò)展浪规,可線(xiàn)性擴(kuò)容或听,能夠適應(yīng)業(yè)務(wù)增長(zhǎng)
成熟的代碼、活躍的社區(qū)和廣泛的應(yīng)用案例
三笋婿、基于HBase的存儲(chǔ)設(shè)計(jì)
HBase Table 中的數(shù)據(jù)按照?RowKey?的字典序排列誉裆,在行的方向上數(shù)據(jù)可以分布到多個(gè) HRegion中,而 HRegion 可以分布在不同的節(jié)點(diǎn)上缸濒,因此只要能夠使數(shù)據(jù)均勻地分布在 HRegion 中足丢,就可以實(shí)現(xiàn)存儲(chǔ)的負(fù)載均衡。
圖4 ? ?HRegion的分布
容易看出庇配,RowKey 的設(shè)計(jì)是負(fù)載均衡的關(guān)鍵斩跌。如果 RowKey 設(shè)計(jì)不好,就容易形成熱點(diǎn)HRegion捞慌,導(dǎo)致其所在節(jié)點(diǎn)負(fù)載過(guò)重耀鸦,進(jìn)而集群的整體性能下降。
接下來(lái)重點(diǎn)介紹 TSDB 中最關(guān)鍵的兩張表的設(shè)計(jì):數(shù)據(jù)表和維度索引表啸澡。前者支撐了所有時(shí)序數(shù)據(jù)的存儲(chǔ)和查詢(xún)袖订,后者是多維度聚合查詢(xún)的基礎(chǔ)。
1 數(shù)據(jù)表
前文介紹過(guò)嗅虏,監(jiān)控時(shí)間序列構(gòu)成如下:
時(shí)間序列 = 監(jiān)控對(duì)象 + 標(biāo)簽列表 + 監(jiān)控項(xiàng) + 數(shù)據(jù)點(diǎn)
為方便講解著角,換一種形式表述:
ts = (object + tags) + metric + [(timestamp, value), (timestamp, value), ...]
可見(jiàn),由object + tags + metric + timestamp?可以唯一定位一個(gè)數(shù)據(jù)點(diǎn)的取值旋恼。為了充分利用HBase 的特性吏口,我們借鑒了 OpenTSDB 的做法,將 RowKey 設(shè)計(jì)如下:
RowKey = entity_id + metric_id + timebase
entity_id?是由 object 和 tags 的經(jīng)過(guò) hash 得到的一個(gè)固定長(zhǎng)度的值冰更,hash 后原始字符串的自然順序被打亂产徊,使得 RowKey 能夠相對(duì)均勻地分布在不同 HRegion 中。
metric_id?為 metric 的字符串 hash 值蜀细,同樣是固定長(zhǎng)度舟铜。
timebase?為 Unix 時(shí)間戳按照 1 小時(shí)(3600 秒)取整得到的數(shù)值,固定 4 個(gè)字節(jié)的長(zhǎng)度
這樣的設(shè)計(jì)有如下好處:
entity_id 和 metric_id 的散列使得數(shù)據(jù)相對(duì)均勻分布
timebase 置于 RowKey 的字節(jié)低位奠衔,使得同一個(gè)時(shí)間序列數(shù)據(jù)的 RowKey 連續(xù)分布谆刨,可以高效地按時(shí)間進(jìn)行范圍掃描
固定長(zhǎng)度的 RowKey 減少了空間浪費(fèi)塘娶,同時(shí)前綴式的設(shè)計(jì)可以充分利用 HBase 的前綴壓縮機(jī)制,進(jìn)一步節(jié)省 RowKey 所占空間
RowKey 代表的行包含 1 小時(shí)的數(shù)據(jù)痊夭,行中數(shù)據(jù)點(diǎn)按照當(dāng)前時(shí)間在 1 小時(shí)內(nèi)的偏移量進(jìn)行存儲(chǔ)刁岸,最終的表結(jié)構(gòu)示意如表 1:
表1 ? ?數(shù)據(jù)表 RowKey 設(shè)計(jì)
2 維度索引表
在數(shù)據(jù)表的設(shè)計(jì)中,tags 被編碼進(jìn)固定長(zhǎng)度的 entity_id 中她我,同時(shí) HBase 并沒(méi)有對(duì)索引的原生支持虹曙,這導(dǎo)致無(wú)法通過(guò) tag 找到對(duì)應(yīng)的 entity_id,也就無(wú)法滿(mǎn)足數(shù)據(jù)的多維度檢索聚合需求番舆。為此我們引入了一張索引表酝碳,建立從 tag 到 entity_id 的映射,以支持通過(guò) tag 篩選數(shù)據(jù)恨狈。
如圖 5 所示疏哗,通過(guò)指定一個(gè)?tag: k1=v1,可以查到所有包含這個(gè) tag 的 entity_id1禾怠、entity_id2 和entity_id3返奉。
圖5 ? ?維度索引
RowKey 的構(gòu)造比較簡(jiǎn)單:
RowKey = key + value
索引對(duì)應(yīng)的 entity_id 直接作為 Column 的 Qualifier 存儲(chǔ),對(duì)應(yīng)的 Column Value 留空刃宵,最終的表結(jié)構(gòu):
表2 ? ?索引表設(shè)計(jì)
總結(jié)
底層存儲(chǔ)選型和數(shù)據(jù)模型設(shè)計(jì)是 TSDB 設(shè)計(jì)中的兩個(gè)重要的基礎(chǔ)環(huán)節(jié)衡瓶,前者決定了后者的設(shè)計(jì)思路,后者的設(shè)計(jì)影響上層功能的設(shè)計(jì)實(shí)現(xiàn)牲证,二者又與集群的架構(gòu)設(shè)計(jì)和性能表現(xiàn)息息相關(guān)哮针。然而,影響系統(tǒng)性能和可用性的設(shè)計(jì)環(huán)節(jié)還有很多坦袍,接下來(lái)的文章將逐步為讀者介紹