OpenTSDB 開發指南之 查詢數據

前面博主寫了一篇文章去介紹opentsdb的http接口的使用方法,但是某一些接口的使用還是比較複雜,這篇文章會通過example來詳細講述opentsdb的一些特性。

本文的舉的例子有這些:

  1. 基本的寫入和查詢
  2. 數據的註釋和說明
  3. 子查詢
  4. 查詢中的filters使用
  5. 查詢數據的rate(增長率)
  6. 直方圖中百分位數(percentiles)的查詢
  7. Downsampling(下采樣)
  8. query/exp 的使用(查詢中使用表達式)
  9. 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
        }
    }
]

在平常使用過程中我們可以使用單個或者多個子查詢,還有需要注意對於每個子查詢而言,主要有兩種類型:

  1. metric查詢方式:子查詢指定metric和tags(optional)進行查詢,本次查詢中的第一個子查詢就是採用這種方式。
  2. 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中創建一棵樹步驟如下:

  1. 首先創建一棵樹,此時數的enable屬性爲false。
  2. 爲這棵樹定義一些規則,數的形狀和數據是由這些規則確定。
  3. 可以通過/api/tree/test接口對這棵樹進行測試,看其接口是否滿足要求。
  4. 將樹的enable設爲true。
  5. 運行./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

下面按照步步驟對這棵樹進行生成:

  1. 寫入圖一中的輸入,請求body此處略。
  2. 創建一棵樹,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下面也會用到。

  1. 利用接口 /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}

  1. 利用/api/tree/test 接口測試我們新創建的tree,get請求有兩個參數:
參數名 意義
treeId 用於指定測試的tree
tsuids 指定時間序列,試圖將這些時間序列放入這顆樹中進行測試,多個tsuid以 ","相隔

這裏的tsuids當然是指圖1中時間序列對應的tsuid,可以用 /api/query接口進行查詢。
/api/tree/test會返回這些時間序列基於這棵樹的層次關係,若這個層次結構不滿足需求則需要對rule進行修改,若滿則需求則可進行下一步。

  1. 在tsdb的build文件夾運行 ./tsdb uid treesync 命令,它會掃描全部的 tsdb-uid,將符合條件的序列加入到tree的結構中。

至此這棵樹的定義就已經完成,可以用 /api/tree/branch 接口對tree的分支進行查詢,查詢的參數有兩個:

參數名 意義
treeid tree的id
branch branch的id

兩個參數只需要一個,當傳遞treeid時,就會返回root branch的信息。當只傳遞branch時,就會返回對應branch的信息。當兩個參數都傳遞時,參數treeid就會被忽略。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章