如何基于Python和Flask編寫Prometheus監(jiān)控
介紹
Prometheus 的基本原理是通過 HTTP 周期性抓取被監(jiān)控組件的狀態(tài)。
任意組件只要提供對應(yīng)的 HTTP 接口并且符合 Prometheus 定義的數(shù)據(jù)格式,就可以接入 Prometheus 監(jiān)控。
Prometheus Server 負(fù)責(zé)定時(shí)在目標(biāo)上抓取 metrics(指標(biāo))數(shù)據(jù)并保存到本地存儲。它采用了一種 Pull(拉)的方式獲取數(shù)據(jù),不僅降低客戶端的復(fù)雜度,客戶端只需要采集數(shù)據(jù),無需了解服務(wù)端情況,也讓服務(wù)端可以更加方便地水平擴(kuò)展。
如果監(jiān)控?cái)?shù)據(jù)達(dá)到告警閾值,Prometheus Server 會通過 HTTP 將告警發(fā)送到告警模塊 alertmanger,通過告警的抑制后觸發(fā)郵件或者 Webhook。Prometheus 支持 PromQL 提供多維度數(shù)據(jù)模型和靈活的查詢,通過監(jiān)控指標(biāo)關(guān)聯(lián)多個(gè) tag 的方式,將監(jiān)控?cái)?shù)據(jù)進(jìn)行任意維度的組合以及聚合。
在python中實(shí)現(xiàn)服務(wù)器端,對外提供接口。在Prometheus中配置請求網(wǎng)址,Prometheus會定期向該網(wǎng)址發(fā)起申請獲取你想要返回的數(shù)據(jù)。
另外Prometheus提供4種類型Metrics:Counter, Gauge, Summary和Histogram。
準(zhǔn)備
pip install flask
pip install prometheus_client
Counter
Counter可以增長,并且在程序重啟的時(shí)候會被重設(shè)為0,常被用于訪問量,任務(wù)個(gè)數(shù),總處理時(shí)間,錯誤個(gè)數(shù)等只增不減的指標(biāo)。
定義它需要2個(gè)參數(shù),第一個(gè)是metrics的名字,第二個(gè)是metrics的描述信息:
c = Counter('c1', 'A counter')
counter只能增加,所以只有一個(gè)方法:
def inc(self, amount=1): '''Increment counter by the given amount.''' if amount < 0: raise ValueError('Counters can only be incremented by non-negative amounts.') self._value.inc(amount)
測試示例:
import prometheus_client from prometheus_client import Counter from prometheus_client.core import CollectorRegistry from flask import Response, Flask app = Flask(__name__) requests_total = Counter('c1','A counter') @app.route("/api/metrics/count/") def requests_count(): requests_total.inc(1) # requests_total.inc(2) return Response(prometheus_client.generate_latest(requests_total),mimetype="text/plain") if __name__ == "__main__": app.run(host="127.0.0.1",port=8081)
訪問http://127.0.0.1:8081/api/metrics/count/:
# HELP c1_total A counter
# TYPE c1_total counter
c1_total 1.0
# HELP c1_created A counter
# TYPE c1_created gauge
c1_created 1.6053265493727107e+09
HELP是c1的注釋說明,創(chuàng)建Counter定義的。
TYPE是c1的類型說明。
c1_total為我們定義的指標(biāo)輸出:你會發(fā)現(xiàn)多了后綴_total,這是因?yàn)镺penMetrics與Prometheus文本格式之間的兼容性,OpenMetrics需要_total后綴。
gauge
gauge可增可減,可以任意設(shè)置。
比如可以設(shè)置當(dāng)前的CPU溫度,內(nèi)存使用量,磁盤、網(wǎng)絡(luò)流量等等。
定義和counter基本一樣:
from prometheus_client import Gauge g = Gauge('my_inprogress_requests', 'Description of gauge') g.inc() # Increment by 1 g.dec(10) # Decrement by given value g.set(4.2) # Set to a given value
方法:
def inc(self, amount=1): '''Increment gauge by the given amount.''' self._value.inc(amount) def dec(self, amount=1): '''Decrement gauge by the given amount.''' self._value.inc(-amount) def set(self, value): '''Set gauge to the given value.''' self._value.set(float(value))
測試示例:
import random import prometheus_client from prometheus_client import Gauge from prometheus_client.core import CollectorRegistry from flask import Response, Flask app = Flask(__name__) random_value = Gauge("g1", 'A gauge') @app.route("/api/metrics/gauge/") def r_value(): random_value.set(random.randint(0, 10)) return Response(prometheus_client.generate_latest(random_value), mimetype="text/plain") if __name__ == "__main__": app.run(host="127.0.0.1",port=8081)
訪問http://127.0.0.1:8081/api/metrics/gauge/
# HELP g1 A gauge
# TYPE g1 gauge
g1 5.0
LABELS的用法
使用labels來區(qū)分metric的特征,一個(gè)指標(biāo)可以有其中一個(gè)label,也可以有多個(gè)label。
from prometheus_client import Counter c = Counter('requests_total', 'HTTP requests total', ['method', 'clientip']) c.labels('get', '127.0.0.1').inc() c.labels('post', '192.168.0.1').inc(3) c.labels(method="get", clientip="192.168.0.1").inc()
import random import prometheus_client from prometheus_client import Gauge from flask import Response, Flask app = Flask(__name__) c = Gauge("c1", 'A counter',['method','clientip']) @app.route("/api/metrics/counter/") def r_value(): c.labels(method='get',clientip='192.168.0.%d' % random.randint(1,10)).inc() return Response(prometheus_client.generate_latest(c), mimetype="text/plain") if __name__ == "__main__": app.run(host="127.0.0.1",port=8081)
連續(xù)訪問9次http://127.0.0.1:8081/api/metrics/counter/:
# HELP c1 A counter
# TYPE c1 gauge
c1{clientip="192.168.0.7",method="get"} 2.0
c1{clientip="192.168.0.1",method="get"} 1.0
c1{clientip="192.168.0.8",method="get"} 1.0
c1{clientip="192.168.0.5",method="get"} 2.0
c1{clientip="192.168.0.4",method="get"} 1.0
c1{clientip="192.168.0.10",method="get"} 1.0
c1{clientip="192.168.0.2",method="get"} 1.0
histogram
這種主要用來統(tǒng)計(jì)百分位的,什么是百分位?英文叫做quantiles。
比如你有100條訪問請求的耗時(shí)時(shí)間,把它們從小到大排序,第90個(gè)時(shí)間是200ms,那么我們可以說90%的請求都小于200ms,這也叫做”90分位是200ms”,能夠反映出服務(wù)的基本質(zhì)量。當(dāng)然,也許第91個(gè)時(shí)間是2000ms,這就沒法說了。
實(shí)際情況是,我們每天訪問量至少幾個(gè)億,不可能把所有訪問數(shù)據(jù)都存起來,然后排序找到90分位的時(shí)間是多少。因此,類似這種問題都采用了一些估算的算法來處理,不需要把所有數(shù)據(jù)都存下來,這里面數(shù)學(xué)原理比較高端,我們就直接看看prometheus的用法好了。
首先定義histogram:
h = Histogram('hh', 'A histogram', buckets=(-5, 0, 5))
第一個(gè)是metrics的名字,第二個(gè)是描述,第三個(gè)是分桶設(shè)置,重點(diǎn)說一下buckets。
這里(-5,0,5)實(shí)際劃分成了幾種桶:(無窮小,-5],(-5,0],(0,5],(5,無窮大)。
如果我們喂給它一個(gè)-8:
h.observe(8)
那么metrics會這樣輸出:
# HELP hh A histogram
# TYPE hh histogram
hh_bucket{le="-5.0"} 0.0
hh_bucket{le="0.0"} 0.0
hh_bucket{le="5.0"} 0.0
hh_bucket{le="+Inf"} 1.0
hh_count 1.0
hh_sum 8.0
hh_sum記錄了observe的總和,count記錄了observe的次數(shù),bucket就是各種桶了,le表示<=某值。
可見,值8<=無窮大,所以只有最后一個(gè)桶計(jì)數(shù)了1次(注意,桶只是計(jì)數(shù),bucket作用相當(dāng)于統(tǒng)計(jì)樣本在不同區(qū)間的出現(xiàn)次數(shù))。
bucket的劃分需要我們根據(jù)數(shù)據(jù)的分布拍腦袋指定,合理的劃分可以讓promql估算百分位的時(shí)候更準(zhǔn)確,我們使用histogram的時(shí)候只需要知道先分好桶,再不斷的打點(diǎn)即可,最終百分位的計(jì)算可以基于histogram的原始數(shù)據(jù)完成。
測試示例:
import random import prometheus_client from prometheus_client import Histogram from flask import Response, Flask app = Flask(__name__) h = Histogram("h1", 'A Histogram', buckets=(-5, 0, 5)) @app.route("/api/metrics/histogram/") def r_value(): h.observe(random.randint(-5, 5)) return Response(prometheus_client.generate_latest(h), mimetype="text/plain") if __name__ == "__main__": app.run(host="127.0.0.1",port=8081)
連續(xù)訪問http://127.0.0.1:8081/api/metrics/histogram/:
# HELP h1 A Histogram
# TYPE h1 histogram
h1_bucket{le="-5.0"} 0.0
h1_bucket{le="0.0"} 5.0
h1_bucket{le="5.0"} 10.0
h1_bucket{le="+Inf"} 10.0
h1_count 10.0
# HELP h1_created A Histogram
# TYPE h1_created gauge
h1_created 1.6053319432993534e+09
summary
python客戶端沒有完整實(shí)現(xiàn)summary算法,這里不介紹。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python zip,lambda,map函數(shù)代碼實(shí)例
這篇文章主要介紹了python zip,lambda,map函數(shù)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Python 利用flask搭建一個(gè)共享服務(wù)器的步驟
這篇文章主要介紹了Python 利用flask搭建一個(gè)共享服務(wù)器的步驟,幫助大家更好的理解和學(xué)習(xí)python,感興趣的朋友可以了解下2020-12-12Python實(shí)現(xiàn)的飛速中文網(wǎng)小說下載腳本
這篇文章主要介紹了Python實(shí)現(xiàn)的飛速中文網(wǎng)小說下載腳本,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04python使用QQ郵箱實(shí)現(xiàn)自動發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了python使用QQ郵箱實(shí)現(xiàn)自動發(fā)送郵件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06