OpenTSDB 开发指南之 查询数据
前面博主寫了一篇文章去介紹opentsdb的http接口的使用方法,但是某一些接口的使用還是比較復雜,這篇文章會通過example來詳細講述opentsdb的一些特性。
本文的舉的例子有這些:
一、基本的寫入和查詢
這個功能是最基本,也是最常用的。
寫數據:寫入數據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}} ]在平常使用過程中我們可以使用單個或者多個子查詢,還有需要注意對于每個子查詢而言,主要有兩種類型:
四、查詢中的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中創建一棵樹步驟如下:
現在按照上面的流程進行操作實際一遍,首先對時間序列、數的規則進行說明。
現在我們有如下的時間序列數據:
圖1
這些時間序列需要滿足如下規則(rules),level表示數的第幾層,order表示同一level的不同rule有不同的優先級。level 0 有兩個rule,當滿足order為0的rule時,會跳過order為1的rule;反之order為1的rule就會生效。
圖2
基于上面的時間序列和tree的規則,可以得到下面的tree:
圖3
下面按照步步驟對這棵樹進行生成:
?
{"name":"Network","description":"","notes":"","rules":null,"created":1368964815,"strictMatch":false,"storeFailures":false,"enabled":false}創建成功后 可以用 get方式請求 /api/tree 接口查詢tree的相關信息,并可以獲得新創建tree的id,treeId下面也會用到。
?
{"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}| treeId | 用于指定測試的tree |
| tsuids | 指定時間序列,試圖將這些時間序列放入這顆樹中進行測試,多個tsuid以 ","相隔 |
這里的tsuids當然是指圖1中時間序列對應的tsuid,可以用 /api/query接口進行查詢。
/api/tree/test會返回這些時間序列基于這棵樹的層次關系,若這個層次結構不滿足需求則需要對rule進行修改,若滿則需求則可進行下一步。
至此這棵樹的定義就已經完成,可以用 /api/tree/branch 接口對tree的分支進行查詢,查詢的參數有兩個:
| treeid | tree的id |
| branch | branch的id |
兩個參數只需要一個,當傳遞treeid時,就會返回root branch的信息。當只傳遞branch時,就會返回對應branch的信息。當兩個參數都傳遞時,參數treeid就會被忽略。
?
總結
以上是生活随笔為你收集整理的OpenTSDB 开发指南之 查询数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hive - HWI 简单使用
- 下一篇: Hbase Compaction 源码分