高可用?Prometheus?架構(gòu)實(shí)踐中的踩坑集錦
掃描二維碼
隨時(shí)隨地手機(jī)看文章
-
監(jiān)控是基礎(chǔ)設(shè)施,目的是為了解決問題,不要只朝著大而全去做,尤其是不必要的指標(biāo)采集,浪費(fèi)人力和存儲(chǔ)資源(To B商業(yè)產(chǎn)品例外)。
-
需要處理的告警才發(fā)出來,發(fā)出來的告警必須得到處理。
-
簡(jiǎn)單的架構(gòu)就是最好的架構(gòu),業(yè)務(wù)系統(tǒng)都掛了,監(jiān)控也不能掛。Google Sre 里面也說避免使用 Magic 系統(tǒng),例如機(jī)器學(xué)習(xí)報(bào)警閾值、自動(dòng)修復(fù)之類。這一點(diǎn)見仁見智吧,感覺很多公司都在搞智能 AI 運(yùn)維。
一、版本的選擇
Prometheus 當(dāng)前最新版本為 2.16,Prometheus 還在不斷迭代,因此盡量用最新版,1.X版本就不用考慮了。
二、Prometheus 的局限
-
Prometheus 是基于 Metric 的監(jiān)控,不適用于日志(Logs)、事件(Event)、調(diào)用鏈(Tracing)。
-
Prometheus 默認(rèn)是 Pull 模型,合理規(guī)劃你的網(wǎng)絡(luò),盡量不要轉(zhuǎn)發(fā)。
-
對(duì)于集群化和水平擴(kuò)展,官方和社區(qū)都沒有銀彈,需要合理選擇 Federate、Cortex、Thanos等方案。
-
監(jiān)控系統(tǒng)一般情況下可用性大于一致性,容忍部分副本數(shù)據(jù)丟失,保證查詢請(qǐng)求成功。這個(gè)后面說 Thanos 去重的時(shí)候會(huì)提到。
-
Prometheus 不一定保證數(shù)據(jù)準(zhǔn)確,這里的不準(zhǔn)確一是指 rate、histogram_quantile 等函數(shù)會(huì)做統(tǒng)計(jì)和推斷,產(chǎn)生一些反直覺的結(jié)果,這個(gè)后面會(huì)詳細(xì)展開。二來查詢范圍過長(zhǎng)要做降采樣,勢(shì)必會(huì)造成數(shù)據(jù)精度丟失,不過這是時(shí)序數(shù)據(jù)的特點(diǎn),也是不同于日志系統(tǒng)的地方。
三、K8S 集群中常用的 exporter
Prometheus 屬于 CNCF 項(xiàng)目,擁有完整的開源生態(tài),與 Zabbix 這種傳統(tǒng) agent 監(jiān)控不同,它提供了豐富的 exporter 來滿足你的各種需求。你可以在這里看到官方、非官方的 exporter。如果還是沒滿足你的需求,你還可以自己編寫 exporter,簡(jiǎn)單方便、自由開放,這是優(yōu)點(diǎn)。但是過于開放就會(huì)帶來選型、試錯(cuò)成本。之前只需要在 zabbix agent里面幾行配置就能完成的事,現(xiàn)在你會(huì)需要很多 exporter 搭配才能完成。還要對(duì)所有 exporter 維護(hù)、監(jiān)控。尤其是升級(jí) exporter 版本時(shí),很痛苦。非官方exporter 還會(huì)有不少 bug。這是使用上的不足,當(dāng)然也是 Prometheus 的設(shè)計(jì)原則。K8S 生態(tài)的組件都會(huì)提供/metric接口以提供自監(jiān)控,這里列下我們正在使用的:
- cadvisor: 集成在 Kubelet 中。
- kubelet: 10255為非認(rèn)證端口,10250為認(rèn)證端口。
- apiserver: 6443端口,關(guān)心請(qǐng)求數(shù)、延遲等。
- scheduler: 10251端口。
- controller-manager: 10252端口。
- etcd: 如etcd 寫入讀取延遲、存儲(chǔ)容量等。
- docker: 需要開啟 experimental 實(shí)驗(yàn)特性,配置 metrics-addr,如容器創(chuàng)建耗時(shí)等指標(biāo)。
- kube-proxy: 默認(rèn) 127 暴露,10249端口。外部采集時(shí)可以修改為 0.0.0.0 監(jiān)聽,會(huì)暴露:寫入 iptables 規(guī)則的耗時(shí)等指標(biāo)。
- kube-state-metrics: K8S 官方項(xiàng)目,采集pod、deployment等資源的元信息。
- node-exporter: Prometheus 官方項(xiàng)目,采集機(jī)器指標(biāo)如 CPU、內(nèi)存、磁盤。
- blackbox_exporter: Prometheus 官方項(xiàng)目,網(wǎng)絡(luò)探測(cè),dns、ping、http監(jiān)控
- process-exporter: 采集進(jìn)程指標(biāo)
- nvidia exporter: 我們有 gpu 任務(wù),需要 gpu 數(shù)據(jù)監(jiān)控
- node-problem-detector: 即 npd,準(zhǔn)確的說不是 exporter,但也會(huì)監(jiān)測(cè)機(jī)器狀態(tài),上報(bào)節(jié)點(diǎn)異常打 taint
- 應(yīng)用層 exporter: mysql、nginx、mq等,看業(yè)務(wù)需求。
四、K8S 核心組件監(jiān)控與 Grafana 面板
k8s 集群運(yùn)行中需要關(guān)注核心組件的狀態(tài)、性能。如 kubelet、apiserver 等,基于上面提到的 exporter 的指標(biāo),可以在 Grafana 中繪制如下圖表:
五、采集組件 All IN One
Prometheus 體系中 Exporter 都是獨(dú)立的,每個(gè)組件各司其職,如機(jī)器資源用 Node-Exporter,Gpu 有Nvidia Exporter等等。但是 Exporter 越多,運(yùn)維壓力越大,尤其是對(duì) Agent做資源控制、版本升級(jí)。我們嘗試對(duì)一些Exporter進(jìn)行組合,方案有二:
-
通過主進(jìn)程拉起N個(gè) Exporter 進(jìn)程,仍然可以跟著社區(qū)版本做更新、bug fix。
-
用Telegraf來支持各種類型的 Input,N 合 1。
六、合理選擇黃金指標(biāo)
采集的指標(biāo)有很多,我們應(yīng)該關(guān)注哪些?Google 在“Sre Handbook”中提出了“四個(gè)黃金信號(hào)”:延遲、流量、錯(cuò)誤數(shù)、飽和度。實(shí)際操作中可以使用 Use 或 Red 方法作為指導(dǎo),Use 用于資源,Red 用于服務(wù)。
-
Use 方法:Utilization、Saturation、Errors。如 Cadvisor 數(shù)據(jù)
-
Red 方法:Rate、Errors、Duration。如 Apiserver 性能指標(biāo)
- 在線服務(wù):如 Web 服務(wù)、數(shù)據(jù)庫等,一般關(guān)心請(qǐng)求速率,延遲和錯(cuò)誤率即 RED 方法
- 離線服務(wù):如日志處理、消息隊(duì)列等,一般關(guān)注隊(duì)列數(shù)量、進(jìn)行中的數(shù)量,處理速度以及發(fā)生的錯(cuò)誤即 Use 方法
- 批處理任務(wù):和離線任務(wù)很像,但是離線任務(wù)是長(zhǎng)期運(yùn)行的,批處理任務(wù)是按計(jì)劃運(yùn)行的,如持續(xù)集成就是批處理任務(wù),對(duì)應(yīng) K8S 中的 job 或 cronjob, 一般關(guān)注所花的時(shí)間、錯(cuò)誤數(shù)等,因?yàn)檫\(yùn)行周期短,很可能還沒采集到就運(yùn)行結(jié)束了,所以一般使用 Pushgateway,改拉為推。
七、K8S 1.16中 Cadvisor 的指標(biāo)兼容問題
在 K8S 1.16版本,Cadvisor 的指標(biāo)去掉了 pod_Name 和 container_name 的 label,替換為了pod 和 container。如果你之前用這兩個(gè) label 做查詢或者 Grafana 繪圖,需要更改下 Sql 了。因?yàn)槲覀円恢敝С侄鄠€(gè) K8S 版本,就通過 relabel配置繼續(xù)保留了原來的**_name。metric_relabel_configs:- source_labels: [container]regex: (. )
target_label: container_name
replacement: $1
action: replace
- source_labels: [pod]
regex: (. )
target_label: pod_name
replacement: $1
action: replace 注意要用 metric_relabel_configs,不是 relabel_configs,采集后做的replace。
八、Prometheus 采集外部 K8S 集群、多集群
Prometheus 如果部署在K8S集群內(nèi)采集是很方便的,用官方給的Yaml就可以,但我們因?yàn)闄?quán)限和網(wǎng)絡(luò)需要部署在集群外,二進(jìn)制運(yùn)行,采集多個(gè) K8S 集群。
honor_timestamps: true
scrape_interval: 30s
scrape_timeout: 10s
metrics_path: /metrics
scheme: https
kubernetes_sd_configs:
- api_server: https://xx:6443
role: node
bearer_token_file: token/cluster.token
tls_config:
insecure_skip_verify: true
bearer_token_file: token/cluster.token
tls_config:
insecure_skip_verify: true
relabel_configs:
- separator: ;
regex: __meta_kubernetes_node_label_(. )
replacement: $1
action: labelmap
- separator: ;
regex: (.*)
target_label: __address__
replacement: xx:6443
action: replace
- source_labels: [__meta_kubernetes_node_name]
separator: ;
regex: (. )
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
action: replace
metric_relabel_configs:
- source_labels: [container]
separator: ;
regex: (. )
target_label: container_name
replacement: $1
action: replace
- source_labels: [pod]
separator: ;
regex: (. )
target_label: pod_name
replacement: $1
action: replace bearer_token_file 需要提前生成,這個(gè)參考官方文檔即可。記得 base64 解碼。
honor_timestamps: true
scrape_interval: 30s
scrape_timeout: 10s
metrics_path: /metrics
scheme: https
kubernetes_sd_configs:
- api_server: https://xxx:6443
role: endpoints
bearer_token_file: token/cluster.token
tls_config:
insecure_skip_verify: true
bearer_token_file: token/cluster.token
tls_config:
insecure_skip_verify: true
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
separator: ;
regex: "true"
replacement: $1
action: keep
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
separator: ;
regex: (https?)
target_label: __scheme__
replacement: $1
action: replace
- separator: ;
regex: (.*)
target_label: __address__
replacement: xxx:6443
action: replace
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_endpoints_name,
__meta_kubernetes_service_annotation_prometheus_io_port]
separator: ;
regex: (. );(. );(.*)
target_label: __metrics_path__
replacement: /api/v1/namespaces/${1}/services/${2}:${3}/proxy/metrics
action: replace
- separator: ;
regex: __meta_kubernetes_service_label_(. )
replacement: $1
action: labelmap
- source_labels: [__meta_kubernetes_namespace]
separator: ;
regex: (.*)
target_label: kubernetes_namespace
replacement: $1
action: replace
- source_labels: [__meta_kubernetes_service_name]
separator: ;
regex: (.*)
target_label: kubernetes_name
replacement: $1
action: replace 對(duì)于 endpoint 類型,需要轉(zhuǎn)換__metrics_path__為/api/v1/namespaces/{1}/services/{2}:${3}/proxy/metrics,需要替換 namespace、svc 名稱端口等,這里的寫法只適合接口為/metrics的exporter,如果你的 exporter 不是/metrics接口,需要替換這個(gè)路徑?;蛘呦裎覀円粯咏y(tǒng)一約束都使用這個(gè)地址。
-
role:node 的,包括 cadvisor、 node-exporter、kubelet 的 summary、kube-proxy、docker 等指標(biāo)
-
role:endpoint 的,包括 kube-state-metric 以及其他自定義 Exporter
-
普通采集:包括Etcd、Apiserver 性能指標(biāo)、進(jìn)程指標(biāo)等。
九、GPU 指標(biāo)的獲取
nvidia-smi可以查看機(jī)器上的 GPU 資源,而Cadvisor 其實(shí)暴露了Metric來表示容器使用 GPU 情況,
container_accelerator_memory_total_bytes
container_accelerator_memory_used_bytes 如果要更詳細(xì)的 GPU 數(shù)據(jù),可以安裝dcgm exporter,不過K8S 1.13 才能支持。
十、更改 Prometheus 的顯示時(shí)區(qū)
Prometheus 為避免時(shí)區(qū)混亂,在所有組件中專門使用 Unix Time 和 Utc 進(jìn)行顯示。不支持在配置文件中設(shè)置時(shí)區(qū),也不能讀取本機(jī) /etc/timezone 時(shí)區(qū)。其實(shí)這個(gè)限制是不影響使用的:- 如果做可視化,Grafana是可以做時(shí)區(qū)轉(zhuǎn)換的。
- 如果是調(diào)接口,拿到了數(shù)據(jù)中的時(shí)間戳,你想怎么處理都可以。
- 如果因?yàn)?Prometheus 自帶的 UI 不是本地時(shí)間,看著不舒服,2.16 版本的新版 Web UI已經(jīng)引入了Local Timezone 的選項(xiàng),區(qū)別見下圖。
- 如果你仍然想改 Prometheus 代碼來適應(yīng)自己的時(shí)區(qū),可以參考這篇文章。
十一、如何采集 LB 后面的 RS 的 Metric
假如你有一個(gè)負(fù)載均衡 LB,但網(wǎng)絡(luò)上 Prometheus 只能訪問到 LB 本身,訪問不到后面的 RS,應(yīng)該如何采集 RS 暴露的 Metric?
-
RS 的服務(wù)加 Sidecar Proxy,或者本機(jī)增加 Proxy 組件,保證 Prometheus 能訪問到。
-
LB 增加 /backend1 和 /backend2請(qǐng)求轉(zhuǎn)發(fā)到兩個(gè)單獨(dú)的后端,再由 Prometheus 訪問 LB 采集。
十二、Prometheus 大內(nèi)存問題
隨著規(guī)模變大,Prometheus 需要的 CPU 和內(nèi)存都會(huì)升高,內(nèi)存一般先達(dá)到瓶頸,這個(gè)時(shí)候要么加內(nèi)存,要么集群分片減少單機(jī)指標(biāo)。這里我們先討論單機(jī)版 Prometheus 的內(nèi)存問題。
-
Prometheus 的內(nèi)存消耗主要是因?yàn)槊扛?小時(shí)做一個(gè) Block 數(shù)據(jù)落盤,落盤之前所有數(shù)據(jù)都在內(nèi)存里面,因此和采集量有關(guān)。
-
加載歷史數(shù)據(jù)時(shí),是從磁盤到內(nèi)存的,查詢范圍越大,內(nèi)存越大。
-
一些不合理的查詢條件也會(huì)加大內(nèi)存,如 Group 或大范圍 Rate。
-
作者給了一個(gè)計(jì)算器,設(shè)置指標(biāo)量、采集間隔之類的,計(jì)算 Prometheus 需要的理論內(nèi)存值:計(jì)算公式
-
Sample 數(shù)量超過了 200 萬,就不要單實(shí)例了,做下分片,然后通過 Victoriametrics,Thanos,Trickster 等方案合并數(shù)據(jù)。
-
評(píng)估哪些 Metric 和 Label 占用較多,去掉沒用的指標(biāo)。
-
查詢時(shí)盡量避免大范圍查詢,注意時(shí)間范圍和 Step 的比例,慎用 Group。
-
如果需要關(guān)聯(lián)查詢,先想想能不能通過 Relabel 的方式給原始數(shù)據(jù)多加個(gè) Label,一條Sql 能查出來的何必用Join,時(shí)序數(shù)據(jù)庫不是關(guān)系數(shù)據(jù)庫。
-
通過 pprof分析:
-
1.X 版本的內(nèi)存:
-
https://groups.google.com/forum/#!searchin/prometheus-users/memory|sort:date/prometheus-users/q4oiVGU6Bxo/uifpXVw3CwAJ
-
https://github.com/prometheus/prometheus/issues/5723
-
https://github.com/prometheus/prometheus/issues/1881
十三、Prometheus 容量規(guī)劃
容量規(guī)劃除了上邊說的內(nèi)存,還有磁盤存儲(chǔ)規(guī)劃,這和你的 Prometheus 的架構(gòu)方案有關(guān)。
-
如果是單機(jī)Prometheus,計(jì)算本地磁盤使用量。
-
如果是 Remote-Write,和已有的 Tsdb 共用即可。
-
如果是 Thanos 方案,本地磁盤可以忽略(2H),計(jì)算對(duì)象存儲(chǔ)的大小就行。
rate(prometheus_tsdb_compaction_chunk_samples_sum[1h]){instance="0.0.0.0:8890", job="prometheus"} 1.252747585939941 如果大致估算本地磁盤大小,可以通過以下公式:
只采集需要的指標(biāo),如 match[], 或者統(tǒng)計(jì)下最常使用的指標(biāo),性能最差的指標(biāo)。
以上磁盤容量并沒有把 wal 文件算進(jìn)去,wal 文件(Raw Data)在 Prometheus 官方文檔中說明至少會(huì)保存3個(gè) Write-Ahead Log Files,每一個(gè)最大為128M(實(shí)際運(yùn)行發(fā)現(xiàn)數(shù)量會(huì)更多)。
十四、對(duì) Apiserver 的性能影響
如果你的 Prometheus 使用了 kubernetes_sd_config 做服務(wù)發(fā)現(xiàn),請(qǐng)求一般會(huì)經(jīng)過集群的 Apiserver,隨著規(guī)模的變大,需要評(píng)估下對(duì) Apiserver性能的影響,尤其是Proxy失敗的時(shí)候,會(huì)導(dǎo)致CPU 升高。當(dāng)然了,如果單K8S集群規(guī)模太大,一般都是拆分集群,不過隨時(shí)監(jiān)測(cè)下 Apiserver 的進(jìn)程變化還是有必要的。
十五、Rate 的計(jì)算邏輯
Prometheus 中的 Counter 類型主要是為了 Rate 而存在的,即計(jì)算速率,單純的 Counter 計(jì)數(shù)意義不大,因?yàn)?Counter 一旦重置,總計(jì)數(shù)就沒有意義了。