天天看點

軟體測試 | 普羅米修斯-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 請求向普羅米修斯發送查詢請求:

http://promurl:port/api/v1/query?query=kube_pod_container_info&time=1636457100
           
  • api 路徑都是/api/v1/query
  • 有兩種查詢類型, 這裡面我們用的查詢類型就是 query 類型(還有另一個叫 query_range)
  • 在路徑和查詢類型後跟着的就是 PromQL 語句了。
  • 最後的 time 是時間戳, 代表着查詢的時間基線。 就是我們的 PromQL 是以哪個時間點為基準查詢的。 我們說過普羅米修斯本身就是一個時序資料庫。它預設儲存 14 天的資料, 超過 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" ]
         }
      ]
   }
}
           

響應資料類型

當 API 調用成功後,Prometheus 會傳回 JSON 格式的響應内容,格式如上小節所示。并且在 data 節點中傳回查詢結果。data 節點格式如下:

{
  "resultType": "matrix" | "vector" | "scalar" | "string",
  "result": <value>
}
           

PromQL 表達式可能傳回多種資料類型,在響應内容中使用 resultType 表示目前傳回的資料類型,包括:

  • 瞬時向量:vector

當傳回資料類型 resultType 為 vector 時,result 響應格式如下:

[
  {
    "metric": { "<label_name>": "<label_value>", ... },
    "value": [ <unix_time>, "<sample_value>" ]
  },
  ...
]
           

其中 metrics 表示目前時間序列的特征次元,value 隻包含一個唯一的樣本。

  • 區間向量:matrix

當傳回資料類型 resultType 為 matrix 時,result 響應格式如下:

[
  {
    "metric": { "<label_name>": "<label_value>", ... },
    "values": [ [ <unix_time>, "<sample_value>" ], ... ]
  },
  ...
]
           

其中 metrics 表示目前時間序列的特征次元,values 包含目前事件序列的一組樣本。

  • 标量:scalar

當傳回資料類型 resultType 為 scalar 時,result 響應格式如下:

[ <unix_time>, "<scalar_value>" ]
           

由于标量不存在時間序列一說,是以 result 表示為目前系統時間一個标量的值。

  • 字元串:string

當傳回資料類型 resultType 為 string 時,result 響應格式如下:

[ <unix_time>, "<string_value>" ]
           

字元串類型的響應内容格式和标量相同。

區間資料查詢

使用 QUERY_RANGE API 我們則可以直接查詢 PromQL 表達式在一段時間傳回内的計算結果。

GET /api/v1/query_range
           

URL 請求參數:

  • query=: PromQL 表達式。
  • start=: 起始時間。
  • end=: 結束時間。
  • step=: 查詢步長。
  • timeout=: 逾時設定。可選參數,預設情況下使用-query,timeout 的全局設定。

當使用 QUERY_RANGE API 查詢 PromQL 表達式時,傳回結果一定是一個區間向量:

{
  "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" ]
            ]
         }
      ]
   }
}
           

實戰示範

最近做了一個資源優化專項,目的是實際了解一下業務運作時産品 160+ 的服務每個服務所使用的 cpu 和記憶體情況。 并對比他們申請的 request 和 limit 的值,計算服務是否申請了過多的資源導緻資源浪費。 是以我們要通過 HTTP PromQL 把相關的資料查詢出來。

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) 的方式統計出每個 pod 的 cpu 使用率總和。 這裡我們使用的就是一個 query_range 的查詢類型。

因為我們希望查詢在測試期間的 2 個小時内 cpu 使用率的最大值和平均值。 是以我們在請求最後使用step=30這個參數來指定每個 30s 計算一次名額,然後我們再使用 start 和 end 參數指定了一個時間範圍。是以在指定的這 2 個小時内,每隔 30s 就會使用 PromQL 查詢一次,這樣傳回結果裡我們就有了很多個采樣資料, 反應了随着時間變化 CPU 使用率的情況。 這時候我們再編寫 python 代碼把傳回的 json 取出來計算最大值和平均值即可。

搜尋微信公衆号:TestingStudio霍格沃茲的幹貨都很硬核