Opentsdb設計之道

OpenTSDB是基於HBase存儲時間序列數據的一個開源數據庫,確切地說,它只是一個HBase的應用而已,其對於時間序列數據的處理可以供其他系統參考和借鑑。本文會針對它在數據庫的設計方面展開一些探索和討論。本文原文鏈接:http://blog.csdn.net/bluishglc/article/details/31052749,轉載請註明出處!

本文基於的是OpenTSDB最早的一個穩定版本1.0.0進行講解的,下載部署完成之後,我們首先需要了解的是它的數據庫Schema, 它主要有兩個表:tsdb-uid和tsdb. 前者描述指標(metrics)相關的元數據,後者存儲時間序列數據。首先我們來了解一下“指標”(metrics)的概念,簡單講一個指標就是一個需要收集的數據項,但是隻有指標是不能全面地描述出一條數據產生的相關背景信息的,比如:如果我們要統計cpu的使用率,我們可以建立一下名爲proc.stat.cpu的metrics,如果我們從不同的機器和用戶下收集了大量的cpu信息,如果沒有對一條信息進行一定地標識,我們是無法區分出哪些數據來自哪臺機器的哪個用戶,所以我們還需要建立一些“標籤”(Tag)來標識一條數據。嚴格地說,指標和標籤之間並沒有必然的從屬關係,就像兩個不同的指標的數據可能都有指示其來自哪臺主機的host標籤一樣,但是有一點是確定的,即:對於一條數據來說,應該至少含有一個指標和一個標籤,這樣的數據纔是有意義的,因此,在OpenTSDB的表設計上,就把指標”(metrics)和“標籤”(Tag)統一放在了tsdb-uid表中存儲,格式爲:RowKey(自增ID,3字節數組):name:metrics,name:tagk,name:tagv同時對它們之間的反向關聯關係也作了展開存儲。

實際上我們看以看到,對於數據來說,指標到數據是一對多的父子關係,標籤對數據也是一對多的父子關係,OpenTSDB在這裏的設計是非常具有典型性的,實際上這也是HBase表設計上的一種常見的“Pattern”把表間關聯關係展開,以JOIN的結果爲RowKey存儲數據!包括正向關聯和反向關聯兩類數據!(請仔細參考圖1理解)

下面讓我們插入2個metrics:proc.stat.cpuproc.stat.mem,以及一條記錄: proc.stat.cpu 1297574486 54.2 host=foo type=user來觀察一下數據表結構

首先是tsdb-uid表:


圖一


從表中的記錄可知:

1. 第一條記錄:rowkey爲\x00,含3個字段:metrics,tagk,tagv, 其值分別是已經添加的所有指標、標籤名和標籤值的數量。這一條數據是系統生成和維護的。這裏有兩個metrics:cpu和mem,兩個key:host和type,兩個value:foo和user,所以 rowkey爲\x00的三個數據的value都是2

2. 一個UID是針對一種指標+一種標籤名+一種標籤值的組合分配的,即一種指標+一種標籤名+一種標籤值 = 一個UID,也就是說:一個UID對應的一種指標+一種標籤名+一種標籤值的組合纔是可以單獨抽取出來時行統計的最小單位!

然後我們看tsdb表:

圖二

我們看重點看一下紀錄表的rowkey:

指標UID(指標+標籤的某個組合)+ 數據生成時間(取整點時間)+標籤1-Key的UID+標籤1-Vlaue的UID+...+標籤N-Key的UID+標籤N-Vlaue的UID

讓我們以圖紀錄爲例,重點看一下時間的處理:

1297574486 = 2011-02-13 13:21:26    

MWeP = 01001101 01010111 01100101 01010000 = 1297573200 = 2011-02-13 13:00:00 (截取整點小時位)

PK = 01010000 01101011 = 1286 (從整點小時到記錄時間的秒偏差,1286秒正是21分鐘26秒)

1297573200+1286=1297574486

PK,即小時內秒數被當作了Column

一些設計技巧:

1. 針對Hot Spot的應對策略

OpenTSDB處理的是典型的時間序列化數據,必然面臨“熱點”問題,關於它對熱點問題的處理,HBase的官方文檔 http://hbase.apache.org/book/rowkey.design.html 中專門提到過:

 However, the difference is that the timestamp is not in the lead position of the key, and the design assumption is that there are dozens or hundreds (or more) of different metric types. Thus, even with a continual stream of input data with a mix of metric types, the Puts are distributed across various points of regions in the table.    

一般來說,如果使用時間做rowkey,那麼前面就必須加“哈希”字段(也就是salted處理)。但是OpenTSDB並沒有特別的哈希字段,它的處理比較聰明:首先,時間字段不會放在rowkey的開始位置,其次,rowkey開始位置挑選了自身的一個理想的業務字段“metrics"來替代了“哈希”字段。

從OpenTSDB的處理上我們可以總結出一點:在處理時間序列數據時,如果系統中存在“理想的”“天然的”起哈希作用的字段應該優先考慮其作爲rowkey的起始組成部分,後接時間字段,但如果找不到這樣的字段再設置人工的哈希字段


2. rowkey的設計思想

一.爲了能夠檢索特定的metrics,tag name,tag name的data point, 將 metrics,tag name,tag name編入rowkey是顯然的事情,但是直接使用它們來組成rowkey有兩個明顯的問題:
1. 會佔用大量的存儲空間(因爲這些值會大量重複地出現在很多的rowkey中)
2. 由於每一個metrics,tag key,tag value的長度都是不固定的,這不利於通過字節偏移量來直接定位它們.(否則需要使用特定的分隔符,而且爲了避免輸入信息中可能存在特定的分隔符導致解析出錯,還要對所有輸入信息的分割符進行轉義處理)

圍繞一個性能指標,會有多種附加"屬性"(或者說"標籤")對其進行說明與描述, 那麼對指標的查詢也自然是以這些標籤或標籤值展開的,因此一條指標記錄的rowkey必然要包含這些標籤和標籤值.但是由於標籤和標籤值是不定長的,這爲rowkey的設計帶來麻煩,所以需要爲這些標籤和標籤值分配一個定長的ID,在rowkey中使用它們的ID來指代它們,這樣rowkey就可以規範化,方便從rowkey中直接通過偏移截取需要的"部分".
二.Tall-Narrow和Wide-Flat兩種表設計風格相結合
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章