簡介
眾所周知,prometheus(普羅米修斯)是微服務監(jiān)控領域的新星搀玖,這幾年發(fā)展迅猛莉炉。之前用過一些框架自帶metrics,接觸過prometheus陕悬,這次準備系統(tǒng)的深入研究一下相關(guān)監(jiān)控方案题暖。
先看看prometheus及周邊生態(tài)的結(jié)構(gòu)圖:
環(huán)境搭建
按照慣例,先把環(huán)境搭起來,hello world跑通再說胧卤。
docker-compose.yaml
version: '3'
services:
prometheus:
image: prom/prometheus
volumes:
- "./prometheus/prometheus.yaml:/etc/prometheus/prometheus.yml"
- "./prometheus/data:/prometheus"
- "./prometheus/rule.yaml:/etc/prometheus/rule.yml"
ports:
- "9090:9090"
server1:
image: phpswoole/swoole:php7.3
volumes:
- "./server1:/app"
ports:
- "9502:9502"
command: php /app/server.php start
grafana:
image: grafana/grafana
ports:
- '3000:3000'
volumes:
- "./grafana/data:/var/lib/grafana"
alertmanager:
image: prom/alertmanager
ports:
- '9093:9093'
volumes:
- "./alertmanager/alert.yaml:/etc/alertmanager/alertmanager.yml"
- "./alertmanager/data:/alertmanager"
- "./alertmanager/templates:/templates"
目錄結(jié)構(gòu):
metrics:
<?php
use Prometheus\CollectorRegistry;
use Prometheus\RenderTextFormat;
use Prometheus\Storage\InMemory;
use Swoole\Coroutine\Http\Server;
use function Swoole\Coroutine\run;
require_once __DIR__ . '/vendor/autoload.php';
run(function () {
$registry = new CollectorRegistry(new InMemory());
$server = new Server('0.0.0.0', 9502, false);
$server->set([
'mode' => SWOOLE_BASE,
'worker_num' => 1
]);
$GLOBALS['gauge'] = 1;
$server->handle('/metrics', function ($request, $response)use ($registry) {
$registry->getOrRegisterCounter('','some_quick_counter','just a quick counter')
->inc();
$registry->getOrRegisterGauge('','some_gauge','it sets',['type'])
->set($GLOBALS['gauge'],['blue']);
$registry->getOrRegisterHistogram('','some_histogram','it observes',['color'],[0.1,2,3,3.5,4,5,6,7,8,9])
->observe(random_int(1,10),['red']);
$render = new RenderTextFormat();
$metrics = $render->render($registry->getMetricFamilySamples());
$response->header('Content-Type',RenderTextFormat::MIME_TYPE);
$response->end($metrics);
});
$server->handle('/reset',function ($request,$response)use ($registry){
$GLOBALS['gauge'] = 0;
$response->end($GLOBALS['gauge']);
});
$server->start();
});
用 swoole server 借助 prometheus client 實現(xiàn) metrics 邏輯唯绍,配置 pull job 即可。
prometheus 配置:
global:
scrape_interval: 10s
evaluation_interval: 10s
scrape_timeout: 10s
external_labels:
prom: 'a'
scrape_configs:
- job_name: 'purelight'
static_configs:
- targets: ['server1:9502']
- job_name: 'prometheus'
static_configs:
- targets: ['127.0.0.1:9090']
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
rule_files:
- "/etc/prometheus/rule.yml"
這樣枝誊,prometheus 就會每10s抓取server1的metrics况芒,以及prometheus自身的metrcis,另外侧啼,alertmanagers配置告警牛柒。
啟動:docker-compose up -d
Prometheus
訪問:http://127.0.0.1:9502/metrics
這就是 prometheus pull 模式抓取 metrics 信息的消息大致格式。
數(shù)據(jù)類型
prometheus 數(shù)據(jù)組成:
指標(metric):metric name和描述當前樣本特征的labelsets;
時間戳(timestamp):一個精確到毫秒的時間戳;
樣本值(value): 一個float64的浮點型數(shù)據(jù)表示當前樣本的值痊乾。
指標格式:<metric name>{<label name>=<label value>, ...}
metric 又分4種類型(metric type):Counter(計數(shù)器)皮壁、Gauge(儀表盤)、Histogram(直方圖)哪审、Summary(摘要)蛾魄。
Counter
Counter類型的指標其工作方式和計數(shù)器一樣,只增不減(除非系統(tǒng)發(fā)生重置)湿滓。常見的監(jiān)控指標滴须,如http_requests_total,node_cpu都是Counter類型的監(jiān)控指標叽奥。 一般在定義Counter類型指標的名稱時推薦使用_total作為后綴扔水。
php client 示例:
$registry = new CollectorRegistry(new InMemory());
$counter = $registry->getOrRegisterCounter('','some_quick_counter','just a quick counter');
$counter->inc();
Gauge:
與Counter不同,Gauge類型的指標側(cè)重于反應系統(tǒng)的當前狀態(tài)朝氓。因此這類指標的樣本數(shù)據(jù)可增可減魔市。常見指標如:node_memory_MemFree(主機當前空閑的內(nèi)容大小)赵哲、node_memory_MemAvailable(可用內(nèi)存大写隆)都是Gauge類型的監(jiān)控指標。
php client 示例:
$gauge = $registry->getOrRegisterGauge('','some_gauge','it sets',['type']);
$gauge->set(2.5, ['blue']);
Histogram和Summary分析數(shù)據(jù)分布情況
除了Counter和Gauge類型的監(jiān)控指標以外枫夺,Prometheus還定義了Histogram和Summary的指標類型将宪。Histogram和Summary主用用于統(tǒng)計和分析樣本的分布情況。
在大多數(shù)情況下人們都傾向于使用某些量化指標的平均值橡庞,例如CPU的平均使用率较坛、頁面的平均響應時間。這種方式的問題很明顯毙死,以系統(tǒng)API調(diào)用的平均響應時間為例:如果大多數(shù)API請求都維持在100ms的響應時間范圍內(nèi)燎潮,而個別請求的響應時間需要5s,那么就會導致某些WEB頁面的響應時間落到中位數(shù)的情況扼倘,而這種現(xiàn)象被稱為長尾問題确封。
為了區(qū)分是平均的慢還是長尾的慢除呵,最簡單的方式就是按照請求延遲的范圍進行分組。例如爪喘,統(tǒng)計延遲在010ms之間的請求數(shù)有多少而1020ms之間的請求數(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
從上面的樣本中可以得知當前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類型的樣本同樣會反應當前指標的記錄的總數(shù)(以_count作為后綴)以及其值的總量(以_sum作為后綴)胸私。不同在于Histogram指標直接反應了在不同區(qū)間內(nèi)樣本的個數(shù),區(qū)間通過標簽len進行定義鳖谈。
同時對于Histogram的指標岁疼,我們還可以通過histogram_quantile()函數(shù)計算出其值的分位數(shù)。不同在于Histogram通過histogram_quantile函數(shù)是在服務器端計算的分位數(shù)缆娃。 而Sumamry的分位數(shù)則是直接在客戶端計算完成五续。因此對于分位數(shù)的計算而言,Summary在通過PromQL進行查詢時有更好的性能表現(xiàn)龄恋,而Histogram則會消耗更多的資源。反之對于客戶端而言Histogram消耗的資源更少凶伙。在選擇這兩種方式時用戶應該按照自己的實際場景進行選擇郭毕。
PromQL
瞬時向量 vs 區(qū)間向量
metric name 默認就是瞬時向量,代表當前最新一條數(shù)據(jù)函荣;區(qū)間向量是過去一段時間的多條數(shù)據(jù)显押,使用方法是 metric name 后跟 [5m] 這種時間標志,支持:s - 秒傻挂,m - 分鐘乘碑,h - 小時,d - 天金拒,w - 周兽肤,y - 年套腹。
時間位移
在瞬時向量表達式或者區(qū)間向量表達式中,都是以當前時間為基準资铡。而如果我們想查詢电禀,5分鐘前的瞬時樣本數(shù)據(jù),或昨天一天的區(qū)間內(nèi)的樣本數(shù)據(jù)呢? 這個時候我們就可以使用位移操作笤休,位移操作的關(guān)鍵字為offset尖飞。
http_request_total{} offset 5m
http_request_total{}[1d] offset 1d
操作符
支持數(shù)學運算符:+
(加法),-
(減法)店雅,*
(乘法)政基,/
(除法),%
(求余)闹啦,^
(冪運算)沮明。
支持布爾運算符:==
(相等),!=
(不相等)亥揖,>
(大于)珊擂,<
(小于),>=
(大于等于)费变,<=
(小于等于)摧扇。
函數(shù)
sum
(求和),min
(最小值)挚歧,max
(最大值)扛稽,avg
(平均值),stddev
(標準差)滑负,stdvar
(標準方差)在张,count
(計數(shù)),count_values
(對value進行計數(shù))矮慕,bottomk
(后n條時序)帮匾,topk
(前n條時序),quantile
(分位數(shù)) ......
PromQL 的發(fā)揮主要是在 Grafana 圖表繪制中痴鳄。
Grafana
Grafana 主要用于可視化圖表繪制瘟斜,內(nèi)置支持 prometheus 數(shù)據(jù)源。
簡單看下如何添加一個 counter 類型的數(shù)據(jù)圖表繪制方法:
非常簡單痪寻,但這只是鳳毛棱角螺句,grafana+prometheus 還支持更多的圖表類型。
應用層
工具花里胡哨的太多橡类,對于項目來說蛇尚,最重要的還是做好 metrics 統(tǒng)計指標,借助 prometheus client 顾画,提供 /metrics http endpoint取劫,讓 prometheus 主動定時 pull 匆笤。
prometheus 除了 pull 模式,還支持客戶端主動 push 的模式勇凭,這個用于客戶端不方便開放 http 端口的情況疚膊。
下次探討 alertmanager 以及 prometheus 更多內(nèi)容……
2021-07-12