軟件測試 | 普羅米修斯-HTTP API調用PromQL
簡介
Prometheus API 使用了 JSON 格式的響應內容。 當 API 調用成功后將會返回查詢結果。所有的 API 請求均使用以下的 JSON 格式:
{
?
"status": "success" | "error",?
??"data": <data>,
?
// Only set if status is "error". The data field may still hold?
?// additional data.?
?"errorType": "<string>",?
?"error": "<string>"?
}
我們可以通過如下的 get 請求向普羅米修斯發(fā)送查詢請求:
http://promurl:port/api/v1/query?query=kube_pod_container_info&time=1636457100
api 路徑都是
/api/v1/query
有兩種查詢類型, 這里面我們用的查詢類型就是 query 類型(還有另一個叫 query_range)
在路徑和查詢類型后跟著的就是 PromQL 語句了。
最后的 time 是時間戳, 代表著查詢的時間基線。 就是我們的 PromQL 是以哪個時間點為基準查詢的。 我們說過普羅米修斯本身就是一個時序數(shù)據(jù)庫。它默認保存 14 天的數(shù)據(jù), 超過 14 天就會自動刪除。 所以這個時間戳可以讓我們以過去某個時間點為基礎進行查詢。如果在 UI 上查詢的話,只能以當前時間為基線進行查詢。
下面貼一個例子看一下我們查詢的 json 結果是什么樣子的:
$ curl 'http://localhost:9090/api/v1/query?query=up&time=2015-07-01T20:10:51.781Z'
?{
?
?"status" : "success",?
?? "data" : {?
? ? ?"resultType" : "vector",
?
? ?"result" : [
? ?
? ? {
? ??
? ? ? ?"metric" : {
? ??
? ? ? ? ? "__name__" : "up",
? ??
? ? ? ? ? "job" : "prometheus",
? ??
? ? ? ? ? "instance" : "localhost:9090"
??
? ? ? ? ?},
? ? ??
? ? ?"value": [ 1435781451.781, "1" ]
?
?? ? ? },?
? ? ? ? {
? ? ??
? ? ?"metric" : {
? ?
? ? ? ? ? "__name__" : "up",
? ?
? ? ? ? ? "job" : "node",
?
?? ? ? ? ? ? "instance" : "localhost:9100"
? ?
?? ? ? ?},
? ? ? ??
? ?"value" : [ 1435781451.781, "0" ]
??
? ? ? }
?
?? ?]
?
?}?
}
響應數(shù)據(jù)類型
當 API 調用成功后,Prometheus 會返回 JSON 格式的響應內容,格式如上小節(jié)所示。并且在 data 節(jié)點中返回查詢結果。data 節(jié)點格式如下:
{?
??"resultType": "matrix" | "vector" | "scalar" | "string",?
?"result": <value>?
}
PromQL 表達式可能返回多種數(shù)據(jù)類型,在響應內容中使用 resultType 表示當前返回的數(shù)據(jù)類型,包括:
瞬時向量:vector
當返回數(shù)據(jù)類型 resultType 為 vector 時,result 響應格式如下:
[?
?{
? ?
"metric": { "<label_name>": "<label_value>", ... },?
?? ?"value": [ <unix_time>, "<sample_value>" ]?
?},
?
...?
]
其中 metrics 表示當前時間序列的特征維度,value 只包含一個唯一的樣本。
區(qū)間向量:matrix
當返回數(shù)據(jù)類型 resultType 為 matrix 時,result 響應格式如下:
[
?
{
??
?"metric": { "<label_name>": "<label_value>", ... },?
?? ?"values": [ [ <unix_time>, "<sample_value>" ], ... ]?
?},
?
...?
]
其中 metrics 表示當前時間序列的特征維度,values 包含當前事件序列的一組樣本。
標量:scalar
當返回數(shù)據(jù)類型 resultType 為 scalar 時,result 響應格式如下:
[ <unix_time>, "<scalar_value>" ]
由于標量不存在時間序列一說,因此 result 表示為當前系統(tǒng)時間一個標量的值。
字符串:string
當返回數(shù)據(jù)類型 resultType 為 string 時,result 響應格式如下:
[ <unix_time>, "<string_value>" ]
字符串類型的響應內容格式和標量相同。
區(qū)間數(shù)據(jù)查詢
使用 QUERY_RANGE API 我們則可以直接查詢 PromQL 表達式在一段時間返回內的計算結果。
GET /api/v1/query_range
URL 請求參數(shù):
query=: PromQL 表達式。
start=: 起始時間。
end=: 結束時間。
step=: 查詢步長。
timeout=: 超時設置。可選參數(shù),默認情況下使用-query,timeout 的全局設置。
當使用 QUERY_RANGE API 查詢 PromQL 表達式時,返回結果一定是一個區(qū)間向量:
{
?"resultType": "matrix",
?"result": <value>
}
需要注意的是,在 QUERY_RANGE API 中 PromQL 只能使用瞬時向量選擇器類型的表達式。
例如使用以下表達式查詢表達式 up 在 30 秒范圍內以 15 秒為間隔計算 PromQL 表達式的結果。
$ curl 'http://localhost:9090/api/v1/query_range?query=up&start=2015-07-01T20:10:30.781Z&end=2015-07-01T20:11:00.781Z&step=15s'?
{
??
"status" : "success",
??
"data" : {
?
?? ?"resultType" : "matrix",
?
?? ?"result" : [
? ?
?? ? {
? ? ? ?
?? ?"metric" : {? ??
? ? ? ? ? ?"__name__" : "up",
? ?
?? ? ? ? ? "job" : "prometheus",
? ? ? ?
? ? ? "instance" : "localhost:9090"
? ?
?? ? ? ?},
? ? ??
? ? ?"values" : [
? ? ?
?? ? ? ? [ 1435781430.781, "1" ],
??
? ? ? ? ? ? [ 1435781445.781, "1" ],
?
?? ? ? ? ? ? [ 1435781460.781, "1" ]
??
? ? ? ? ?]
?
?? ? ? },
? ?
?? ? {
? ? ? ? ??
?"metric" : {
? ? ?
?? ? ? ? "__name__" : "up",
? ? ?
?? ? ? ? "job" : "node",
? ? ? ? ??
? ? "instance" : "localhost:9091"
? ?
?? ? ? ?},
? ? ? ? ??
?"values" : [
? ? ? ? ??
? ? [ 1435781430.781, "0" ],
? ? ??
? ? ? ? [ 1435781445.781, "0" ],
? ?
?? ? ? ? ? [ 1435781460.781, "1" ]
??
? ? ? ? ?]
? ?
?? ? }
? ? ?
]
?
?}?
}
實戰(zhàn)演示
最近做了一個資源優(yōu)化專項,目的是實際了解一下業(yè)務運行時產品 160+ 的服務每個服務所使用的 cpu 和內存情況。 并對比他們申請的 request 和 limit 的值,計算服務是否申請了過多的資源導致資源浪費。 所以我們要通過 HTTP PromQL 把相關的數(shù)據(jù)查詢出來。
prom_url = 'http://1.117.219.41:30778'?
start_time = str(int(datetime.strptime("09/11/2021 19:25:00", "%d/%m/%Y %H:%M:%S").timestamp()))
end_time = str(int(datetime.strptime("09/11/2021 21:25:00", "%d/%m/%Y %H:%M:%S").timestamp()))?
result = {}?
r = requests.get(
?
?url='{prom_url}/api/v1/query_range?query=sum(node_namespace_pod_container%3Acontainer_cpu_usage_seconds_total%3Asum_rate%7Bcluster%3D%22cls-hchrqyex%22%7D)%20by%20(pod)&start={start}&end={end}&step=30'.format(
? ? ? ?start=start_time, end=end_time, prom_url=prom_url))?
datas = r.json()['data']['result']?
for data in datas:
?
??pod_name = data['metric']['pod']
??
?cpu_usages = []?
? ?for c in data['values']:
??
? ? ?cpu_usages.append(float(c[1]))
?
??max_value = max(cpu_usages)?
?? ?avg_value = statistics.mean(cpu_usages)
?
??result[pod_name] = {
? ? ??
?'cpu_max_usage': max_value,
??
? ? ?'cpu_avg_usage': avg_value
??
?}
上面代碼中的 PromQL 是sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_rate) by (pod)
?首先 node_namespace_pod_container:container_cpu_usage_seconds_total:sum_rate 是一個預定義的查詢別名。 有些查詢語句過于復雜,所以我們可以給復雜的語句一個別名, 這樣在使用 的時候就比較方便了。 而我們使用的這個別名就如同它的名字一樣, 是查詢每個容器的 cpu 使用率的。 因為一個 pod 里可能會有多個容器, 所以需要使用 sum by (pod) 的方式統(tǒng)計出每個 pod 的 cpu 使用率總和。 這里我們使用的就是一個 query_range 的查詢類型。 因為我們希望查詢在測試期間的 2 個小時內 cpu 使用率的最大值和平均值。 所以我們在請求最后使用step=30
這個參數(shù)來指定每隔 30s 計算一次指標,然后我們在使用 start 和 end 參數(shù)指定了一個時間范圍。所以在指定的這 2 個小時內,每隔 30s 就會使用 PromQL 查詢一次,這樣返回結果里我們就有了很多個采樣數(shù)據(jù), 反應了隨著時間變化 CPU 使用率的情況。 這時候我們再編寫 python 代碼把返回的 json 取出來計算最大值和平均值即可。