逝者如斯夫,不捨晝夜。 —— 孔子
時間如流水,一去不復返。自古不乏對時間流逝的感慨,而現代已經有不少技術記錄流逝的過去。咱們能夠拍照,能夠錄像,固然還能夠用時序數據庫!數據庫
時序數據庫是專門存放隨着時間推移而不斷變化的數據。近些年,隨着IoT等概念的流行,時序數據庫成爲數據庫一個相對獨立的領域逐漸受到重視,普遍應用於物聯網、監控系統、金融、醫療和零售等多種場景。併發
那麼雲上的用戶如何構建一個存儲海量數據的時序數據庫呢?筆者這裏推薦使用 雲HBase + OpenTSDB 方案。雲HBase是使用阿里多年優化過的HBase內核版本,本文不做過多介紹,詳情請看產品主頁。測試
OpenTSDB是一款基於HBase構建的時序數據庫,它的數據存儲徹底交給HBase,自己沒有任何數據存儲。全部節點是對等的,因此部署起來實際上是很是方便的。由於基於HBase,因此自己就具有了橫向擴展,存儲海量數據的能力。常見的部署模式有2種,一種分離部署,一種混合部署。優化
獨立部署,即與多個業務共享一個HBase。適合時序業務較小,或者用不滿HBase資源。ui
混合部署,即TSDB進程和RS在一個VM內。適合時序業務較重,須要獨享HBase。spa
上述2種模式,雲HBase產品都能提供支持,雲HBase購買頁面現已增長時序引擎購買入口。設計
一條時間線由 Metirc + 多個tag 惟一肯定,時間線上會有源源不斷的數據點(Data Point)寫入,數據點由時間戳和值組成。OpenTSDB支持秒級(10位整數),毫秒級別(13位整數)兩種時間精度。3d
舉個例子,好比咱們監控一個手環收集的心跳信息,那麼咱們能夠這樣定義:code
Metric: "band.heartbeat" Tags: "id" # 只定義一個tag,就是手環的ID
那麼咱們經過 band.heartbeat
+ id=1
就能查詢到編爲1的手環收集到的心跳信息。blog
這個設計有幾個特色:
salt:打散同一metric不一樣時間線的熱點
metric, tagK, tagV:實際存儲的是字符串對應的UID(在tsdb-uid表中)
timestamp:每小時數據存在一行,記錄的是每小時整點秒級時間戳
它們長度默認是3個字節,即最多隻能分配 2^24=16777216
個UID。能夠經過這些參數調整:
tsd.storage.uid.width.metric # metric UID長度,默認3 tsd.storage.uid.width.tagk # tagK UID長度,默認3 tsd.storage.uid.width.tagv # tagV UID長度 默認3 # 這3者的UID分配分別是獨立的空間
注意:
集羣已經寫過數據後就沒法修改,因此最好是一開始就肯定好,建議4個字節。由於使用壓縮技術後,RowKey多佔的幾個字節能夠忽略,下文會提到。
salt這個東西最好根據本身HBase集羣規模去配置,它有2個配置:
tsd.storage.salt.width # 默認1,1基本夠了,不用調整 tsd.storage.salt.buckets # 打散到幾個bucket去,默認20
查詢的時候會併發 tsd.storage.salt.buckets
個Scanner到HBase上,因此若是這個配置太大,對查詢影響比較大,容易打爆HBase。這裏實際上是一個權衡,寫入熱點和查詢壓力。默認20其實我我的以爲有點多,配置3~8就差很少了,固然實際效果還和metric設計有關,若是在一個metric裏設計了不少時間線,那就得配置不少bucket。在一個metric中設計過多時間線,會影響OpenTSDB的查詢效率,因此不建議這麼作。
這個參數也是設置了就不能改的,因此也是要一開始規劃好。
這是列名(HBase中稱爲qualifier)的格式,能夠看到毫米級須要多出2個字節。因此若是你的採集間隔不須要精確到毫秒級別,那請必定使用秒級(10位整數)。Value只能存儲整數和浮點,因此有一個bit存儲Float flag。
這裏你們必定會有疑問,直接經過qualifier長度是4仍是2不就能判斷是秒級精度的數據點,仍是毫秒了麼?爲什麼還須要MS flag這樣一個標記信息?閱讀下面的「壓縮」部分,就能知道爲何。
OpenTSDB有個很常見而且很麻煩的問題,就是整點時候對HBase對流量衝擊。下面2張圖是咱們一個測試集羣只作寫入對效果:
能夠看到會有一個數倍流量的爆發,要持續好久才能消化。這意味着咱們須要更高規格去抗這個峯值。首先咱們要明白OpenTSDB爲啥要作壓縮?在壓縮些什麼東西?
前面提到過OpenTSDB一行一小時的特色,那麼一行裏會有不少KV。表面上看起來好像沒什麼問題,可是實際上對比邏輯視圖和物理視圖你會發現一些問題。
很明顯,每一個KV都記錄了rowX,那rowX就是一個空間浪費。這個空間不只影響成本,還影響查詢效率(畢竟數據多了)。壓縮作的事情就是把多個小KV合成1個大KV,減小這部分浪費。因此壓縮的時候會涉及到對HBase的「讀-寫-刪」,這就是整點HBase IO流量的來源。
那麼咱們有沒有辦法,既作壓縮,同時又消除這部分HBase IO呢?
固然有!咱們能夠把壓縮的邏輯放到HBase內部去。由於HBase自己就須要對HFile作合併工做,這時候HBase自己就會讀寫數據文件,這部分對HDFS的IO不會少,而咱們經過hook在HBase讀出數據後,替換掉要寫入的數據(即壓縮好的數據)。
實現上面這個功能,固然須要必定內核開發量。好消息是經過雲HBase購買頁面購買的時序引擎,已經自帶了上述功能。不論是分離部署模式,仍是混合部署模式。
這個功能的好處顯而易見,消除峯值節省成本,提高集羣穩定性。這樣咱們對一個現有的HBase集羣空閒資源需求就不是那麼高了,徹底能夠複用了。下面是使用此功能後,一樣只作寫入的測試集羣的流量狀況:
本文做者:郭澤暉
本文爲雲棲社區原創內容,未經容許不得轉載。