控體系實(shí)戰(zhàn):數(shù)據(jù)模型、PromQL與告警避坑指南)
簡(jiǎn)介Prometheus作為開(kāi)源監(jiān)控與報(bào)警系統(tǒng)是運(yùn)維和DevOps工程師常用的時(shí)序數(shù)據(jù)監(jiān)控方案。這份學(xué)習(xí)資料面向具備基礎(chǔ)Linux操作能力的技術(shù)人員系統(tǒng)講解時(shí)間序列數(shù)據(jù)模型、PromQL查詢語(yǔ)法、Prometheus架構(gòu)組成以及它與傳統(tǒng)數(shù)據(jù)庫(kù)和其他監(jiān)控系統(tǒng)的適用場(chǎng)景對(duì)比。內(nèi)容從環(huán)境準(zhǔn)備入手完整演示Prometheus服務(wù)安裝、配置prometheus.yml再通過(guò)node_exporter監(jiān)控遠(yuǎn)程Linux主機(jī)通過(guò)mysqld_exporter采集MySQL性能指標(biāo)并進(jìn)一步集成Grafana繪制CPU負(fù)載、MySQL監(jiān)控圖表最后使用Alertmanager配置報(bào)警規(guī)則和通知策略形成一套可落地的監(jiān)控全鏈路。資源以單個(gè)PDF形式提供壓縮包僅2.95MB適合按章節(jié)循序漸進(jìn)學(xué)習(xí)目前已吸引633人學(xué)習(xí)下載。學(xué)完可獨(dú)立完成監(jiān)控平臺(tái)部署、自定義指標(biāo)定義、報(bào)警規(guī)則設(shè)置與儀表盤構(gòu)建達(dá)成實(shí)時(shí)監(jiān)控和故障排查的目標(biāo)。1. Prometheus 從入門到精通這套監(jiān)控體系到底在解決什么問(wèn)題凌晨三點(diǎn)某公司 A 同學(xué)被電話叫醒線上接口超時(shí)率飆到 40%。打開(kāi)監(jiān)控看板CPU 沒(méi)滿、內(nèi)存沒(méi)滿、磁盤沒(méi)滿滿屏的綠色曲線就是找不到問(wèn)題在哪——排查到天亮才發(fā)現(xiàn)是下游第三方 API 的 P99 延遲翻了一倍。這類“什么都正常但業(yè)務(wù)不正?!钡暮谙蛔訒r(shí)刻就是監(jiān)控體系的真正價(jià)值所在。Prometheus 是當(dāng)前云原生場(chǎng)景下最被廣泛接受的監(jiān)控方案它以拉取方式采集指標(biāo)把數(shù)據(jù)存成帶標(biāo)簽的時(shí)間序列再用 PromQL 這套查詢語(yǔ)言把運(yùn)行狀態(tài)變成可追溯的曲線和可觸發(fā)的告警。這篇文章適合運(yùn)維、后端開(kāi)發(fā)以及任何想用數(shù)據(jù)而不是直覺(jué)來(lái)定位故障的人。無(wú)論你是在容器環(huán)境還是傳統(tǒng)虛擬機(jī)讀完你都能獨(dú)立搭一套能用的監(jiān)控體系。2. 玩轉(zhuǎn) Prometheus 先吃透數(shù)據(jù)模型從計(jì)數(shù)器到直方圖的選型邏輯Prometheus 的文檔很多但多數(shù)人第一步就卡在概念上什么叫樣本、什么叫標(biāo)簽Counter 和 Gauge 有什么區(qū)別。不理解數(shù)據(jù)模型后面全是靠瞎試。這一章把 Prometheus 最核心的幾個(gè)機(jī)制講透后面的配置和查詢才不會(huì)發(fā)虛。2.1 拉取式采集為什么 Prometheus 用 pull 而不是 push傳統(tǒng)監(jiān)控系統(tǒng)多用 push 模式客戶端裝 agentagent 定時(shí)把數(shù)據(jù)推給服務(wù)端。推的模式看起來(lái)省事但有幾個(gè)根本問(wèn)題服務(wù)端無(wú)法判斷“沒(méi)有數(shù)據(jù)”是因?yàn)榭蛻舳藪炝诉€是真的沒(méi)數(shù)據(jù)客戶端數(shù)量多了以后服務(wù)端要分別承擔(dān)流量峰值擴(kuò)容困難數(shù)據(jù)在傳輸過(guò)程中沒(méi)有統(tǒng)一的采樣節(jié)奏時(shí)間戳對(duì)齊很費(fèi)勁。Prometheus 選擇了 pull 模式服務(wù)端按 scrape_interval 定時(shí)到每個(gè) target 的 /metrics 端口里抓取指標(biāo)。這樣做的直接好處是抓取目標(biāo)的狀態(tài)是標(biāo)準(zhǔn)的——成功、失敗、超時(shí)都是服務(wù)端主動(dòng)探測(cè)出來(lái)的采集節(jié)奏由服務(wù)端統(tǒng)一控制target 只要暴露一個(gè) HTTP 端口就能被任何 Prometheus 抓取。這也是為什么云原生環(huán)境下它比老牌監(jiān)控系統(tǒng)更順手。但 pull 模式對(duì)“生命周期很短的任務(wù)”有天然缺陷一個(gè)批處理任務(wù)可能跑 30 秒就退出了Prometheus 還沒(méi)等到下一次抓取。常見(jiàn)的做法是這類短命任務(wù)額外推一個(gè) PushgatewayPushgateway 是一個(gè)持有指標(biāo)快照的緩存層Prometheus 再?gòu)乃抢锢?。注意Pushgateway 只適合“臨時(shí)任務(wù)指標(biāo)匯總”不適合把業(yè)務(wù)所有指標(biāo)都塞進(jìn)去否則它會(huì)變成一個(gè)故障點(diǎn)。2.2 四種指標(biāo)類型Counter、Gauge、Histogram、Summary接口暴露出來(lái)的每條指標(biāo)都有類型聲明。選錯(cuò)類型是新手最容易犯的錯(cuò)比如用 Gauge 存累計(jì)請(qǐng)求數(shù)那 rate 算出來(lái)會(huì)很難看。先記結(jié)論類型特點(diǎn)典型用法Counter只增不減請(qǐng)求總數(shù)、錯(cuò)誤總數(shù)、字節(jié)數(shù)Gauge可增可減內(nèi)存用量、連接數(shù)、溫度Histogram累計(jì)桶計(jì)數(shù)請(qǐng)求耗時(shí)分布服務(wù)端可求分位數(shù)Summary客戶端預(yù)計(jì)算分位數(shù)舊系統(tǒng)兼容或需要精確分位時(shí)Counter 之所以叫 Counter是為了配合 rate()只看絕對(duì)值沒(méi)有意義絕對(duì)值除以時(shí)間才是每秒速率。Gauge 描述當(dāng)前狀態(tài)直接讀數(shù)不要對(duì)它做 increase。Histogram 和 Summary 都用于“分布”類指標(biāo)區(qū)別在分位數(shù)在哪一側(cè)計(jì)算——Histogram 在服務(wù)端算Summary 在客戶端算。推薦優(yōu)先使用 Histogram因?yàn)槟憧梢栽?PromQL 里隨意調(diào)整分位值Summary 則是一錘子買賣必須提前在埋點(diǎn)里定死。一個(gè)實(shí)際指標(biāo)端點(diǎn)的樣子可以用 curl 看curl -s http://127.0.0.1:9100/metrics | \ grep -E ^node_cpu_seconds_total|^node_memory_MemAvailable_bytes | head -n 5返回的每一行結(jié)構(gòu)是指標(biāo)名、用花括號(hào)包圍的標(biāo)簽、空格后的值。node_cpu_seconds_total 這個(gè) Counter 后面帶著 cpu 和 mode 兩個(gè)標(biāo)簽分別代表核序號(hào)和 CPU 工作模式值表示該模式下累計(jì)的 CPU 秒數(shù)??吹?_total 后綴基本可以斷定它是 Counter這是社區(qū)約定。2.3 標(biāo)簽是它的靈魂job、instance 與自定義標(biāo)簽怎么命名同一臺(tái)機(jī)器上的 node_cpu_seconds_total 之所以有多條序列就是因?yàn)闃?biāo)簽值不同。Prometheus 的多維模型意味著同一個(gè)指標(biāo) 一組不同的標(biāo)簽值 一條獨(dú)立的時(shí)間序列。所有查詢都是在這個(gè)多維空間里做切片。抓取配置里自帶兩個(gè)內(nèi)建標(biāo)簽job 是配置里的 job_nameinstance 是 targets 的地址加端口。比如 jobnodeinstance192.168.1.10:9100。自定義標(biāo)簽用 static_configs 里的 labels 字段加scrape_configs: - job_name: node static_configs: - targets: [192.168.1.10:9100] labels: env: prod role: web這段配置的效果是這個(gè) target 抓回來(lái)的每個(gè)序列都會(huì)帶 envprod、roleweb 這兩個(gè)固定標(biāo)簽。標(biāo)簽命名的原則是標(biāo)簽值的變化頻率越低越好。env、zone、role 這種固定值是理想標(biāo)簽Pod 名稱、容器 IP、用戶 ID 這種高頻變化的字段如果進(jìn)了標(biāo)簽序列數(shù)量會(huì)爆發(fā)式增長(zhǎng)直接撐爆內(nèi)存這個(gè)問(wèn)題在第 5 章單獨(dú)展開(kāi)。2.4 本地存儲(chǔ)機(jī)制block、壓縮與保留策略Prometheus 不是通用時(shí)序數(shù)據(jù)庫(kù)它的本地存儲(chǔ)是按 2 小時(shí)為一個(gè) block 寫的后臺(tái)再做 compaction 壓縮。默認(rèn)保留時(shí)間是 15 天超過(guò)保留期的 block 會(huì)被刪除。這個(gè)設(shè)計(jì)決定了它的定位為近期排障和告警而生的短周期監(jiān)控不適合做跨月趨勢(shì)分析和審計(jì)留存。相關(guān)參數(shù)在啟動(dòng)里能看到./prometheus \ --storage.tsdb.path/var/lib/prometheus \ --storage.tsdb.retention.time30dstorage.tsdb.path 指定數(shù)據(jù)目錄storage.tsdb.retention.time 寫成 30d 表示保留 30 天。我一般會(huì)在測(cè)試環(huán)境用 7d 省磁盤生產(chǎn)環(huán)境按合規(guī)要求設(shè) 15d 或 30d。想長(zhǎng)期留數(shù)年就得把遠(yuǎn)程存儲(chǔ)或者 Thanos 這類邊車方案引入進(jìn)來(lái)讓歷史 block 上傳到對(duì)象存儲(chǔ)。這個(gè)復(fù)雜度不是入門階段要考慮的但你要知道邊界在哪。3. 本地跑通 Prometheus 的最小部署從下載到第一個(gè)查詢概念到這兒差不多了下面直接動(dòng)手。這一章的最終目標(biāo)在你的 Linux 機(jī)器上跑起一個(gè) Prometheus抓取機(jī)器自身的指標(biāo)然后用 curl 驗(yàn)證一條真實(shí)查詢。整個(gè)過(guò)程不需要 Docker、不需要容器用最小依賴把鏈路打通。3.1 二進(jìn)制安裝與 systemd 托管常見(jiàn)做法是直接下載官方發(fā)布的二進(jìn)制包不用編譯不依賴額外運(yùn)行時(shí)。到官方下載站的 release 頁(yè)面拿當(dāng)前最新穩(wěn)定版的 linux-amd64 包文件名形如 prometheus-2.x.x.linux-amd64.tar.gz。解壓后目錄里自帶 prometheus 和 promtool 兩個(gè)二進(jìn)制tar xzf prometheus-2.x.x.linux-amd64.tar.gz cd prometheus-2.x.x.linux-amd64 ./prometheus --versionprometheus 是主服務(wù)promtool 是命令行校驗(yàn)工具配置寫完之后拿它驗(yàn)證語(yǔ)法很有用。下載的版本號(hào)按你實(shí)際拿到的文件替換下文其他地方同理。把服務(wù)交給 systemd 管理便于開(kāi)機(jī)自啟和崩潰拉起。先建運(yùn)行用戶和數(shù)據(jù)目錄sudo useradd --no-create-home --shell /bin/false prometheus sudo mkdir -p /etc/prometheus /var/lib/prometheus sudo cp prometheus promtool /usr/local/bin/然后寫 systemd 單元文件配置文件路徑指定到 /etc/prometheus/prometheus.yml[Unit] DescriptionPrometheus Wantsnetwork-online.target Afternetwork-online.target [Service] Userprometheus Groupprometheus Typesimple ExecStart/usr/local/bin/prometheus \ --config.file/etc/prometheus/prometheus.yml \ --storage.tsdb.path/var/lib/prometheus \ --storage.tsdb.retention.time30d \ --web.enable-lifecycle Restartalways [Install] WantedBymulti-user.targetUser 和 Group 指定服務(wù)降權(quán)運(yùn)行避免 Prometheus 以 root 身份跑。storage.tsdb.path 是數(shù)據(jù)目錄務(wù)必保證 prometheus 用戶對(duì)它可寫。Restartalways 保證進(jìn)程不因意外退出而失聯(lián)。Typesimple 表示 ExecStart 啟動(dòng)的進(jìn)程本身就是主進(jìn)程。--web.enable-lifecycle 是為了后面能通過(guò)接口熱加載配置不加的話配置改動(dòng)必須重啟進(jìn)程。啟動(dòng)sudo systemctl daemon-reload sudo systemctl enable --now prometheus systemctl status prometheus看到 active (running) 說(shuō)明服務(wù)起來(lái)了瀏覽器訪問(wèn)服務(wù)器 9090 端口就能看到自帶的 UI。3.2 第一份 prometheus.yml抓取間隔、規(guī)則加載與 storage 配置Prometheus 的一切行為都從這份 YAML 開(kāi)始。一個(gè)能工作的最小配置長(zhǎng)這樣global: scrape_interval: 15s evaluation_interval: 15s scrape_timeout: 10s rule_files: - /etc/prometheus/rules/*.yml scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090]global 里的三個(gè)參數(shù)是全局默認(rèn)值scrape_interval 表示多久抓一次目標(biāo)evaluation_interval 表示多久評(píng)估一次告警規(guī)則scrape_timeout 表示單次抓取允許的最大耗時(shí)。三者之間有個(gè)硬約束scrape_timeout 必須小于 scrape_interval如果抓一次要 8 秒、但 5 秒就再抓請(qǐng)求會(huì)重疊產(chǎn)生一堆超時(shí)誤報(bào)。rule_files 指向告警規(guī)則的存放路徑現(xiàn)在還沒(méi)有規(guī)則文件留空也會(huì)正常啟動(dòng)。scrape_configs 里定義的 job_nameprometheus 是讓 Prometheus 抓自己暴露的指標(biāo)targets 寫 localhost:9090 就是它的 /metrics 地址。配置改完之后用 promtool 校驗(yàn)promtool check config /etc/prometheus/prometheus.yml輸出 SUCCESS 說(shuō)明語(yǔ)法通過(guò)。配置文件改動(dòng)后需要重載才生效不用重啟進(jìn)程因?yàn)?3.1 里已經(jīng)開(kāi)了 lifecycle 開(kāi)關(guān)curl -X POST http://127.0.0.1:9090/-/reload注意 9090 端口的默認(rèn)監(jiān)聽(tīng)地址是 0.0.0.0生產(chǎn)環(huán)境一定用防火墻限制訪問(wèn)來(lái)源或者在前面加一層帶認(rèn)證的反向代理否則任何人都能查你的監(jiān)控?cái)?shù)據(jù)。3.3 掛載 Node Exporter監(jiān)控一臺(tái)普通 Linux 機(jī)器Prometheus 只負(fù)責(zé)拉取指標(biāo)從哪來(lái)取決于被監(jiān)控對(duì)象。對(duì) Linux 服務(wù)器社區(qū)標(biāo)準(zhǔn)做法是跑一個(gè) node_exporter它把 CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)等系統(tǒng)指標(biāo)暴露在 9100 端口。同樣從官方下載站拿 node_exporter 的 linux-amd64 包tar xzf node_exporter-1.x.x.linux-amd64.tar.gz cd node_exporter-1.x.x.linux-amd64 sudo cp node_exporter /usr/local/bin/ node_exporter --web.listen-address:9100 同樣可以把它寫進(jìn) systemd 管理此處先用后臺(tái)方式驗(yàn)證。起來(lái)之后用 curl 看一眼指標(biāo)端點(diǎn)curl http://127.0.0.1:9100/metrics | head -n 20能看到一堆 node_ 開(kāi)頭的指標(biāo)就說(shuō)明 exporter 工作正常。此時(shí)回到 Prometheus 配置文件把 target 加進(jìn)去scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090] - job_name: node static_configs: - targets: [192.168.1.10:9100] labels: role: web重載之后Web UI 里 Status - Targets 頁(yè)面會(huì)多出一個(gè) node 任務(wù)狀態(tài)為 UP 表示抓取鏈路通暢。labels 里的 role 是自定義標(biāo)簽加它的目的是在查詢時(shí)能按業(yè)務(wù)角色切分。3.4 用 curl 做第一次手動(dòng)查詢看一眼 /api/v1/queryWeb UI 里的 Graph 面板本質(zhì)就是發(fā) HTTP 請(qǐng)求到查詢 API。直接 curl 能更清楚看到數(shù)據(jù)如何返回curl -G http://127.0.0.1:9090/api/v1/query \ --data-urlencode queryup返回的 JSON 會(huì)有 status、data.resultType 和 data.result。result 數(shù)組里每項(xiàng)代表一條序列up 的值是 1 表示上一次抓取成功。Prometheus 內(nèi)置的 up 指標(biāo)是自檢探活最常用的每個(gè) target 都有。再查一個(gè)真實(shí)指標(biāo)curl -G http://127.0.0.1:9090/api/v1/query \ --data-urlencode querynode_memory_MemAvailable_bytes這時(shí)候返回結(jié)果里帶著 instance 和 job 標(biāo)簽值是該機(jī)當(dāng)前可用內(nèi)存字節(jié)數(shù)。查詢 API 是 Prometheus 對(duì)外的數(shù)據(jù)接口Grafana、自研平臺(tái)、命令行都是通過(guò)它拿數(shù)據(jù)的理解 curl 的行為等于理解了所有下游工具的調(diào)用方式。4. PromQL 進(jìn)階rate、histogram_quantile 與聚合的正確打開(kāi)方式PromQL 是 Prometheus 的查詢語(yǔ)言也是“玩轉(zhuǎn)”這個(gè)詞里含金量最高的部分?;A(chǔ)查詢照葫蘆畫瓢不難難在窗口、速率、分位、聚合這些概念之間存在大量邊界條件。這一章把最常見(jiàn)也最容易出錯(cuò)的四個(gè)操作講透。4.1 四類選擇器匹配字符串的四個(gè)符號(hào)一條完整的 PromQL 由指標(biāo)名、標(biāo)簽選擇器和可選的函數(shù)/運(yùn)算組成。標(biāo)簽選擇器有四種寫法http_requests_total{jobapi} http_requests_total{job!api} http_requests_total{job~api|web} http_requests_total{job!~api|web}第一行是精確匹配第二行是不等于第三行是正則匹配第四行是不匹配正則。正則表達(dá)式用 RE2 語(yǔ)法不是 PCRE所以像 ? 這類需要回溯的斷言是不能用的。選擇器寫的標(biāo)簽越多篩選條件越收斂。注意一個(gè)陷阱PromQL 里 {job} 能匹配到?jīng)]有該標(biāo)簽的序列但 {job!} 不會(huì)排除沒(méi)有該標(biāo)簽的序列——它只在有 job 標(biāo)簽的序列里過(guò)濾。兩套語(yǔ)義不一致寫排除條件時(shí)習(xí)慣先確認(rèn)目標(biāo)序列確實(shí)帶著這些標(biāo)簽。4.2 速率計(jì)算的三條公式rate、irate 和 increaseCounter 型指標(biāo)本身是累計(jì)值用它排查問(wèn)題必須轉(zhuǎn)成速率。三個(gè)函數(shù)是等價(jià)的入口但行為差異很大rate(node_cpu_seconds_total{modeuser}[5m]) irate(node_cpu_seconds_total{modeuser}[5m]) increase(http_requests_total[5m])rate 計(jì)算窗口內(nèi)每秒平均增速取窗口第一個(gè)樣本和最后一個(gè)樣本差值除以兩者時(shí)間差。irate 只看窗口最后的兩個(gè)樣本反映瞬時(shí)尖峰曲線更敏感、也更毛糙。increase 返回窗口內(nèi)的總增量用于看“這 5 分鐘漲了多少”這類問(wèn)題。窗口參數(shù) [5m] 不是隨便填的窗口至少要是抓取間隔的兩倍否則窗口里可能只有一兩個(gè)樣本rate 算出來(lái)要么是 0 要么是殘值。我個(gè)人的習(xí)慣是15s 抓一次就用 5m看長(zhǎng)期趨勢(shì)用 rate看突發(fā)尖峰用 irateincrease 只在要和總量對(duì)比時(shí)用。4.3 直方圖分位數(shù)histogram_quantile 的參數(shù)與坑耗時(shí)類指標(biāo)是排查性能問(wèn)題的關(guān)鍵用的就是 Histogram。它把觀測(cè)值按 bucket 累計(jì)比如http_request_duration_seconds_bucket{le0.1} 3521 http_request_duration_seconds_bucket{le0.5} 5600 http_request_duration_seconds_bucket{le1} 7200 http_request_duration_seconds_bucket{leInf} 9800le 標(biāo)簽是“小于等于”的邊界數(shù)值是累計(jì)計(jì)數(shù)耗時(shí) 0.1 秒以內(nèi)的請(qǐng)求 3521 個(gè)1 秒以內(nèi)的 7200 個(gè)。求 P99 的標(biāo)準(zhǔn)寫法是histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))里面那層 rate 先把累計(jì)計(jì)數(shù)變成每秒增量sum by (le) 按 le 標(biāo)簽聚合所有實(shí)例維度外層 histogram_quantile 在 bucket 之間做線性插值。三個(gè)細(xì)節(jié)必須記住第一聚合時(shí)只能保留 le其他維度都要用 by 規(guī)則聚合掉或過(guò)濾掉不然插值會(huì)錯(cuò)第二bucket 的粒度決定分位數(shù)的精度le 跨度越大P99 的誤差越大第三不要對(duì) Histogram 用 increase因?yàn)榉治粩?shù)需要的是速率分布總量沒(méi)有意義。4.4 聚合與維度控制CPU 使用率的正確寫法聚合函數(shù)控制著多序列如何合并。最常用的帶上 by 保留維度sum(rate(node_cpu_seconds_total[5m])) by (instance) avg(rate(node_cpu_seconds_total{modeidle}[5m])) * 100第一行按 instance 分組計(jì)算整機(jī) CPU 每秒使用速率第二行算的是空閑率。要 CPU 使用率取空閑率的補(bǔ)集100 - avg(rate(node_cpu_seconds_total{modeidle}[5m])) * 100這個(gè)公式看似繞但它是社區(qū)里對(duì) CPU 使用率最穩(wěn)定的定義之一。不能直接對(duì) user mode 求和因?yàn)?mode 還有 system、iowait、steal 等好幾種只取 user 會(huì)漏掉一部分負(fù)載。寫內(nèi)存使用率也有類似的套路100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)用空閑內(nèi)存的補(bǔ)集避免被 buffer/cache 干擾。聚合維度的選擇和指標(biāo)語(yǔ)義強(qiáng)相關(guān)這部分的判斷經(jīng)驗(yàn)比語(yǔ)法本身更值錢建議每個(gè)團(tuán)隊(duì)都沉淀一套自己的常用指標(biāo)字典。5. Prometheus 實(shí)戰(zhàn)避坑5 個(gè)讓我熬夜的血淚教訓(xùn)精確踩坑比順暢教程更救命。這里列的是我在多個(gè)環(huán)境中真實(shí)遇到的問(wèn)題每條都按現(xiàn)象、原因、解決方案展開(kāi)你遇到同類問(wèn)題可以直接照著走。5.1 現(xiàn)象targets 一直 UP查詢卻沒(méi)有最近數(shù)據(jù)某個(gè)環(huán)境里界面顯示所有 target 都是 UP但曲線時(shí)間軸越往前越近最新數(shù)據(jù)停在幾分鐘前再往后就沒(méi)點(diǎn)了??雌饋?lái)像“丟了數(shù)據(jù)”。原因是虛擬機(jī)所在宿主機(jī)和監(jiān)控服務(wù)器的時(shí)鐘不同步node_exporter 上報(bào)的樣本時(shí)間戳比 Prometheus 本地時(shí)鐘慢了幾分鐘。Prometheus 在寫入時(shí)會(huì)對(duì)時(shí)間戳做合理性判斷過(guò)于陳舊的樣本直接拒絕。解決給所有被監(jiān)控節(jié)點(diǎn)統(tǒng)一部署 NTP 同步配合 chrony 或 systemd-timesyncd 都可以。同步完成后重啟 exporter讓新樣本帶正確的時(shí)間戳。這類問(wèn)題排查時(shí)最容易迷惑的是“指標(biāo)還在但圖形在漂”先查兩端 date 命令輸出10 秒就能確認(rèn)。5.2 現(xiàn)象increase 在服務(wù)重啟后數(shù)值明顯失真某服務(wù)每隔幾天重啟一次increase(http_requests_total[5m]) 在重啟時(shí)刻出現(xiàn)一個(gè)異常的尖峰或斷崖告警也跟著誤報(bào)。原因是 Counter 在進(jìn)程重啟時(shí)歸零。increase 計(jì)算的是窗口內(nèi)最后一個(gè)樣本減第一個(gè)樣本如果重啟發(fā)生在窗口中間兩側(cè)的樣本來(lái)自新舊兩個(gè)進(jìn)程周期差值把正常增長(zhǎng)和歸零突變混在一起算出來(lái)結(jié)果必然失真。解決不要在重啟場(chǎng)景里直接用 increase 做告警閾值先看 up 是否發(fā)生過(guò)翻轉(zhuǎn)再?zèng)Q定要不要信這個(gè)增量。也可以改用來(lái)對(duì)比兩個(gè)時(shí)間點(diǎn)的總量差值或者把重啟事件計(jì)入部署流程里的告警屏蔽窗口。一句話rate 和 increase 的前提是 Counter 連續(xù)遞增進(jìn)程一旦重啟這個(gè)前提就破了你需要自己補(bǔ)條件。5.3 現(xiàn)象up 1 但業(yè)務(wù)已經(jīng)連續(xù)報(bào)錯(cuò)Prometheus 自帶的 up 指標(biāo)表示“抓取到了指標(biāo)”不表示“服務(wù)健康”。很多團(tuán)隊(duì)的第一條告警就是 up 0結(jié)果某次接口全面 5xxup 卻依然全綠。原因是 exporter 的探活停留在網(wǎng)絡(luò)層面node_exporter 能抓到數(shù)據(jù)說(shuō)明操作系統(tǒng)活著、9100 端口通至于業(yè)務(wù)進(jìn)程是不是在返回錯(cuò)誤up 根本不關(guān)心。它是基礎(chǔ)設(shè)施探活不是業(yè)務(wù)健康探活。解決業(yè)務(wù)健康要單獨(dú)埋點(diǎn)。HTTP 服務(wù)用 blackbox_exporter 做真實(shí)探活或者用業(yè)務(wù)自身暴露的指標(biāo)比如 http_requests_total{code5xx} 的速率超過(guò)閾值時(shí)告警。把 up 當(dāng)“基礎(chǔ)設(shè)施在線”看把業(yè)務(wù)指標(biāo)當(dāng)“用戶體感在線”看兩者組合才是完整的健康判斷。5.4 現(xiàn)象Prometheus 內(nèi)存一路攀升頻繁 OOM某次上線新業(yè)務(wù)后Prometheus 進(jìn)程的 RSS 曲線肉眼可見(jiàn)地往上走幾天后 OOM 被殺重啟后繼續(xù)攀升。原因是標(biāo)簽基數(shù)爆炸。某個(gè)客戶端埋點(diǎn)把請(qǐng)求里的請(qǐng)求 ID 或者用戶 ID 寫成了標(biāo)簽值這會(huì)導(dǎo)致每來(lái)一個(gè) ID 就新增一條時(shí)間序列。10 個(gè) ID 沒(méi)問(wèn)題1 萬(wàn)個(gè) ID 內(nèi)存就崩了。Prometheus 的時(shí)序是按標(biāo)簽組合存儲(chǔ)的組合數(shù)等于各標(biāo)簽值數(shù)量的笛卡爾積增長(zhǎng)是指數(shù)級(jí)的。解決先看當(dāng)前序列總量prometheus_tsdb_head_series如果數(shù)值遠(yuǎn)超預(yù)期去收集端把高基數(shù)標(biāo)簽去掉。已經(jīng)在內(nèi)存里的數(shù)據(jù)用 metric_relabel_configs 在抓取時(shí)把標(biāo)簽丟棄scrape_configs: - job_name: problem_app metric_relabel_configs: - source_labels: [request_id] regex: . action: labeldrop注意relabel 只控制寫入 Prometheus 的數(shù)據(jù)源頭埋點(diǎn)不改的話流量早晚還會(huì)漲回來(lái)。更徹底的方案是把這類標(biāo)簽從指標(biāo)設(shè)計(jì)階段就刪除或者用日志系統(tǒng)去承載這類高基數(shù)維度。5.5 現(xiàn)象抓取超時(shí)exporter 數(shù)據(jù)間歇性空白某個(gè) exporter 產(chǎn)生的指標(biāo)特別多15 秒的間隔里經(jīng)常抓不完目標(biāo)一會(huì) UP 一會(huì) DOWN曲線斷斷續(xù)續(xù)。原因是 scrape_timeout 太短。注意 Prometheus 的超時(shí)邏輯抓取開(kāi)始后如果超過(guò) scrape_timeout 還沒(méi)返回完這次抓取會(huì)被標(biāo)記失敗下一次間隔再試所以圖形上表現(xiàn)為“漏點(diǎn)”。默認(rèn) 10s對(duì)于大 exporter 來(lái)說(shuō)確實(shí)不夠。解決拆開(kāi)兩個(gè)參數(shù)——拉長(zhǎng)抓取間隔、增大超時(shí)但超時(shí)必須小于間隔scrape_configs: - job_name: big_exporter scrape_interval: 60s scrape_timeout: 30s也可以檢查 exporter 自身是不是花了太多時(shí)間在計(jì)算指標(biāo)上例如 node_exporter 的某些 collector 可以按需關(guān)閉。參數(shù)調(diào)節(jié)本質(zhì)是拿時(shí)效性換完整性到底多長(zhǎng)合適要看你對(duì)數(shù)據(jù)粒度還是數(shù)據(jù)連續(xù)性的優(yōu)先級(jí)更高。6. 從查詢到告警Prometheus 的進(jìn)階用法與自檢習(xí)慣把數(shù)據(jù)查出來(lái)是一回事讓監(jiān)控自動(dòng)找你就是另一回事。最后這一章補(bǔ)上告警閉環(huán)然后給你一份自檢清單把這套體系真正變成日常依賴的“值班伙伴”。6.1 告警規(guī)則與 Alertmanager兩個(gè)組件各管一段告警規(guī)則寫在 Prometheus 的 rule_files 里Prometheus 按 evaluation_interval 周期評(píng)估規(guī)則表達(dá)式觸發(fā)后把告警發(fā)給 Alertmanager。Alertmanager 負(fù)責(zé)去重、分組、路由和通知渠道。先在 rules 目錄建一個(gè) node_alerts.ymlgroups: - name: node_alerts rules: - alert: NodeDown expr: up{jobnode} 0 for: 2m labels: severity: critical annotations: summary: instance {{ $labels.instance }} downexpr 是觸發(fā)條件for: 2m 表示條件持續(xù) 2 分鐘才激活避免瞬時(shí)抖動(dòng)誤報(bào)。labels 和 annotations 是告警的元數(shù)據(jù)和可讀描述Alertmanager 里會(huì)按 labels 做路由。Alertmanager 的配置負(fù)責(zé)把告警發(fā)出去一個(gè)最小配置長(zhǎng)這樣route: receiver: default receivers: - name: default webhook_configs: - url: http://127.0.0.1:8080/alertwebhook 通道是為了對(duì)接企業(yè)內(nèi)部的消息平臺(tái)。生產(chǎn)環(huán)境一定要配置分組規(guī)則把同服務(wù)多實(shí)例的告警合并成一條否則大故障時(shí)告警轟炸是必然的。6.2 長(zhǎng)期可用的自檢清單監(jiān)控系統(tǒng)自己也會(huì)生病我習(xí)慣每周跑一遍下面的檢查成本不到十分鐘檢查項(xiàng)方法關(guān)注點(diǎn)抓取失敗率up 0 的 target 數(shù)不應(yīng)持續(xù)存在抓取耗時(shí)max(scrape_duration_seconds)是否逼近 scrape_timeout時(shí)間戳延遲timestamp(up) 與當(dāng)前時(shí)間差不應(yīng)持續(xù)增長(zhǎng)序列總量prometheus_tsdb_head_series和上周對(duì)比是否翻倍規(guī)則執(zhí)行失敗prometheus_rule_evaluation_failures_total必須為 0磁盤使用tsdb 目錄占用率按 retention 估算增長(zhǎng)這套清單不解決所有問(wèn)題但能擋住大部分“監(jiān)控沒(méi)報(bào)警才知道監(jiān)控掛了”的尷尬。從我自己的經(jīng)驗(yàn)講每次出問(wèn)題后回來(lái)反思最后 80% 都落在指標(biāo)設(shè)計(jì)不嚴(yán)謹(jǐn)或告警閾值沒(méi)對(duì)齊上Prometheus 本身反而很少是根源。把基礎(chǔ)打牢比追新工具值錢得多。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取