前面博主寫了一篇文章去介紹opentsdb的http接口的使用方法,但是某一些接口的使用還是比較複雜,這篇文章會通過example來詳細講述opentsdb的一些特性。
本文的舉的例子有這些:
- 基本的寫入和查詢
- 數據的註釋和說明
- 子查詢
- 查詢中的filters使用
- 查詢數據的rate(增長率)
- 直方圖中百分位數(percentiles)的查詢
- Downsampling(下采樣)
- query/exp 的使用(查詢中使用表達式)
- trees詳解
一、基本的寫入和查詢
這個功能是最基本,也是最常用的。
寫數據:寫入數據post接口爲 /api/put?details,details表示會將寫入的詳細結果返回回來:
#請求體
[
{
"metric": "sys.cpu.nice",
"timestamp": 1346846402,
"value": 18,
"tags": {
"host": "web01",
"dc": "lga"
}
}
]
#寫入成功返回的內容
{
"success": 1,
"failed": 0,
"errors": []
}
查數據:寫入成功之後,當然可以去查詢。查詢post接口爲 /api/query:
#請求體
{
"start": 1346846402,
"end": 1346846403,
#返回數據對應的tsUID
"showTSUIDs":"true",
"queries": [
{
"aggregator": "avg",
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
}
}
]
}
#返回數據
[
{
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000001000002000002" #數據對應的tsUID
],
"dps": {
"1346846402": 18
}
}
]
這裏需要對tsUID進行說明一下,opentsdb是由metric+tags來區分數據的,當metric和tags相同時,其tsUID就會相同,代表着同一系列的數據。那麼,假如我們想對這一系列數據進行標註和說明呢?見下一個example。
二、數據的註釋和說明
數據的註釋和說明是用到了 /api/annotation 接口,post方式是寫入annotation數據,get是查詢annotation數據。
#post接口的請求body
{
"startTime":"1346846402",
#和返回前面一個example返回tsUID相同,這樣時間序列數據就和annotation數據關聯了起來,可作爲時間序列數據的註釋和說明
"tsuid":"000001000001000001000002000002",
"description": "Testing Annotations",
"notes": "These would be details about the event, the description is just a summary",
"custom": {
"owner": "jdoe",
"dept": "ops"
}
}
當寫入成功時間,再次運行查詢example1中的 /api/query 請求,即可得到:
[
{
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000001000002000002"
],
"annotations": [
{
"tsuid": "000001000001000001000002000002",
"description": "Testing Annotations",
"notes": "These would be details about the event, the description is just a summary",
"custom": {
"owner": "jdoe",
"dept": "ops"
},
"startTime": 1346846402,
"endTime": 0
}
],
"dps": {
"1346846402": 18
}
}
]
可見,此次在返回數據的清楚上,把相關聯的註釋(annotation數據)也一起返回回來,註釋一般可以用來解釋和說明數據。
三、子查詢
在 /api/query 接口中,body中有一個參數是queries,它表示可以含有多個子查詢,所謂子查詢就是隻要數據滿足其中的一個子查詢,數據就會返回回來。注意每次查詢至少需要一個子查詢。
在example1中寫入一條數據的前提下,這裏再向tsdb中寫入一條數據:
[
{
"metric": "sys.cpu.nice",
"timestamp": 1346846402,
"value": 9,
"tags": {
"host": "web02",
"dc": "lga"
}
}
]
# 通過 /api/query 接口我們可以查得該條數據的tsUID爲000001000001000003000002000002
下面查詢body就表示有兩個子查詢:
//請求體
{
"start": 1346846401,
"end": 1346846403,
"showTSUIDs":"true",
"queries": [
{ //第一個子查詢,查詢的是example1中寫入的數據
"aggregator": "avg",
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
}
},
{ //第二個子查詢,查詢的是剛剛寫入的數據
"aggregator": "avg",
"tsuids":["000001000001000003000002000002"]
}
]
}
//返回結果
[
{ //第一個子查詢對應的數據
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000001000002000002"
],
"annotations": [
{
"tsuid": "000001000001000001000002000002",
"description": "Testing Annotations",
"notes": "These would be details about the event, the description is just a summary",
"custom": {
"owner": "jdoe",
"dept": "ops"
},
"startTime": 1346846402,
"endTime": 0
}
],
"dps": {
"1346846402": 18
}
},
{ //第二個子查詢對應的數據
"metric": "sys.cpu.nice",
"tags": {
"host": "web02",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000003000002000002"
],
"dps": {
"1346846402": 9
}
}
]
在平常使用過程中我們可以使用單個或者多個子查詢,還有需要注意對於每個子查詢而言,主要有兩種類型:
- metric查詢方式:子查詢指定metric和tags(optional)進行查詢,本次查詢中的第一個子查詢就是採用這種方式。
- TSUID查詢方式:需要給出一個或者多個tsuid,對應本次查詢中的第二個子查詢。
四、查詢中的filters使用
從opentsdb2.2版本便支持filter,它其實是用於過濾tags的,可以作爲tags查詢的替代者,並且比tags更加靈活。請求body如下:
{
"start": 1346846401,
"end": 1346846403,
"showTSUIDs":"true",
"queries": [
{
"aggregator": "avg",
"metric": "sys.cpu.nice",
"filters": [
{
"type":"literal_or",
"tagk":"host",
"filter":"web01|web02",
"groupBy":true
}
]
}
]
}
參數 | 意義 |
---|---|
type | 過濾器的類型,可以訪問 /api/config/filters 接口查看支持的所有類型,這裏 literal_or 表示value是一個枚舉 |
tagk | 指定過濾的key |
filter | 和相type對應,這裏表示對web01和web02都進行匹配 |
groupBy | 是否對匹配到的數據進行分組 |
這裏使用literal_or,filter裏面的多個tagV以豎線相隔,這個過濾器的意思是對tagK爲host進行匹配,並且value爲web01和web02都數據都會匹配成功。
返回結果:
[
{
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000001000002000002"
],
"annotations": [
{
"tsuid": "000001000001000001000002000002",
"description": "Testing Annotations",
"notes": "These would be details about the event, the description is just a summary",
"custom": {
"owner": "jdoe",
"dept": "ops"
},
"startTime": 1346846402,
"endTime": 0
}
],
"dps": {
"1346846402": 18
}
},
{
"metric": "sys.cpu.nice",
"tags": {
"host": "web02",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000003000002000002"
],
"dps": {
"1346846402": 9
}
}
]
可見本次filter查詢用一個子查詢的結果和example3中用了兩個子查詢的效果是一樣的。
五、查詢數據的rate(增長率)
在某些情況下,我們查詢的可能並不是數據的本身,而是它的增長率。恰巧opentsdb有幫我們提供這個功能:子查詢中的rate參數。
首先我們先寫入3條數據,時間分別間隔兩秒,數據分別爲0、64000和1000。
[
{
"metric": "sys.cpu.nice",
"timestamp": 1346846410,
"value": 0,
"tags": {
"host": "web03",
"dc": "lga"
}
},
{
"metric": "sys.cpu.nice",
"timestamp": 1346846412,
"value": 64000,
"tags": {
"host": "web03",
"dc": "lga"
}
},
{
"metric": "sys.cpu.nice",
"timestamp": 1346846414,
"value": 1000,
"tags": {
"host": "web03",
"dc": "lga"
}
}
]
查詢增長率的請求body如下:
{
"start": 1346846409,
"end": 1346846414,
"showTSUIDs":"true",
"queries": [
{
"aggregator": "avg",
"metric": "sys.cpu.nice",
"rate":true, # 查詢增長率
"rateOptions":{
"counter":false
},
"tags": {
"host": "web03",
"dc": "lga"
}
}
]
}
# 響應結果
[
{
"metric": "sys.cpu.nice",
"tags": {
"host": "web03",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000007000002000002"
],
"dps": {
"1346846412": 32000,
"1346846414": -31500
}
}
]
3200=(6400-0)/2,-31500=(1000-6400)/2,可見增長率是以秒爲單位。
六、直方圖中百分位數(percentiles)的查詢
opentsdb在2.4版本對直方圖(histogram進行了支持),本個example中首先寫入直方圖數據,然後根據數據對百分位數(percentile)進行查詢。
寫入數據的body如下:buckets是直方圖數據,意思爲0到1.75區間的數值爲12,1.75到3.5區間的數值爲16.
{
"metric": "sys.cpu.nice",
"timestamp": 1356998400,
"overflow": 1,
"underflow": 0,
"buckets": {
"0,1.75": 12,
"1.75,3.5": 16
},
"tags": {
"host": "web01",
"dc": "lga"
}
}
關於百分位的定義可以自行查資料進行詳細認識,本次查詢中percentiles列表裏面就是需要查詢的百分位,需要注意的是列表裏面的數字的取值區間是[0,100],並且可以不按照順序排列。查詢body如下:
{
"start": 1356998400,
"end": 1356998401,
"showTSUIDs":"true",
"queries": [
{
"aggregator": "sum",
"percentiles": [100,99,43,42,1],
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
}
}
]
}
請求的結果如下:
[
{
"metric": "sys.cpu.nice_pct_1.0",
"tags": {
"host": "web01",
"dc": "lga"
},
"aggregateTags": [],
"tsuids": [
"000001000001000001000002000002"
],
"dps": {
"1356998400": 0.875
}
},
{
"metric": "sys.cpu.nice_pct_42.0",
···
"dps": {
"1356998400": 0.875
}
},
{
"metric": "sys.cpu.nice_pct_43.0",
···
"dps": {
"1356998400": 2.625
}
},
{
"metric": "sys.cpu.nice_pct_99.0",
···
"dps": {
"1356998400": 2.625
}
},
{
"metric": "sys.cpu.nice_pct_100.0",
···
"dps": {
"1356998400": 2.625
}
}
]
返回內容如上:其中相同部分已經省略,返回的metric由 原始metric_pct_number 組成,下面講述它們的計算方式:
第一個區間的數值爲12,第二個區間的數值爲16,12/(12+16)=0.428。
- 我們看到1和42的百分位的取值都是0.875,0.875=1.75/2,取的第一個區間的中點座標,可以得到在0.428之前的百分位的數值都爲0.875。
- 43、99、100百分位對應的數值都爲2.625,2.625=1.75+(3.5-1.75)/2,2.625的物理意義就是第二個區間中點的橫座標,因此43到100之間的百分位取值都爲2.525。
七、Downsampling(下采樣)
下采樣即讓濃密數據變稀疏的過程,首先寫入10條數據,數值分別爲0到9,相鄰數據的時間間隔爲1s:
[
{
"timestamp": 1562068000,
"value": 0,
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
}
},
······
{
"metric": "sys.cpu.nice",
"timestamp": 1562068009,
"value": 9,
"tags": {
"host": "web01",
"dc": "lga"
}
}
]
下采樣查詢如下,downsample字段是一個字符串,該字段由 interval-aggregate-fill policy 組成,分別表示時間間隔、聚合方法、缺少的值補齊的方法。本次查詢下采樣間隔爲2s,聚合方法是取聚合區間的最小值,並且缺少的值用0補齊:
{
"start": 1562068000,
"end": 1562068009,
"queries": [
{
"aggregator": "avg",
"metric": "sys.cpu.nice",
"downsample":"2s-min-zero",
"tags": {
"host": "web01",
"dc": "lga"
}
}
]
}
返回結果如下,可見原本每秒一個數據在結果中是每兩秒返回一個數據,並且在每個間隔中,都是取的最小值。
[
{
"metric": "sys.cpu.nice",
"tags": {
"host": "web01",
"dc": "lga"
},
"aggregateTags": [],
"dps": {
"1562068000": 0,
"1562068002": 2,
"1562068004": 4,
"1562068006": 6,
"1562068008": 8
}
}
]
八、query/exp 的使用(查詢中使用表達式)
這個接口允許使用表達式進行查詢,可以對查詢的多個結果進行操作。
在example7寫入數據的基礎上,再寫入如下數據,相比example7的數據而言僅僅是metric發生了變化:
[
{
"timestamp": 1562068000,
"value": 0,
"metric": "sys.cpu.nice1",
"tags": {
"host": "web01",
"dc": "lga"
}
},
······
{
"metric": "sys.cpu.nice1",
"timestamp": 1562068009,
"value": 9,
"tags": {
"host": "web01",
"dc": "lga"
}
}
]
緊接着使用表達式進行查詢,查詢body如下,
- time 定義了查詢的時間區間和聚合方式
- filters 定義了一個過濾器f1
- metric 中指定了對sys.cpu.nice和sys.cpu.nice1兩個metric進行查詢,並且兩個metric都使用同一個filter:f1
- expressions 中是語法表達式,e就等於結果a加上結果b,e2就等於e乘以2
- outputs 指定需要輸出的表達式計算結果
{
"time": {"start": "1562068000","end":"1562068009","aggregator":"sum"},
"filters": [{ "tags": [{"type": "wildcard","tagk": "host","filter": "web*","groupBy": true}],
"id": "f1"}],
"metrics": [{"id": "a","metric": "sys.cpu.nice","filter": "f1","fillPolicy":{"policy":"nan"}},
{"id": "b", "metric": "sys.cpu.nice1","filter": "f1","fillPolicy":{"policy":"nan"}}],
"expressions": [{"id": "e","expr": "a + b"},
{"id":"e2","expr": "e * 2"}],
"outputs":[{"id":"e", "alias":"e"},{"id":"e2", "alias":"e2"}]
}
查詢結果如下,query是裏面是關於查詢請求body的信息,爲了節約空間這裏省略。可以得知表達式計算是對同一個時間點進行計算的。
- outputs中的e,時間點1562068001000對應的值爲2,sys.cpu.nice和sys.cpu.nice1在1562068001000對應的數值都爲1,便可和表達式中 e=a+b 對應起來。
- e2中時間點1562068001000對應的值爲4,便可和表達式中 e2=ex2 對應起來。
{
"outputs": [
{
"id": "e",
"alias": "e",
"dps": [ [1562068000000,0],[1562068001000,2],[1562068002000,4],[ 1562068003000, 6],[1562068004000,8],[1562068005000,10],[1562068006000,12],[1562068007000,14],[1562068008000,16],[1562068009000,18] ],
"dpsMeta": { "firstTimestamp": 1562068000000,"lastTimestamp": 1562068009000, "setCount": 10,"series": 1
},
"meta": [{"index":0,"metrics":["timestamp"]},{"index":1,"metrics":["sys.cpu.nice","sys.cpu.nice1"],"commonTags":{"host":"web01","dc":"lga"},"aggregatedTags":[]}]
},
{
"id": "e2",
"alias": "e2",
"dps": [[1562068000000,0],[1562068001000,4],[1562068002000,8],[1562068003000,12],[1562068004000,16],[1562068005000,20],[1562068006000,24],[1562068007000,28],[1562068008000,32],[1562068009000,36]],
"dpsMeta": { "firstTimestamp": 1562068000000,"lastTimestamp": 1562068009000,"setCount": 10,"series": 1},
"meta": [{"index":0,"metrics":["timestamp"]},{"index":1,"metrics":["sys.cpu.nice","sys.cpu.nice1"],"commonTags":{"host":"web01","dc":"lga"},"aggregatedTags":[]}]
}
],
"query": {
······
}
}
九、trees詳解
opentsdb2.0版本引入了tree的概念,tree可以將一些時間序列組織起來使其具有層次結構,和文件系統一樣,tree中的葉子類比於文件系統的文件,tree中的branch類比於文件系統的文件夾,還可以繼續在裏面創建新的文件夾。其相關定義可參考官網。
在tsdb中創建一棵樹步驟如下:
- 首先創建一棵樹,此時數的enable屬性爲false。
- 爲這棵樹定義一些規則,數的形狀和數據是由這些規則確定。
- 可以通過/api/tree/test接口對這棵樹進行測試,看其接口是否滿足要求。
- 將樹的enable設爲true。
- 運行./tsdb uid treesync掃描TSMeta中的全部對象,將符合條件的時間序列加入到樹中。注意:若需要每創建一個TSMeta對象時,都試圖將對象加入到enable tree中,那麼在啓動tsdb時需要加上 tsd.core.tree.enable_processing=true 配置。
現在按照上面的流程進行操作實際一遍,首先對時間序列、數的規則進行說明。
現在我們有如下的時間序列數據:
圖1
這些時間序列需要滿足如下規則(rules),level表示數的第幾層,order表示同一level的不同rule有不同的優先級。level 0 有兩個rule,當滿足order爲0的rule時,會跳過order爲1的rule;反之order爲1的rule就會生效。
圖2
基於上面的時間序列和tree的規則,可以得到下面的tree:
圖3
下面按照步步驟對這棵樹進行生成:
- 寫入圖一中的輸入,請求body此處略。
- 創建一棵樹,post接口爲 /api/tree,請求body如下:
{"name":"Network","description":"","notes":"","rules":null,"created":1368964815,"strictMatch":false,"storeFailures":false,"enabled":false}
創建成功後 可以用 get方式請求 /api/tree 接口查詢tree的相關信息,並可以獲得新創建tree的id,treeId下面也會用到。
- 利用接口 /api/tree/rule接口,依次創建圖2中的4個rule,請求body分別如下:
{"type":"tagk","field":"dc","description":"a tagk named data center","level":0,"order":0,"treeId":1}
{"type":"tagk","field":"host","description":"a tagk named host","regex":".*\\.(.*)\\.mysite\\.com","level":0,"order":1,"treeId":1}
{"type":"tagk","field":"host","description":"a tagk named host","separator":"\\.","level":1,"order":0,"treeId":1}
{"type":"metric","description":"metric","separator":"\\.","level":2,"order":0,"treeId":1}
- 利用/api/tree/test 接口測試我們新創建的tree,get請求有兩個參數:
參數名 | 意義 |
---|---|
treeId | 用於指定測試的tree |
tsuids | 指定時間序列,試圖將這些時間序列放入這顆樹中進行測試,多個tsuid以 ","相隔 |
這裏的tsuids當然是指圖1中時間序列對應的tsuid,可以用 /api/query接口進行查詢。
/api/tree/test會返回這些時間序列基於這棵樹的層次關係,若這個層次結構不滿足需求則需要對rule進行修改,若滿則需求則可進行下一步。
- 在tsdb的build文件夾運行 ./tsdb uid treesync 命令,它會掃描全部的 tsdb-uid,將符合條件的序列加入到tree的結構中。
至此這棵樹的定義就已經完成,可以用 /api/tree/branch 接口對tree的分支進行查詢,查詢的參數有兩個:
參數名 | 意義 |
---|---|
treeid | tree的id |
branch | branch的id |
兩個參數只需要一個,當傳遞treeid時,就會返回root branch的信息。當只傳遞branch時,就會返回對應branch的信息。當兩個參數都傳遞時,參數treeid就會被忽略。