在我看來學(xué)習(xí)Prometheus的基礎(chǔ)就是PromQL,就好比關(guān)系型數(shù)據(jù)庫與SQL一樣艺玲。雖說有很多中間件的監(jiān)控我們可以通過Grafana的模板就已經(jīng)能很好地展示監(jiān)控數(shù)據(jù)了括蝠,但是我們總有要自定義監(jiān)控面板的時候,甚至說要自定義去監(jiān)控企業(yè)內(nèi)部應(yīng)用(如java代碼項目)的時候板驳。這時候又跛,PromQL就派上用場了。下面是書本的截取的部分內(nèi)容:
2.1 理解時間序列
2.1.1 樣本
Prometheus會將所有采集到的樣本數(shù)據(jù)以時間序列(time-series)的方式保存在內(nèi)存數(shù)據(jù)庫中若治,并且定時保存到硬盤上慨蓝。time-series是按照時間戳和值的序列順序存放的,我們稱之為向量(vector). 每條time-series通過指標名稱(metrics name)和一組標簽集(labelset)命名端幼。所以說礼烈,Prometheus server也是一個時序型的數(shù)據(jù)庫。
在time-series中的每一個點稱為一個樣本(sample)婆跑,樣本由以下三部分組成:
- 指標(metric):metric name和描述當(dāng)前樣本特征的labelsets;
- 時間戳(timestamp):一個精確到毫秒的時間戳;
- 樣本值(value): 一個folat64的浮點型數(shù)據(jù)表示當(dāng)前樣本的值此熬。
<-------------- metric ---------------------><--timestamp ---><--value->
http_request_total{status="200", method="GET"}@1434417560938 => 94355
http_request_total{status="200", method="GET"}@1434417561287 => 94334
2.1.2 指標(Metric)
在形式上,所有的指標(Metric)都通過如下格式標示:
<metric name>{<label name>=<label value>, ...}
指標的名稱(metric name)可以反映被監(jiān)控樣本的含義(比如滑进,http_request_total - 表示當(dāng)前系統(tǒng)接收到的HTTP請求總量)犀忱。指標名稱只能由ASCII字符、數(shù)字扶关、下劃線以及冒號組成并必須符合正則表達式[a-zA-Z_:][a-zA-Z0-9_:]*阴汇。
標簽(label)反映了當(dāng)前樣本的特征維度,通過這些維度Prometheus可以對樣本數(shù)據(jù)進行過濾节槐,聚合等搀庶。標簽的名稱只能由ASCII字符、數(shù)字以及下劃線組成并滿足正則表達式[a-zA-Z_][a-zA-Z0-9_]*铜异。
其中以__作為前綴的標簽哥倔,是系統(tǒng)保留的關(guān)鍵字,只能在系統(tǒng)內(nèi)部使用揍庄。標簽的值則可以包含任何Unicode編碼的字符咆蒿。在Prometheus的底層實現(xiàn)中指標名稱實際上是以name=<metric name>的形式保存在數(shù)據(jù)庫中的,因此以下兩種方式均表示的同一條time-series:
api_http_requests_total{method="POST", handler="/messages"}
等同于:
{__name__="api_http_requests_total",method="POST", handler="/messages"}
2.2 Metrics類型
Prometheus定義了4中不同的指標類型(metric type):Counter(計數(shù)器)蜡秽、Gauge(儀表盤)府阀、Histogram(直方圖)、Summary(摘要)芽突。這4中指標類型各有自己的使用場景试浙,比如最開始提到的counter類型(記錄CPU的)寞蚌。
2.2.1 Counter:只增不減的計數(shù)器
Counter類型的指標其工作方式和計數(shù)器一樣田巴,只增不減(除非系統(tǒng)發(fā)生重置)。常見的監(jiān)控指標管宵,如http_requests_total秋度,node_cpu都是Counter類型的監(jiān)控指標。 一般在定義Counter類型指標的名稱時推薦使用_total作為后綴。
Counter是一個簡單但有強大的工具,例如我們可以在應(yīng)用程序中記錄某些事件發(fā)生的次數(shù)牵敷,通過以時序的形式存儲這些數(shù)據(jù)苫亦,我們可以輕松的了解該事件產(chǎn)生速率的變化毛肋。 PromQL內(nèi)置的聚合操作和函數(shù)可以讓用戶對這些數(shù)據(jù)進行進一步的分析:
例如怨咪,通過rate()函數(shù)獲取HTTP請求量的增長率:
rate(http_requests_total[5m])
查詢當(dāng)前系統(tǒng)中,訪問量前10的HTTP地址:
topk(10, http_requests_total)
2.2.2 Gauge:可增可減的儀表盤
與Counter不同润匙,Gauge類型的指標側(cè)重于反應(yīng)系統(tǒng)的當(dāng)前狀態(tài)诗眨。因此這類指標的樣本數(shù)據(jù)可增可減。常見指標如:node_memory_MemFree(主機當(dāng)前空閑的內(nèi)容大性谢洹)匠楚、node_memory_MemAvailable(可用內(nèi)存大小)都是Gauge類型的監(jiān)控指標缺虐。
通過Gauge指標唆香,用戶可以直接查看系統(tǒng)的當(dāng)前狀態(tài):
node_memory_MemFree_bytes
對于Gauge類型的監(jiān)控指標贪薪,通過PromQL內(nèi)置函數(shù)delta()可以獲取樣本在一段時間返回內(nèi)的變化情況。例如与斤,計算CPU溫度在兩個小時內(nèi)的差異:
delta(cpu_temp_celsius{host="zeus"}[2h])
還可以使用deriv()計算樣本的線性回歸模型,甚至是直接使用predict_linear()對數(shù)據(jù)的變化趨勢進行預(yù)測荚恶。例如撩穿,預(yù)測系統(tǒng)磁盤空間在4個小時之后的剩余情況:
predict_linear(node_filesystem_free{job="node"}[1h], 4 * 3600)
2.2.3 使用Histogram和Summary分析數(shù)據(jù)分布情況
除了Counter和Gauge類型的監(jiān)控指標以外,Prometheus還定義了Histogram和Summary的指標類型裆甩。Histogram和Summary主用用于統(tǒng)計和分析樣本的分布情況冗锁。
在大多數(shù)情況下人們都傾向于使用某些量化指標的平均值,例如CPU的平均使用率嗤栓、頁面的平均響應(yīng)時間冻河。這種方式的問題很明顯,以系統(tǒng)API調(diào)用的平均響應(yīng)時間為例:如果大多數(shù)API請求都維持在100ms的響應(yīng)時間范圍內(nèi)茉帅,而個別請求的響應(yīng)時間需要5s叨叙,那么就會導(dǎo)致某些WEB頁面的響應(yīng)時間落到中位數(shù)的情況,而這種現(xiàn)象被稱為長尾問題堪澎。
為了區(qū)分是平均的慢還是長尾的慢擂错,最簡單的方式就是按照請求延遲的范圍進行分組。例如樱蛤,統(tǒng)計延遲在0~10ms之間的請求數(shù)有多少而10~20ms之間的請求數(shù)又有多少钮呀。通過這種方式可以快速分析系統(tǒng)慢的原因。Histogram和Summary都是為了能夠解決這樣問題的存在昨凡,通過Histogram和Summary類型的監(jiān)控指標爽醋,我們可以快速了解監(jiān)控樣本的分布情況。
例如便脊,指標prometheus_tsdb_wal_fsync_duration_seconds的指標類型為Summary蚂四。 它記錄了Prometheus Server中wal_fsync處理的處理時間,通過訪問Prometheus Server的/metrics地址,可以獲取到以下監(jiān)控樣本數(shù)據(jù):
# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.012352463
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.014458005
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.017316173
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
prometheus_tsdb_wal_fsync_duration_seconds_count 216
從上面的樣本中可以得知當(dāng)前Prometheus Server進行wal_fsync操作的總次數(shù)為216次遂赠,耗時2.888716127000002s久妆。其中中位數(shù)(quantile=0.5)的耗時為0.012352463,9分位數(shù)(quantile=0.9)的耗時為0.014458005s跷睦。
在Prometheus Server自身返回的樣本數(shù)據(jù)中筷弦,我們還能找到類型為Histogram的監(jiān)控指標prometheus_tsdb_compaction_chunk_range_bucket。
# HELP prometheus_tsdb_compaction_chunk_range Final time range of chunks on their first compaction
# TYPE prometheus_tsdb_compaction_chunk_range histogram
prometheus_tsdb_compaction_chunk_range_bucket{le="100"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="6400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="25600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="102400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="409600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1.6384e+06"} 260
prometheus_tsdb_compaction_chunk_range_bucket{le="6.5536e+06"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="2.62144e+07"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="+Inf"} 780
prometheus_tsdb_compaction_chunk_range_sum 1.1540798e+09
prometheus_tsdb_compaction_chunk_range_count 780
與Summary類型的指標相似之處在于Histogram類型的樣本同樣會反應(yīng)當(dāng)前指標的記錄的總數(shù)(以_count作為后綴)以及其值的總量(以_sum作為后綴)送讲。不同在于Histogram指標直接反應(yīng)了在不同區(qū)間內(nèi)樣本的個數(shù)奸笤,區(qū)間通過標簽len進行定義。
同時對于Histogram的指標哼鬓,我們還可以通過histogram_quantile()函數(shù)計算出其值的分位數(shù)监右。不同在于Histogram通過histogram_quantile函數(shù)是在服務(wù)器端計算的分位數(shù)。 而Sumamry的分位數(shù)則是直接在客戶端計算完成异希。因此對于分位數(shù)的計算而言健盒,Summary在通過PromQL進行查詢時有更好的性能表現(xiàn),而Histogram則會消耗更多的資源称簿。反之對于客戶端而言Histogram消耗的資源更少扣癣。在選擇這兩種方式時用戶應(yīng)該按照自己的實際場景進行選擇。
2.3 初識PromQL
PromQL是Prometheus內(nèi)置的數(shù)據(jù)查詢語言憨降,其提供對時間序列數(shù)據(jù)豐富的查詢父虑,聚合以及邏輯運算能力的支持。并且被廣泛應(yīng)用在Prometheus的日常應(yīng)用當(dāng)中授药,包括對數(shù)據(jù)查詢士嚎、可視化、告警處理當(dāng)中悔叽±绸茫可以這么說,PromQL是Prometheus所有應(yīng)用場景的基礎(chǔ)娇澎,理解和掌握PromQL是Prometheus入門的第一課笨蚁。
2.3.1 查詢時間序列
當(dāng)Prometheus通過Exporter采集到相應(yīng)的監(jiān)控指標樣本數(shù)據(jù)后,我們就可以通過PromQL對監(jiān)控樣本數(shù)據(jù)進行查詢趟庄。
當(dāng)我們直接使用監(jiān)控指標名稱查詢時括细,可以查詢該指標下的所有時間序列。如:
http_requests_total
等同于:
http_requests_total{}
該表達式會返回指標名稱為http_requests_total的所有時間序列:
http_requests_total{code="200",handler="alerts",instance="localhost:9090",job="prometheus",method="get"}=(20889@1518096812.326)
http_requests_total{code="200",handler="graph",instance="localhost:9090",job="prometheus",method="get"}=(21287@1518096812.326)
PromQL還支持用戶根據(jù)時間序列的標簽匹配模式來對時間序列進行過濾戚啥,目前主要支持兩種匹配模式:完全匹配和正則匹配勒极。
PromQL支持使用=
和!=
兩種完全匹配模式:
通過使用
label=value
可以選擇那些標簽滿足表達式定義的時間序列;反之使用
label!=value
則可以根據(jù)標簽匹配排除時間序列虑鼎;
例如,如果我們只需要查詢所有http_requests_total時間序列中滿足標簽instance為localhost:9090的時間序列,則可以使用如下表達式:
http_requests_total{instance="localhost:9090"}
反之使用instance!="localhost:9090"
則可以排除這些時間序列:
http_requests_total{instance!="localhost:9090"}
除了使用完全匹配的方式對時間序列進行過濾以外炫彩,PromQL還可以支持使用正則表達式作為匹配條件匾七,多個表達式之間使用|
進行分離:
使用
label=~regx
表示選擇那些標簽符合正則表達式定義的時間序列;反之使用
label!~regx
進行排除江兢;
例如昨忆,如果想查詢多個環(huán)節(jié)下的時間序列序列可以使用如下表達式:
http_requests_total{environment=~"staging|testing|development",method!="GET"}
2.3.2 范圍查詢
直接通過類似于PromQL表達式http_requests_total
查詢時間序列時,返回值中只會包含該時間序列中的最新的一個樣本值杉允,這樣的返回結(jié)果我們稱之為瞬時向量邑贴。而相應(yīng)的這樣的表達式稱之為瞬時向量表達式。
而如果我們想過去一段時間范圍內(nèi)的樣本數(shù)據(jù)時叔磷,我們則需要使用區(qū)間向量表達式拢驾。區(qū)間向量表達式和瞬時向量表達式之間的差異在于在區(qū)間向量表達式中我們需要定義時間選擇的范圍,時間范圍通過時間范圍選擇器[]
進行定義改基。例如繁疤,通過以下表達式可以選擇最近5分鐘內(nèi)的所有樣本數(shù)據(jù):
http_request_total{}[5m]
該表達式將會返回查詢到的時間序列中最近5分鐘的所有樣本數(shù)據(jù):
通過區(qū)間向量表達式查詢到的結(jié)果我們稱為區(qū)間向量。
除了使用m表示分鐘以外秕狰,PromQL的時間范圍選擇器支持其它時間單位:
- s稠腊、m、h鸣哀、d架忌、w、y (秒我衬、分叹放、時、天低飒、周许昨、年)
2.3.3 時間位移操作
在瞬時向量表達式或者區(qū)間向量表達式中,都是以當(dāng)前時間為基準:
http_request_total{} # 瞬時向量表達式褥赊,選擇當(dāng)前最新的數(shù)據(jù)
http_request_total{}[5m] # 區(qū)間向量表達式糕档,選擇以當(dāng)前時間為基準,5分鐘內(nèi)的數(shù)據(jù)
而如果我們想查詢拌喉,5分鐘前的瞬時樣本數(shù)據(jù)速那,或昨天一天的區(qū)間內(nèi)的樣本數(shù)據(jù)呢? 這個時候我們就可以使用位移操作,位移操作的關(guān)鍵字為offset尿背。
可以使用offset時間位移操作:
http_request_total{} offset 5m
http_request_total{}[1d] offset 1d
2.3.4 使用聚合操作
一般來說端仰,如果描述樣本特征的標簽(label)在并非唯一的情況下,通過PromQL查詢數(shù)據(jù)田藐,會返回多條滿足這些特征維度的時間序列荔烧。而PromQL提供的聚合操作可以用來對這些時間序列進行處理吱七,形成一條新的時間序列:
# 查詢系統(tǒng)所有http請求的總量
sum(http_request_total)
# 按照mode計算主機CPU的平均使用時間
avg(node_cpu) by (mode)
# 按照主機查詢各個主機的CPU使用率
sum(sum(irate(node_cpu{mode!='idle'}[5m])) / sum(irate(node_cpu[5m]))) by (instance)
2.3.5 標量和字符串
除了使用瞬時向量表達式和區(qū)間向量表達式以外,PromQL還直接支持用戶使用標量(Scalar)和字符串(String)鹤竭。
標量(Scalar):一個浮點型的數(shù)字值
標量只有一個數(shù)字踊餐,沒有時序。
例如:
10
需要注意的是臀稚,當(dāng)使用表達式count(http_requests_total)吝岭,返回的數(shù)據(jù)類型,依然是瞬時向量吧寺。用戶可以通過內(nèi)置函數(shù)scalar()將單個瞬時向量轉(zhuǎn)換為標量窜管。
字符串(String):一個簡單的字符串值[]
直接使用字符串,作為PromQL表達式稚机,則會直接返回字符串幕帆。
"this is a string"
'these are unescaped: \n \\ \t'
`these are not unescaped: \n ' " \t`
2.3.6 合法的PromQL表達式
所有的PromQL表達式都必須至少包含一個指標名稱(例如http_request_total),或者一個不會匹配到空字符串的標簽過濾器(例如{code="200"})抒钱。
因此以下兩種方式蜓肆,均為合法的表達式:
http_request_total # 合法
http_request_total{} # 合法
{method="get"} # 合法
而如下表達式,則不合法:
{job=~".*"} # 不合法
同時谋币,除了使用<metric name>{label=value}
的形式以外仗扬,我們還可以使用內(nèi)置的__name__
標簽來指定監(jiān)控指標名稱:
{__name__=~"http_request_total"} # 合法
{__name__=~"node_disk_bytes_read|node_disk_bytes_written"} # 合法
2.4 PromQL操作符
使用PromQL除了能夠方便的按照查詢和過濾時間序列以外,PromQL還支持豐富的操作符蕾额,用戶可以使用這些操作符對進一步的對事件序列進行二次加工早芭。這些操作符包括:數(shù)學(xué)運算符,邏輯運算符诅蝶,布爾運算符等等退个。
2.4.1 數(shù)學(xué)運算
例如,我們可以通過指標node_memory_free_bytes_total獲取當(dāng)前主機可用的內(nèi)存空間大小调炬,其樣本單位為Bytes语盈。這是如果客戶端要求使用MB作為單位響應(yīng)數(shù)據(jù),那只需要將查詢到的時間序列的樣本值進行單位換算即可:
node_memory_free_bytes_total / (1024 * 1024)
node_memory_free_bytes_total表達式會查詢出所有滿足表達式條件的時間序列缰泡,在上一小節(jié)中我們稱該表達式為瞬時向量表達式刀荒,而返回的結(jié)果成為瞬時向量。
當(dāng)瞬時向量與標量之間進行數(shù)學(xué)運算時棘钞,數(shù)學(xué)運算符會依次作用域瞬時向量中的每一個樣本值缠借,從而得到一組新的時間序列。
而如果是瞬時向量與瞬時向量之間進行數(shù)學(xué)運算時宜猜,過程會相對復(fù)雜一點泼返。因為要先計算每個瞬時向量的結(jié)果,然后再對比是否類型一樣姨拥,一樣才能進行計算绅喉,這里不做介紹渠鸽。
PromQL支持的所有數(shù)學(xué)運算符如下所示:
-
+
(加法) 、-
(減法) 霹疫、*
(乘法) 拱绑、/
(除法) 、%
(求余) 丽蝎、^
(冪運算)
2.4.2 使用布爾運算過濾時間序列
在PromQL通過標簽匹配模式,用戶可以根據(jù)時間序列的特征維度對其進行查詢膀藐。而布爾運算則支持用戶根據(jù)時間序列中樣本的值屠阻,對時間序列進行過濾。
例如额各,通過數(shù)學(xué)運算符我們可以很方便的計算出国觉,當(dāng)前所有主機節(jié)點的內(nèi)存使用率:
(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total
而系統(tǒng)管理員在排查問題的時候可能只想知道當(dāng)前內(nèi)存使用率超過95%的主機呢?通過使用布爾運算符可以方便的獲取到該結(jié)果:
(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total > 0.95
瞬時向量與標量進行布爾運算時虾啦,PromQL依次比較向量中的所有時間序列樣本的值麻诀,如果比較結(jié)果為true則保留,反之丟棄傲醉。
瞬時向量與瞬時向量直接進行布爾運算時蝇闭,同樣遵循默認的匹配模式:依次找到與左邊向量元素匹配(標簽完全一致)的右邊向量元素進行相應(yīng)的操作,如果沒找到匹配元素硬毕,則直接丟棄呻引。
目前,Prometheus支持以下布爾運算符如下:
-
==
(相等)吐咳、!=
(不相等)逻悠、>
(大于) 、<
(小于)韭脊、>=
(大于等于) 童谒、<=
(小于等于)
2.4.3 使用bool修飾符改變布爾運算符的行為
布爾運算符的默認行為是對時序數(shù)據(jù)進行過濾。而在其它的情況下我們可能需要的是真正的布爾結(jié)果沪羔。例如饥伊,只需要知道當(dāng)前模塊的HTTP請求量是否>=1000,如果大于等于1000則返回1(true)否則返回0(false)任内。這時可以使用bool修飾符改變布爾運算的默認行為撵渡。 例如:
http_requests_total > bool 1000
使用bool修改符后,布爾運算不會對時間序列進行過濾死嗦,而是直接依次瞬時向量中的各個樣本數(shù)據(jù)與標量的比較結(jié)果0或者1趋距。從而形成一條新的時間序列。
http_requests_total{code="200",handler="query",instance="localhost:9090",job="prometheus",method="get"} 1
http_requests_total{code="200",handler="query_range",instance="localhost:9090",job="prometheus",method="get"} 0
同時需要注意的是越除,如果是在兩個標量之間使用布爾運算节腐,則必須使用bool修飾符
2 == bool 2 # 結(jié)果為1
2.4.4 使用集合運算符
使用瞬時向量表達式能夠獲取到一個包含多個時間序列的集合外盯,我們稱為瞬時向量。 通過集合運算翼雀,可以在兩個瞬時向量與瞬時向量之間進行相應(yīng)的集合操作饱苟。目前,Prometheus支持以下集合運算符:
-
and
(并且)狼渊、or
(或者)箱熬、unless
(排除)
2.4.5 操作符優(yōu)先級
對于復(fù)雜類型的表達式,需要了解運算操作的運行優(yōu)先級
例如狈邑,查詢主機的CPU使用率,可以使用表達式:
100 * (1 - avg (irate(node_cpu{mode='idle'}[5m])) by(job) )
其中irate是PromQL中的內(nèi)置函數(shù)米苹,用于計算區(qū)間向量中時間序列每秒的即時增長率糕伐。關(guān)于內(nèi)置函數(shù)的部分褥蚯,會在下一節(jié)詳細介紹。
在PromQL操作符中優(yōu)先級由高到低依次為:
^
*, /, %
+, -
==, !=, <=, <, >=, >
and, unless
or
2.4.6 匹配模式詳解
向量與向量之間進行運算操作時會基于默認的匹配規(guī)則:依次找到與左邊向量元素匹配(標簽完全一致)的右邊向量元素進行運算雪情,如果沒找到匹配元素遵岩,則直接丟棄。
接下來將介紹在PromQL中有兩種典型的匹配模式:一對一(one-to-one),多對一(many-to-one)或一對多(one-to-many)巡通。
一對一匹配
一對一匹配模式會從操作符兩邊表達式獲取的瞬時向量依次比較并找到唯一匹配(標簽完全一致)的樣本值尘执。默認情況下,使用表達式:
vector1 <operator> vector2
在操作符兩邊表達式標簽不一致的情況下宴凉,可以使用on(label list)或者ignoring(label list)來修改便簽的匹配行為誊锭。使用ignoreing可以在匹配時忽略某些便簽。而on則用于將匹配行為限定在某些便簽之內(nèi)弥锄。
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
例如當(dāng)存在樣本:
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="get", code="404"} 30
method_code:http_errors:rate5m{method="put", code="501"} 3
method_code:http_errors:rate5m{method="post", code="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120
使用PromQL表達式:
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
該表達式會返回在過去5分鐘內(nèi)丧靡,HTTP請求狀態(tài)碼為500的在所有請求中的比例。如果沒有使用ignoring(code)籽暇,操作符兩邊表達式返回的瞬時向量中將找不到任何一個標簽完全相同的匹配項温治。
因此結(jié)果如下:
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
同時由于method為put和del的樣本找不到匹配項,因此不會出現(xiàn)在結(jié)果當(dāng)中戒悠。
多對一和一對多
多對一和一對多兩種匹配模式指的是“一”側(cè)的每一個向量元素可以與"多"側(cè)的多個元素匹配的情況熬荆。在這種情況下,必須使用group修飾符:group_left或者group_right來確定哪一個向量具有更高的基數(shù)(充當(dāng)“多”的角色)绸狐。
<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>
多對一和一對多兩種模式一定是出現(xiàn)在操作符兩側(cè)表達式返回的向量標簽不一致的情況卤恳。因此需要使用ignoring和on修飾符來排除或者限定匹配的標簽列表累盗。
例如,使用表達式:
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
該表達式中,左向量method_code:http_errors:rate5m
包含兩個標簽method和code突琳。而右向量method:http_requests:rate5m
中只包含一個標簽method若债,因此匹配時需要使用ignoring限定匹配的標簽為code。 在限定匹配標簽后拆融,右向量中的元素可能匹配到多個左向量中的元素 因此該表達式的匹配模式為多對一蠢琳,需要使用group修飾符group_left指定左向量具有更好的基數(shù)。
最終的運算結(jié)果如下:
{method="get", code="500"} 0.04 // 24 / 600
{method="get", code="404"} 0.05 // 30 / 600
{method="post", code="500"} 0.05 // 6 / 120
{method="post", code="404"} 0.175 // 21 / 120
提醒:group修飾符只能在比較和數(shù)學(xué)運算符中使用镜豹。在邏輯運算and,unless和or才注意操作中默認與右向量中的所有元素進行匹配挪凑。
2.5 PromQL聚合操作
Prometheus還提供了下列內(nèi)置的聚合操作符,這些操作符作用域瞬時向量逛艰。可以將瞬時表達式返回的樣本數(shù)據(jù)進行聚合搞旭,形成一個新的時間序列散怖。
- sum (求和)、 min (最小值)肄渗、max (最大值)镇眷、avg (平均值)
- stddev (標準差)、stdvar (標準差異)翎嫡、count (計數(shù))欠动、count_values (對value進行計數(shù))
- bottomk (后n條時序)、topk (前n條時序)惑申、quantile (分布統(tǒng)計)
使用聚合操作的語法如下:
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
其中只有count_values, quantile, topk, bottomk支持參數(shù)(parameter)具伍。
without用于從計算結(jié)果中移除列舉的標簽,而保留其它標簽圈驼。by則正好相反人芽,結(jié)果向量中只保留列出的標簽,其余標簽則移除绩脆。通過without和by可以按照樣本的問題對數(shù)據(jù)進行聚合萤厅。
例如:
sum(http_requests_total) without (instance)
等價于
sum(http_requests_total) by (code,handler,job,method)
如果只需要計算整個應(yīng)用的HTTP請求總量,可以直接使用表達式:
sum(http_requests_total)
count_values用于時間序列中每一個樣本值出現(xiàn)的次數(shù)靴迫。count_values會為每一個唯一的樣本值輸出一個時間序列惕味,并且每一個時間序列包含一個額外的標簽。
例如:
count_values("count", http_requests_total)
topk和bottomk則用于對樣本值進行排序玉锌,返回當(dāng)前樣本值前n位名挥,或者后n位的時間序列。
獲取HTTP請求數(shù)前5位的時序樣本數(shù)據(jù)芬沉,可以使用表達式:
topk(5, http_requests_total)
quantile用于計算當(dāng)前樣本數(shù)據(jù)值的分布情況quantile(φ, express)其中0 ≤ φ ≤ 1躺同。
例如阁猜,當(dāng)φ為0.5時,即表示找到當(dāng)前樣本數(shù)據(jù)中的中位數(shù):
quantile(0.5, http_requests_total)
2.6 PromQL內(nèi)置函數(shù)
在上一小節(jié)中蹋艺,我們已經(jīng)看到了類似于irate()這樣的函數(shù)剃袍,可以幫助我們計算監(jiān)控指標的增長率。除了irate以外捎谨,Prometheus還提供了其它大量的內(nèi)置函數(shù)民效,可以對時序數(shù)據(jù)進行豐富的處理。本小節(jié)將帶來讀者了解一些常用的內(nèi)置函數(shù)以及相關(guān)的使用場景和用法涛救。
2.6.1 計算Counter指標增長率
我們知道Counter類型的監(jiān)控指標其特點是只增不減畏邢,在沒有發(fā)生重置(如服務(wù)器重啟,應(yīng)用重啟)的情況下其樣本值應(yīng)該是不斷增大的检吆。為了能夠更直觀的表示樣本數(shù)據(jù)的變化劇烈情況舒萎,需要計算樣本的增長速率。
如下圖所示蹭沛,樣本增長率反映出了樣本變化的劇烈程度:
increase(v range-vector)函數(shù)是PromQL中提供的眾多內(nèi)置函數(shù)之一臂寝。其中參數(shù)v是一個區(qū)間向量,increase函數(shù)獲取區(qū)間向量中的第一個后最后一個樣本并返回其增長量摊灭。因此咆贬,可以通過以下表達式Counter類型指標的增長率:
increase(node_cpu[2m]) / 120
這里通過node_cpu[2m]獲取時間序列最近兩分鐘的所有樣本,increase計算出最近兩分鐘的增長量帚呼,最后除以時間120秒得到node_cpu樣本在最近兩分鐘的平均增長率掏缎。并且這個值也近似于主機節(jié)點最近兩分鐘內(nèi)的平均CPU使用率。
除了使用increase函數(shù)以外煤杀,PromQL中還直接內(nèi)置了rate(v range-vector)函數(shù)眷蜈,rate函數(shù)可以直接計算區(qū)間向量v在時間窗口內(nèi)平均增長速率。因此怜珍,通過以下表達式可以得到與increase函數(shù)相同的結(jié)果:
rate(node_cpu[2m])
需要注意的是使用rate或者increase函數(shù)去計算樣本的平均增長速率端蛆,容易陷入“長尾問題”當(dāng)中,其無法反應(yīng)在時間窗口內(nèi)樣本數(shù)據(jù)的突發(fā)變化酥泛。 例如今豆,對于主機而言在2分鐘的時間窗口內(nèi),可能在某一個由于訪問量或者其它問題導(dǎo)致CPU占用100%的情況柔袁,但是通過計算在時間窗口內(nèi)的平均增長率卻無法反應(yīng)出該問題呆躲。
為了解決該問題,PromQL提供了另外一個靈敏度更高的函數(shù)irate(v range-vector)捶索。irate同樣用于計算區(qū)間向量的計算率插掂,但是其反應(yīng)出的是瞬時增長率。irate函數(shù)是通過區(qū)間向量中最后兩個兩本數(shù)據(jù)來計算區(qū)間向量的增長速率。這種方式可以避免在時間窗口范圍內(nèi)的“長尾問題”辅甥,并且體現(xiàn)出更好的靈敏度酝润,通過irate函數(shù)繪制的圖標能夠更好的反應(yīng)樣本數(shù)據(jù)的瞬時變化狀態(tài)。
irate(node_cpu[2m])
irate函數(shù)相比于rate函數(shù)提供了更高的靈敏度璃弄,不過當(dāng)需要分析長期趨勢或者在告警規(guī)則中要销,irate的這種靈敏度反而容易造成干擾。因此在長期趨勢分析或者告警中更推薦使用rate函數(shù)夏块。
2.6.2 預(yù)測Gauge指標變化趨勢
在一般情況下疏咐,系統(tǒng)管理員為了確保業(yè)務(wù)的持續(xù)可用運行,會針對服務(wù)器的資源設(shè)置相應(yīng)的告警閾值脐供。例如浑塞,當(dāng)磁盤空間只剩512MB時向相關(guān)人員發(fā)送告警通知。 這種基于閾值的告警模式對于當(dāng)資源用量是平滑增長的情況下是能夠有效的工作的政己。 但是如果資源不是平滑變化的呢酌壕? 比如有些某些業(yè)務(wù)增長,存儲空間的增長速率提升了高幾倍歇由。這時仅孩,如果基于原有閾值去觸發(fā)告警,當(dāng)系統(tǒng)管理員接收到告警以后可能還沒來得及去處理問題印蓖,系統(tǒng)就已經(jīng)不可用了。 因此閾值通常來說不是固定的京腥,需要定期進行調(diào)整才能保證該告警閾值能夠發(fā)揮去作用赦肃。 那么還有沒有更好的方法嗎?
PromQL中內(nèi)置的predict_linear(v range-vector, t scalar) 函數(shù)可以幫助系統(tǒng)管理員更好的處理此類情況公浪,predict_linear函數(shù)可以預(yù)測時間序列v在t秒后的值他宛。它基于簡單線性回歸的方式,對時間窗口內(nèi)的樣本數(shù)據(jù)進行統(tǒng)計欠气,從而可以對時間序列的變化趨勢做出預(yù)測厅各。例如,基于2小時的樣本數(shù)據(jù)预柒,來預(yù)測主機可用磁盤空間的是否在4個小時候被占滿队塘,可以使用如下表達式:
predict_linear(node_filesystem_free{job="node"}[2h], 4 * 3600) < 0
統(tǒng)計Histogram指標的分位數(shù)
在本章的第2小節(jié)中,我們介紹了Prometheus的四種監(jiān)控指標類型宜鸯,其中Histogram和Summary都可以同于統(tǒng)計和分析數(shù)據(jù)的分布情況憔古。區(qū)別在于Summary是直接在客戶端計算了數(shù)據(jù)分布的分位數(shù)情況。而Histogram的分位數(shù)計算需要通過histogram_quantile(φ float, b instant-vector)函數(shù)進行計算淋袖。其中φ(0<φ<1)表示需要計算的分位數(shù)鸿市,如果需要計算中位數(shù)φ取值為0.5,以此類推即可。
以指標http_request_duration_seconds_bucket為例:
# HELP http_request_duration_seconds request duration histogram
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.5"} 0
http_request_duration_seconds_bucket{le="1"} 1
http_request_duration_seconds_bucket{le="2"} 2
http_request_duration_seconds_bucket{le="3"} 3
http_request_duration_seconds_bucket{le="5"} 3
http_request_duration_seconds_bucket{le="+Inf"} 3
http_request_duration_seconds_sum 6
http_request_duration_seconds_count 3
當(dāng)計算9分位數(shù)時焰情,使用如下表達式:
histogram_quantile(0.5, http_request_duration_seconds_bucket)
通過對Histogram類型的監(jiān)控指標陌凳,用戶可以輕松獲取樣本數(shù)據(jù)的分布情況。同時分位數(shù)的計算内舟,也可以非常方便的用于評判當(dāng)前監(jiān)控指標的服務(wù)水平合敦。
需要注意的是通過histogram_quantile計算的分位數(shù),并非為精確值谒获,而是通過http_request_duration_seconds_bucket和http_request_duration_seconds_sum近似計算的結(jié)果蛤肌。
2.6.3 動態(tài)標簽替換
一般來說來說,使用PromQL查詢到時間序列后批狱,可視化工具會根據(jù)時間序列的標簽來渲染圖表裸准。例如通過up指標可以獲取到當(dāng)前所有運行的Exporter實例以及其狀態(tài):
up{instance="localhost:8080",job="cadvisor"} 1
up{instance="localhost:9090",job="prometheus"} 1
up{instance="localhost:9100",job="node"} 1
這是可視化工具渲染圖標時可能根據(jù),instance和job的值進行渲染赔硫,為了能夠讓客戶端的圖標更具有可讀性炒俱,可以通過label_replace標簽為時間序列添加額外的標簽。label_replace的具體參數(shù)如下:
label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string)
該函數(shù)會依次對v中的每一條時間序列進行處理爪膊,通過regex匹配src_label的值权悟,并將匹配部分relacement寫入到dst_label標簽中。如下所示:
label_replace(up, "host", "$1", "instance", "(.*):.*")
函數(shù)處理后推盛,時間序列將包含一個host標簽峦阁,host標簽的值為Exporter實例的IP地址:
up{host="localhost",instance="localhost:8080",job="cadvisor"} 1
up{host="localhost",instance="localhost:9090",job="prometheus"} 1
up{host="localhost",instance="localhost:9100",job="node"} 1
除了label_replace以外,Prometheus還提供了label_join函數(shù)耘成,該函數(shù)可以將時間序列中v多個標簽src_label的值榔昔,通過separator作為連接符寫入到一個新的標簽dst_label中:
label_join(v instant-vector, dst_label string, separator string, src_label_1 string, src_label_2 string, ...)
label_replace和label_join函數(shù)提供了對時間序列標簽的自定義能力,從而能夠更好的于客戶端或者可視化工具配合瘪菌。
2.6.4 其它內(nèi)置函數(shù)
除了上文介紹的這些內(nèi)置函數(shù)以外撒会,PromQL還提供了大量的其它內(nèi)置函數(shù)。這些內(nèi)置函數(shù)包括一些常用的數(shù)學(xué)計算师妙、日期等等诵肛。這里就不一一細講,感興趣的讀者可以通過閱讀Prometheus的官方文檔默穴,了解這些函數(shù)的使用方式怔檩。
2.7 在HTTP API中使用PromQL
有些時候,我們并不一定有web界面給我們?nèi)ゲ樵償?shù)據(jù)蓄诽。這時候就要使用HTTP的API接口了珠洗,也就是在命令行下使用curl。通過HTTP API我們可以分別通過/api/v1/query和/api/v1/query_range查詢PromQL表達式當(dāng)前或者一定時間范圍內(nèi)的計算結(jié)果若专。
查詢節(jié)點狀態(tài)為up许蓖,名稱為
curl 'http://localhost:9090/api/v1/query?query=up&job=node'
當(dāng)API調(diào)用成功后,Prometheus會返回JSON格式的響應(yīng)內(nèi)容,如:
{
"status":"success",
"data":{"resultType":"vector","result":[{"metric":{"__name__":"up","instance":"192.168.113.52:9090","job":"prometheus"},"value":[1571622906.932,"1"]},{"metric":{"__name__":"up","instance":"192.168.113.52:9100","job":"node"},"value":[1571622906.932,"1"]}]}
}