本篇先來回答語法以外的問題。
本節的問題有兩個:
除了報警系統響時可以間接得知 Prometheus 裡的資料以外,都是靠 http 來傳資料的。
相關 http API 有:
Prometheus 提供一個定時寫出資料的 http client,主要用來把資料寫到下游的資料庫如 InfluxDB、OpenTSDB、Graphite 或是其他 Prometheus。
只要依文件在設定檔裡設定好 remote_write,Prometheus 就會把資料寫出去了。
用 API 來讀取時間序資料都會用到 PromQL,PromQL 有四種運算時的中間型態,但能返回的資料型態基本只有一種。就是一個由時間序列所構成的時間序列集。
這個時間序列集可以只有一個時間序列,也可以有多個時間序列。它們都會有對應的標籤值和樣本值。
如 PromQL: api_http_responses 這個時間序列集可能包含了四個時間序列:
api_http_responses{job="apiserver", handler="/api/comments"} # 1 1 3
api_http_responses{job="apiserver", handler="/api/posts"} # 1 2 3 
api_http_responses{job="ingested", handler="/api/comments"} # 0 7 12
api_http_responses{job="ingested", handler="/api/posts"} # 2 2 4
從而 PromQL: sum(api_http_responses) by (job) 這個時間序列集包含了兩個時間序列:
{job="apiserver"} # 2 3 6
{job="ingested"} # 2 9 16
瞭解了 PromQL 返回的資料型態,就可以知道讀取資料的 API 拿 PromQL 做些什麼了。
/query這個 API 一般用來讀取給定時間點下,PromQL 表達的時間序列集中,每個時間序列當時最新的樣本值。參數有:
query:PromQL 表達式time:要查詢的時間點(預設是 Prometheus 收到 http 的時間)timeout:http 超時時限回傳資料格式是 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" ]
            }
            ]
        }
}
查詢名為 up 的序列集,得兩個時間序列
up{job="prometheus", instance="localhost:9090"}
up{job="node", instance="localhost:9100"}
而這兩個時間序列在查詢時間點的值分別是 1 和 0。
/query_range這個 API 是 /query 的加強版,也是 Grafana 監控面版用的 API。它不只查詢某個時間點的值,而是可以對一段時間內的值間隔取樣計算。參數有:
query:PromQL 表達式start:取樣時間最小值(閉區間)end:取樣時間最大值(閉區間)step:取樣間隔(從 start 開始,每次加 step)timeout:http 超時時限回傳資料格式是 JSON
$ 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:9100"
                },
                "values" : [
                    [ 1435781430.781, "0" ],
                    [ 1435781445.781, "0" ],
                    [ 1435781460.781, "0" ]
                ]
            }
            ]
        }
}
注意到每個樣本值的時間戳記都是 http 所指定的取樣時間,而不是樣本從標的被拉到 Prometheus 的時間。step 越小,樣本值的數量就越多。如果取樣間隔遠小於 Prometheus 拉資料的間隔,回傳的樣本值就會有很多重複的,因為取樣時的樣本值都沒有變。
/query_exemplars這個 API 類似 /query,但它查詢的是指標的範例值(OpenMetrics 規定加在註解的部份)。參數有:
query:PromQL 表達式start:時間最小值(閉區間)end:時間最大值(閉區間)這些 API 用來讀取 Prometheus 裡的中介資料,如標籤值、標籤值的值、時間序列集。這些 API 一般用來幫助使用者查詢 Prometheus 裡有哪些時間序列,或是有哪些標籤值。
/series這個 API 用來查詢 Prometheus 裡有哪些時間序列在給定時間範圍內有值。參數有:
match[]:時間序列的的過濾條件,可以有多個,符合其中一個就會被返回start:時間最小值(閉區間)end:時間最大值(閉區間)limit:最多返回幾個時間序列回傳的資料格式是 JSON。
/labels和 /series 類似,這個 API 用來查詢 Prometheus 裡有哪些標籤。參數同上。
不同的是回傳的就只有標籤名字,而不是時間序列集。
/label/<標籤名>/values這個 API 用來查詢 Prometheus 裡某個標籤名在時間範圍內有哪些值。參數亦同上。
回傳的也只有標籤值。
Grafrana 的標籤選單就是用這個 API 來查詢的。
本節的問題:
在資料不變的情況下,PromQL 所表達的時間序列集是不變的。但這裡的資料是不只是 Prometheus 的存起來的資料,還包含 PromQL 所取樣的時間點。
舉一個極端的例子,如果有一個時間序列 x 在奇數秒的值是 1,偶數秒的值是 0。那麼 PromQL: 1 / x 這個表達式就只有在奇數秒有值。
那麼 query_range?step=2&start=0.5 跟 query_range?step=2&start=1.5 這兩個查詢就會得到不同的結果。query_range?step=2&start=0.5 會得到全部都是 1,而 query_range?step=2&start=1.5 會全部都是 +Inf。