<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Prometheus 避坑指南,建議收藏~

          共 19105字,需瀏覽 39分鐘

           ·

          2021-02-06 12:36

          Java技術棧

          www.javastack.cn

          關注閱讀更多優(yōu)質(zhì)文章



          作者:徐亞松

          來源:http://www.xuyasong.com/?p=1921


          監(jiān)控系統(tǒng)的歷史悠久,是一個很成熟的方向,而 Prometheus 作為新生代的開源監(jiān)控系統(tǒng),慢慢成為了云原生體系的事實標準,也證明了其設計很受歡迎。


          本文主要分享在 Prometheus 實踐中遇到的一些問題和思考,如果你對 K8S 監(jiān)控體系或 Prometheus 的設計還不太了解,可以先看下容器監(jiān)控系列。


          容器監(jiān)控系列:https://yasongxu.gitbook.io/container-monitor/


          幾點原則


          • 監(jiān)控是基礎設施,目的是為了解決問題,不要只朝著大而全去做,尤其是不必要的指標采集,浪費人力和存儲資源(To B商業(yè)產(chǎn)品例外)。

          • 需要處理的告警才發(fā)出來,發(fā)出來的告警必須得到處理。

          • 簡單的架構就是最好的架構,業(yè)務系統(tǒng)都掛了,監(jiān)控也不能掛。Google Sre 里面也說避免使用 Magic 系統(tǒng),例如機器學習報警閾值、自動修復之類。這一點見仁見智吧,感覺很多公司都在搞智能 AI 運維。


          Prometheus 的局限



          K8S 集群中常用的 exporter一級標題


          Prometheus 屬于 CNCF 項目,擁有完整的開源生態(tài),與 Zabbix 這種傳統(tǒng) agent 監(jiān)控不同,它提供了豐富的 exporter 來滿足你的各種需求。


          你可以在這里看到官方、非官方的 exporter。如果還是沒滿足你的需求,你還可以自己編寫 exporter,簡單方便、自由開放,這是優(yōu)點。


          Prometheus:https://prometheus.io/docs/instrumenting/exporters/


          但是過于開放就會帶來選型、試錯成本。之前只需要在 zabbix agent里面幾行配置就能完成的事,現(xiàn)在你會需要很多 exporter 搭配才能完成。還要對所有 exporter 維護、監(jiān)控。尤其是升級 exporter 版本時,很痛苦。非官方exporter 還會有不少 bug。這是使用上的不足,當然也是 Prometheus 的設計原則。


          K8S 生態(tài)的組件都會提供/metric接口以提供自監(jiān)控,這里列下我們正在使用的:


          • cadvisor: 集成在 Kubelet 中。

          • kubelet: 10255為非認證端口,10250為認證端口。

          • apiserver: 6443端口,關心請求數(shù)、延遲等。

          • scheduler: 10251端口。

          • controller-manager: 10252端口。

          • etcd: 如etcd 寫入讀取延遲、存儲容量等。

          • docker: 需要開啟 experimental 實驗特性,配置 metrics-addr,如容器創(chuàng)建耗時等指標。

          • kube-proxy: 默認 127 暴露,10249端口。外部采集時可以修改為 0.0.0.0 監(jiān)聽,會暴露:寫入 iptables 規(guī)則的耗時等指標。

          • kube-state-metrics: K8S 官方項目,采集pod、deployment等資源的元信息。

          • node-exporter: Prometheus 官方項目,采集機器指標如 CPU、內(nèi)存、磁盤。

          • blackbox_exporter: Prometheus 官方項目,網(wǎng)絡探測,dns、ping、http監(jiān)控

          • process-exporter: 采集進程指標

          • nvidia exporter: 我們有 gpu 任務,需要 gpu 數(shù)據(jù)監(jiān)控

          • node-problem-detector: 即 npd,準確的說不是 exporter,但也會監(jiān)測機器狀態(tài),上報節(jié)點異常打 taint

          • 應用層 exporter: mysql、nginx、mq等,看業(yè)務需求。


          cadvisor:http://www.xuyasong.com/?p=1483
          kube-state-metrics:http://www.xuyasong.com/?p=1525

          node-exporter:http://www.xuyasong.com/?p=1539


          還有各種場景下的自定義 exporter,如日志提取后面會再做介紹。


          自定義 exporter:http://www.xuyasong.com/?p=1942


          K8S 核心組件監(jiān)控與 Grafana 面板


          k8s 集群運行中需要關注核心組件的狀態(tài)、性能。如 kubelet、apiserver 等,基于上面提到的 exporter 的指標,可以在 Grafana 中繪制如下圖表:



          模板可以參考dashboards-for-kubernetes-administrators,根據(jù)運行情況不斷調(diào)整報警閾值。


          dashboards-for-kubernetes-administrators:https://povilasv.me/grafana-dashboards-for-kubernetes-administrators


          這里提一下 Grafana 雖然支持了 templates 能力,可以很方便地做多級下拉框選擇,但是不支持templates 模式下配置報警規(guī)則,相關issue


          issue:https://github.com/grafana/grafana/issues/9334


          官方對這個功能解釋了一堆,可最新版本仍然沒有支持。借用 issue 的一句話吐槽下:


          關于 Grafana 的基礎用法,可以看看《容器監(jiān)控實踐—Grafana》。


          容器監(jiān)控實踐—Grafana:http://www.xuyasong.com/?p=1693


          采集組件 All IN One


          Prometheus 體系中 Exporter 都是獨立的,每個組件各司其職,如機器資源用 Node-Exporter,Gpu 有Nvidia Exporter等等。但是 Exporter 越多,運維壓力越大,尤其是對 Agent做資源控制、版本升級。我們嘗試對一些Exporter進行組合,方案有二:


          • 通過主進程拉起N個 Exporter 進程,仍然可以跟著社區(qū)版本做更新、bug fix。

          • 用Telegraf來支持各種類型的 Input,N 合 1。


          另外,Node-Exporter 不支持進程監(jiān)控,可以加一個Process-Exporter,也可以用上邊提到的Telegraf,使用 procstat 的 input來采集進程指標。


          合理選擇黃金指標


          采集的指標有很多,我們應該關注哪些?Google 在“Sre Handbook”中提出了“四個黃金信號”:延遲、流量、錯誤數(shù)、飽和度。實際操作中可以使用 Use 或 Red 方法作為指導,Use 用于資源,Red 用于服務。


          • Use 方法:Utilization、Saturation、Errors。如 Cadvisor 數(shù)據(jù)

          • Red 方法:Rate、Errors、Duration。如 Apiserver 性能指標


          Prometheus 采集中常見的服務分三種:


          • 在線服務:如 Web 服務、數(shù)據(jù)庫等,一般關心請求速率,延遲和錯誤率即 RED 方法。

          • 離線服務:如日志處理、消息隊列等,一般關注隊列數(shù)量、進行中的數(shù)量,處理速度以及發(fā)生的錯誤即 Use 方法。

          • 批處理任務:和離線任務很像,但是離線任務是長期運行的,批處理任務是按計劃運行的,如持續(xù)集成就是批處理任務,對應 K8S 中的 job 或 cronjob, 一般關注所花的時間、錯誤數(shù)等,因為運行周期短,很可能還沒采集到就運行結束了,所以一般使用 Pushgateway,改拉為推。


          對 Use 和 Red 的實際示例可以參考容器監(jiān)控實踐—K8S常用指標分析這篇文章。


          容器監(jiān)控實踐—K8S常用指標分析:http://www.xuyasong.com/?P=1717


          K8S 1.16中 Cadvisor 的指標兼容問題


          在 K8S 1.16版本,Cadvisor 的指標去掉了 pod_Name 和 container_name 的 label,替換為了pod 和 container。如果你之前用這兩個 label 做查詢或者 Grafana 繪圖,需要更改下 Sql 了。因為我們一直支持多個 K8S 版本,就通過 relabel配置繼續(xù)保留了原來的**_name。



          注意要用 metric_relabel_configs,不是 relabel_configs,采集后做的replace。


          Prometheus采集外部K8S集群、多集群


          Prometheus 如果部署在K8S集群內(nèi)采集是很方便的,用官方給的Yaml就可以,但我們因為權限和網(wǎng)絡需要部署在集群外,二進制運行,采集多個 K8S 集群。


          以 Pod 方式運行在集群內(nèi)是不需要證書的(In-Cluster 模式),但集群外需要聲明 token之類的證書,并替換address,即使用 Apiserver Proxy采集,以 Cadvisor采集為例,Job 配置為:



          bearer_token_file 需要提前生成,這個參考官方文檔即可。記得 base64 解碼。


          對于 cadvisor 來說,__metrics_path__可以轉換為/api/v1/nodes/${1}/proxy/metrics/cadvisor,代表Apiserver proxy 到 Kubelet,如果網(wǎng)絡能通,其實也可以直接把 Kubelet 的10255作為 target,可以直接寫為:


          ${1}:10255/metrics/cadvisor,代表直接請求Kubelet,規(guī)模大的時候還減輕了 Apiserver 的壓力,即服務發(fā)現(xiàn)使用 Apiserver,采集不走 Apiserver。


          因為 cadvisor 是暴露主機端口,配置相對簡單,如果是 kube-state-metric 這種 Deployment,以 endpoint 形式暴露,寫法應該是:



          對于 endpoint 類型,需要轉換__metrics_path__為/api/v1/namespaces/${1}/services/${2}:${3}/proxy/metrics,需要替換 namespace、svc 名稱端口等,這里的寫法只適合接口為/metrics的exporter,如果你的 exporter 不是/metrics接口,需要替換這個路徑。或者像我們一樣統(tǒng)一約束都使用這個地址。


          這里的__meta_kubernetes_service_annotation_prometheus_io_port來源就是 exporter 部署時寫的那個 annotation,大多數(shù)文章中只提到prometheus.io/scrape: 'true',但也可以定義端口、路徑、協(xié)議。以方便在采集時做替換處理。


          其他的一些 relabel 如kubernetes_namespace 是為了保留原始信息,方便做 promql 查詢時的篩選條件。


          如果是多集群,同樣的配置多寫幾遍就可以了,一般一個集群可以配置三類job:


          • role:node 的,包括 cadvisor、 node-exporter、kubelet 的 summary、kube-proxy、docker 等指標。

          • role:endpoint 的,包括 kube-state-metric 以及其他自定義 Exporter。

          • 普通采集:包括Etcd、Apiserver 性能指標、進程指標等。


          GPU 指標的獲取


          nvidia-smi可以查看機器上的 GPU 資源,而Cadvisor 其實暴露了Metric來表示容器使用 GPU 情況,



          如果要更詳細的 GPU 數(shù)據(jù),可以安裝dcgm exporter,不過K8S 1.13 才能支持。


          更改 Prometheus 的顯示時區(qū)


          Prometheus 為避免時區(qū)混亂,在所有組件中專門使用 Unix Time 和 Utc 進行顯示。不支持在配置文件中設置時區(qū),也不能讀取本機 /etc/timezone 時區(qū)。


          其實這個限制是不影響使用的:


          • 如果做可視化,Grafana是可以做時區(qū)轉換的。

          • 如果是調(diào)接口,拿到了數(shù)據(jù)中的時間戳,你想怎么處理都可以。

          • 如果因為 Prometheus 自帶的 UI 不是本地時間,看著不舒服,2.16 版本的新版 Web UI已經(jīng)引入了Local Timezone 的選項,區(qū)別見下圖。

          • 如果你仍然想改 Prometheus 代碼來適應自己的時區(qū),可以參考《修改源碼更改prometheus的時區(qū)問題》。


          2.16 版本:

          https://github.com/prometheus/prometheus/commit/d996ba20ec9c7f1808823a047ed9d5ce96be3d8f

          修改源碼更改prometheus的時區(qū)問題:

          https://zhangguanzhang.github.io/2019/09/05/prometheus-change-timezone/



          關于 timezone 的討論,可以看這個issue。


          issue:https://github.com/prometheus/prometheus/issues/500


          如何采集 LB 后面的 RS 的 Metric


          假如你有一個負載均衡 LB,但網(wǎng)絡上 Prometheus 只能訪問到 LB 本身,訪問不到后面的 RS,應該如何采集 RS 暴露的 Metric?


          • RS 的服務加 Sidecar Proxy,或者本機增加 Proxy 組件,保證 Prometheus 能訪問到。

          • LB 增加 /backend1 和 /backend2請求轉發(fā)到兩個單獨的后端,再由 Prometheus 訪問 LB 采集。


          版本的選擇


          Prometheus 當前最新版本為 2.16,Prometheus 還在不斷迭代,因此盡量用最新版,1.X版本就不用考慮了。


          2.16 版本上有一套實驗 UI,可以查看 TSDB 的狀態(tài),包括Top 10的 Label、Metric。



          Prometheus 大內(nèi)存問題


          隨著規(guī)模變大,Prometheus 需要的 CPU 和內(nèi)存都會升高,內(nèi)存一般先達到瓶頸,這個時候要么加內(nèi)存,要么集群分片減少單機指標。這里我們先討論單機版 Prometheus 的內(nèi)存問題。


          原因:


          • Prometheus 的內(nèi)存消耗主要是因為每隔2小時做一個 Block 數(shù)據(jù)落盤,落盤之前所有數(shù)據(jù)都在內(nèi)存里面,因此和采集量有關。

          • 加載歷史數(shù)據(jù)時,是從磁盤到內(nèi)存的,查詢范圍越大,內(nèi)存越大。這里面有一定的優(yōu)化空間。

          • 一些不合理的查詢條件也會加大內(nèi)存,如 Group 或大范圍 Rate。


          我的指標需要多少內(nèi)存:


          • 作者給了一個計算器,設置指標量、采集間隔之類的,計算 Prometheus 需要的理論內(nèi)存值:計算公式。


          計算公式:https://www.robustperception.io/how-much-ram-does-prometheus-2-x-need-for-cardinality-and-ingestion


          以我們的一個 Prometheus Server為例,本地只保留 2 小時數(shù)據(jù),95 萬 Series,大概占用的內(nèi)存如下:



          有什么優(yōu)化方案:


          • Sample 數(shù)量超過了 200 萬,就不要單實例了,做下分片,然后通過 Victoriametrics,Thanos,Trickster 等方案合并數(shù)據(jù)。

          • 評估哪些 Metric 和 Label 占用較多,去掉沒用的指標。2.14 以上可以看 Tsdb 狀態(tài)。

          • 查詢時盡量避免大范圍查詢,注意時間范圍和 Step 的比例,慎用 Group。

          • 如果需要關聯(lián)查詢,先想想能不能通過 Relabel 的方式給原始數(shù)據(jù)多加個 Label,一條Sql 能查出來的何必用Join,時序數(shù)據(jù)庫不是關系數(shù)據(jù)庫。


          Prometheus 內(nèi)存占用分析:


          • 通過 pprof分析:https://www.robustperception.io/optimising-prometheus-2-6-0-memory-usage-with-pprof

          • 1.X 版本的內(nèi)存:https://www.robustperception.io/how-much-ram-does-my-prometheus-need-for-ingestion


          相關 issue:


          • https://groups.google.com/forum/#!searchin/prometheus-users/memory%7Csort:date/prometheus-users/q4oiVGU6Bxo/uifpXVw3CwAJ

          • https://github.com/prometheus/prometheus/issues/5723

          • https://github.com/prometheus/prometheus/issues/1881


          Prometheus 容量規(guī)劃


          容量規(guī)劃除了上邊說的內(nèi)存,還有磁盤存儲規(guī)劃,這和你的 Prometheus 的架構方案有關。


          • 如果是單機Prometheus,計算本地磁盤使用量。

          • 如果是 Remote-Write,和已有的 Tsdb 共用即可。

          • 如果是 Thanos 方案,本地磁盤可以忽略(2H),計算對象存儲的大小就行。


          Prometheus 每2小時將已緩沖在內(nèi)存中的數(shù)據(jù)壓縮到磁盤上的塊中。包括Chunks、Indexes、Tombstones、Metadata,這些占用了一部分存儲空間。一般情況下,Prometheus中存儲的每一個樣本大概占用1-2字節(jié)大小(1.7Byte)。可以通過Promql來查看每個樣本平均占用多少空間:



          rate(prometheus_tsdb_compaction_chunk_size_bytes_sum[1h])

          /

          rate(prometheus_tsdb_compaction_chunk_samples_sum[1h]){instance="0.0.0.0:8890", job="prometheus"}

          1.252747585939941


          如果大致估算本地磁盤大小,可以通過以下公式:



          保留時間(retention_time_seconds)和樣本大小(bytes_per_sample)不變的情況下,如果想減少本地磁盤的容量需求,只能通過減少每秒獲取樣本數(shù)(ingested_samples_per_second)的方式。


          查看當前每秒獲取的樣本數(shù):



          有兩種手段,一是減少時間序列的數(shù)量,二是增加采集樣本的時間間隔。考慮到 Prometheus 會對時間序列進行壓縮,因此減少時間序列的數(shù)量效果更明顯。


          舉例說明:


          • 采集頻率 30s,機器數(shù)量1000,Metric種類6000,1000600026024 約 200 億,30G 左右磁盤。

          • 只采集需要的指標,如 match[], 或者統(tǒng)計下最常使用的指標,性能最差的指標。


          以上磁盤容量并沒有把 wal 文件算進去,wal 文件(Raw Data)在 Prometheus 官方文檔中說明至少會保存3個 Write-Ahead Log Files,每一個最大為128M(實際運行發(fā)現(xiàn)數(shù)量會更多)。


          因為我們使用了 Thanos 的方案,所以本地磁盤只保留2H 熱數(shù)據(jù)。Wal 每2小時生成一份Block文件,Block文件每2小時上傳對象存儲,本地磁盤基本沒有壓力。

          關于 Prometheus 存儲機制,可以看《容器監(jiān)控實踐—Prometheus存儲機制》。


          容器監(jiān)控實踐—Prometheus存儲機制:http://www.xuyasong.com/?p=1601


          對 Apiserver 的性能影響


          如果你的 Prometheus 使用了 kubernetes_sd_config 做服務發(fā)現(xiàn),請求一般會經(jīng)過集群的 Apiserver,隨著規(guī)模的變大,需要評估下對 Apiserver性能的影響,尤其是Proxy失敗的時候,會導致CPU 升高。當然了,如果單K8S集群規(guī)模太大,一般都是拆分集群,不過隨時監(jiān)測下 Apiserver 的進程變化還是有必要的。


          在監(jiān)控Cadvisor、Docker、Kube-Proxy 的 Metric 時,我們一開始選擇從 Apiserver Proxy 到節(jié)點的對應端口,統(tǒng)一設置比較方便,但后來還是改為了直接拉取節(jié)點,Apiserver 僅做服務發(fā)現(xiàn)。


          Rate 的計算邏輯


          Prometheus 中的 Counter 類型主要是為了 Rate 而存在的,即計算速率,單純的 Counter 計數(shù)意義不大,因為 Counter 一旦重置,總計數(shù)就沒有意義了。


          Rate 會自動處理 Counter 重置的問題,Counter 一般都是一直變大的,例如一個 Exporter 啟動,然后崩潰了。本來以每秒大約10的速率遞增,但僅運行了半個小時,則速率(x_total [1h])將返回大約每秒5的結果。另外,Counter 的任何減少也會被視為 Counter 重置。例如,如果時間序列的值為[5,10,4,6],則將其視為[5,10,14,16]。


          Rate 值很少是精確的。由于針對不同目標的抓取發(fā)生在不同的時間,因此隨著時間的流逝會發(fā)生抖動,query_range 計算時很少會與抓取時間完美匹配,并且抓取有可能失敗。面對這樣的挑戰(zhàn),Rate 的設計必須是健壯的。


          Rate 并非想要捕獲每個增量,因為有時候增量會丟失,例如實例在抓取間隔中掛掉。如果 Counter 的變化速度很慢,例如每小時僅增加幾次,則可能會導致【假象】。比如出現(xiàn)一個 Counter 時間序列,值為100,Rate 就不知道這些增量是現(xiàn)在的值,還是目標已經(jīng)運行了好幾年并且才剛剛開始返回。


          建議將 Rate 計算的范圍向量的時間至少設為抓取間隔的四倍。這將確保即使抓取速度緩慢,且發(fā)生了一次抓取故障,您也始終可以使用兩個樣本。此類問題在實踐中經(jīng)常出現(xiàn),因此保持這種彈性非常重要。例如,對于1分鐘的抓取間隔,您可以使用4分鐘的 Rate 計算,但是通常將其四舍五入為5分鐘。


          如果 Rate 的時間區(qū)間內(nèi)有數(shù)據(jù)缺失,他會基于趨勢進行推測,比如:



          反直覺的 P95 統(tǒng)計


          histogram_quantile 是 Prometheus 常用的一個函數(shù),比如經(jīng)常把某個服務的 P95 響應時間來衡量服務質(zhì)量。不過它到底是什么意思很難解釋得清,特別是面向非技術的同學,會遇到很多“靈魂拷問”。


          我們常說 P95(P99,P90都可以) 響應延遲是 100ms,實際上是指對于收集到的所有響應延遲,有 5% 的請求大于 100ms,95% 的請求小于 100ms。Prometheus 里面的 histogram_quantile 函數(shù)接收的是 0-1 之間的小數(shù),將這個小數(shù)乘以 100 就能很容易得到對應的百分位數(shù),比如 0.95 就對應著 P95,而且還可以高于百分位數(shù)的精度,比如 0.9999。


          當你用 histogram_quantile 畫出響應時間的趨勢圖時,可能會被問:為什么P95大于或小于我的平均值?


          正如中位數(shù)可能比平均數(shù)大也可能比平均數(shù)小,P99 比平均值小也是完全有可能的。通常情況下 P99 幾乎總是比平均值要大的,但是如果數(shù)據(jù)分布比較極端,最大的 1% 可能大得離譜從而拉高了平均值。一種可能的例子:



          服務 X 由順序的 A,B 兩個步驟完成,其中 X 的 P99 耗時 100Ms,A 過程 P99 耗時 50Ms,那么推測 B 過程的 P99 耗時情況是?


          直覺上來看,因為有 X=A+B,所以答案可能是 50Ms,或者至少應該要小于 50Ms。實際上 B 是可以大于 50Ms 的,只要 A 和 B 最大的 1% 不恰好遇到,B 完全可以有很大的 P99:



          所以我們從題目唯一能確定的只有 B 的 P99 應該不能超過 100ms,A 的 P99 耗時 50Ms 這個條件其實沒啥用。


          類似的疑問很多,因此對于 histogram_quantile 函數(shù),可能會產(chǎn)生反直覺的一些結果,最好的處理辦法是不斷試驗調(diào)整你的 Bucket 的值,保證更多的請求時間落在更細致的區(qū)間內(nèi),這樣的請求時間才有統(tǒng)計意義。


          慢查詢問題


          Prometheus 提供了自定義的 Promql 作為查詢語句,在 Graph 上調(diào)試的時候,會告訴你這條 Sql 的返回時間,如果太慢你就要注意了,可能是你的用法出現(xiàn)了問題。


          慢查詢:http://www.xuyasong.com/?p=1578


          評估 Prometheus 的整體響應時間,可以用這個默認指標:



          一般情況下響應過慢都是Promql 使用不當導致,或者指標規(guī)劃有問題,如:


          • 大量使用 join 來組合指標或者增加 label,如將 kube-state-metric 中的一些 meta label和 node-exporter 中的節(jié)點屬性 label加入到 cadvisor容器數(shù)據(jù)里,像統(tǒng)計 pod 內(nèi)存使用率并按照所屬節(jié)點的機器類型分類,或按照所屬 rs 歸類。

          • 范圍查詢時,大的時間范圍 step 值卻很小,導致查詢到的數(shù)量過大。

          • rate 會自動處理 counter 重置的問題,最好由 promql 完成,不要自己拿出來全部元數(shù)據(jù)在程序中自己做 rate 計算。

          • 在使用 rate 時,range duration要大于等于step,否則會丟失部分數(shù)據(jù)

          • prometheus 是有基本預測功能的,如deriv和predict_linear(更準確)可以根據(jù)已有數(shù)據(jù)預測未來趨勢

          • 如果比較復雜且耗時的sql,可以使用 record rule 減少指標數(shù)量,并使查詢效率更高,但不要什么指標都加 record,一半以上的 metric 其實不太會查詢到。同時 label 中的值不要加到 record rule 的 name 中。


          step:https://www.robustperception.io/step-and-query_range

          部分數(shù)據(jù):https://chanjarster.github.io/post/p8s-step-param/


          高基數(shù)問題 Cardinality


          高基數(shù)是數(shù)據(jù)庫避不開的一個話題,對于 Mysql 這種 DB 來講,基數(shù)是指特定列或字段中包含的唯一值的數(shù)量。基數(shù)越低,列中重復的元素越多。對于時序數(shù)據(jù)庫而言,就是 tags、label 這種標簽值的數(shù)量多少。


          比如 Prometheus 中如果有一個指標 http_request_count{method="get",path="/abc",originIP="1.1.1.1"}表示訪問量,method 表示請求方法,originIP 是客戶端 IP,method的枚舉值是有限的,但 originIP 卻是無限的,加上其他 label 的排列組合就無窮大了,也沒有任何關聯(lián)特征,因此這種高基數(shù)不適合作為 Metric 的 label,真要的提取originIP,應該用日志的方式,而不是 Metric 監(jiān)控。


          時序數(shù)據(jù)庫會為這些 Label 建立索引,以提高查詢性能,以便您可以快速找到與所有指定標簽匹配的值。如果值的數(shù)量過多,索引是沒有意義的,尤其是做 P95 等計算的時候,要掃描大量 Series 數(shù)據(jù)。


          官方文檔中對于Label 的建議



          如何查看當前的Label 分布情況呢,可以使用 Prometheus提供的Tsdb工具。可以使用命令行查看,也可以在 2.16 版本以上的 Prometheus Graph 查看




          top10 高基數(shù)的 metric



          高基數(shù)的 label



          找到最大的 metric 或 job


          top10的 metric 數(shù)量:按 metric 名字分



          top10的 metric 數(shù)量:按 job 名字分



          Prometheus 重啟慢與熱加載


          Prometheus 重啟的時候需要把 Wal 中的內(nèi)容 Load 到內(nèi)存里,保留時間越久、Wal 文件越大,重啟的實際越長,這個是 Prometheus 的機制,沒得辦法,因此能 Reload 的就不要重啟,重啟一定會導致短時間的不可用,而這個時候Prometheus高可用就很重要了。


          Prometheus 也曾經(jīng)對啟動時間做過優(yōu)化,在 2.6 版本中對于Wal的 Load 速度就做過速度的優(yōu)化,希望重啟的時間不超過 1 分鐘。


          1分鐘:https://www.robustperception.io/optimising-startup-time-of-prometheus-2-6-0-with-pprof


          Prometheus 提供了熱加載能力,不過需要開啟web.enable-lifecycle配置,更改完配置后,curl 下 reload 接口即可。prometheus-operator 中更改了配置會默認觸發(fā) reload,如果你沒有使用operator,又希望可以監(jiān)聽 configmap 配置變化來 reload 服務,可以試下這個簡單的腳本。



          使用時和 prometheus 掛載同一個 configmap,傳入如下參數(shù)即可:



          你的應用需要暴露多少指標


          當你開發(fā)自己的服務的時候,你可能會把一些數(shù)據(jù)暴露 Metric出去,比如特定請求數(shù)、Goroutine 數(shù)等,指標數(shù)量多少合適呢?


          雖然指標數(shù)量和你的應用規(guī)模相關,但也有一些建議(Brian Brazil),比如簡單的服務如緩存等,類似 Pushgateway,大約 120 個指標,Prometheus 本身暴露了 700 左右的指標,如果你的應用很大,也盡量不要超過 10000 個指標,需要合理控制你的 Label。


          建議(Brian Brazil):https://www.robustperception.io/how-many-metrics-should-an-application-return


          node-exporter 的問題


          • node-exporter 不支持進程監(jiān)控,這個前面已經(jīng)提到了。

          • node-exporter 只支持 unix 系統(tǒng),windows機器 請使用 wmi_exporter。因此以 yaml 形式不是 node-exporter 的時候,node-selector 要表明os類型。

          • 因為node_exporter是比較老的組件,有一些最佳實踐并沒有merge進去,比如符合Prometheus命名規(guī)范,因此建議使用較新的0.16和0.17版本。


          命名規(guī)范:https://prometheus.io/docs/practices/naming/


          一些指標名字的變化:



          如果你之前用的舊版本 exporter,在繪制 grafana 的時候指標名稱就會有差別,解決方法有兩種:


          • 一是在機器上啟動兩個版本的node-exporter,都讓prometheus去采集。

          • 二是使用指標轉換器,他會將舊指標名稱轉換為新指標


          指標轉換器:https://github.com/prometheus/node_exporter/blob/master/docs/example-16-compatibility-rules.yml


          kube-state-metric 的問題


          除了文章中提到的作用,kube-state-metric還有一個很重要的使用場景,就是和 cadvisor 指標組合,原始的 cadvisor 中只有 pod 信息,不知道屬于哪個 deployment 或者 sts,但是和kube-state-metric 中的 kube_pod_info 做 join 查詢之后就可以顯示出來,kube-state-metric的元數(shù)據(jù)指標,在擴展 cadvisor 的 label 中起到了很多作用,prometheus-operator 的很多 record rule 就使用了 kube-state-metric 做組合查詢。


          容器監(jiān)控實踐—kube-state-metrics:http://www.xuyasong.com/?p=1525


          kube-state-metric 中也可以展示 pod 的 label 信息,可以在拿到 cadvisor 數(shù)據(jù)后更方便地做 group by,如按照 pod 的運行環(huán)境分類。但是 kube-state-metric 不暴露 pod 的 annotation,原因是下面會提到的高基數(shù)問題,即 annotation 的內(nèi)容太多,不適合作為指標暴露。


          relabel_configs


          relabel_configs 與 metric_relabel_configs


          relabel_config 發(fā)生在采集之前,metric_relabel_configs 發(fā)生在采集之后,合理搭配可以滿足很多場景的配置。


          如:



          Prometheus 的預測能力


          場景1:你的磁盤剩余空間一直在減少,并且降低的速度比較均勻,你希望知道大概多久之后達到閾值,并希望在某一個時刻報警出來。


          場景2:你的 Pod 內(nèi)存使用率一直升高,你希望知道大概多久之后會到達 Limit 值,并在一定時刻報警出來,在被殺掉之前上去排查。


          Prometheus 的 Deriv 和 Predict_Linear 方法可以滿足這類需求, Promtheus 提供了基礎的預測能力,基于當前的變化速度,推測一段時間后的值。


          以 mem_free 為例,最近一小時的 free 值一直在下降。



          deriv函數(shù)可以顯示指標在一段時間的變化速度:



          predict_linear方法是預測基于這種速度,最后可以達到的值:



          你可以基于設置合理的報警規(guī)則,如小于 10 時報警:



          predict_linear 與 deriv 的關系: 含義上約等于如下表達式,不過 predict_linear 稍微準確一些。



          如果你要基于 Metric做模型預測,可以參考下forecast-prometheus。


          forecast-prometheus:https://github.com/nfrumkin/forecast-prometheus


          alertmanager 的上層封裝


          Prometheus 部署之后很少會改動,尤其是做了服務發(fā)現(xiàn),就不需要頻繁新增 target。但報警的配置是很頻繁的,如修改閾值、修改報警人等。alertmanager 擁有豐富的報警能力如分組、抑制等,但如果你要想把他給業(yè)務部門使用,就要做一層封裝了,也就是報警配置臺。用戶喜歡表單操作,而非晦澀的 yaml,同時他們也并不愿意去理解 promql。而且大多數(shù)公司內(nèi)已經(jīng)有現(xiàn)成的監(jiān)控平臺,也只有一份短信或郵件網(wǎng)關,所以最好能使用 webhook 直接集成。


          例如: 機器磁盤使用量超過 90% 就報警,rule 應該寫為:disk_used/disk_total > 0.9


          如果不加 label 篩選,這條報警會對所有機器生效,但如果你想去掉其中幾臺機器,就得在disk_used和disk_total后面加上{instance != “”}。這些操作在 promql 中是很簡單的,但是如果放在表單里操作,就得和內(nèi)部的 cmdb 做聯(lián)動篩選了。




          • 使用 webhook 擴展報警能力,改造 alertmanager, 在 send message 時做加密和認證,對接內(nèi)部已有報警能力,并聯(lián)動用戶體系,做限流和權限控制。

          • 調(diào)用 alertmanager api 查詢報警事件,進行展示和統(tǒng)計。


          對于用戶來說,封裝 alertmanager yaml 會變的易用,但也會限制其能力,在增加報警配置時,研發(fā)和運維需要有一定的配合。如新寫了一份自定義的 exporter,要將需要的指標供用戶選擇,并調(diào)整好展示和報警用的 promql。還有報警模板、原生 promql 暴露、用戶分組等,需要視用戶需求做權衡。


          錯誤的高可用設計


          有些人提出過這種類型的方案,想提高其擴展性和可用性。



          應用程序?qū)?Metric 推到到消息隊列如 Kafaka,然后經(jīng)過 Exposer 消費中轉,再被 Prometheus 拉取。產(chǎn)生這種方案的原因一般是有歷史包袱、復用現(xiàn)有組件、想通過 Mq 來提高擴展性。


          這種方案有幾個問題:


          • 增加了 Queue 組件,多了一層依賴,如果 App與 Queue 之間連接失敗,難道要在 App 本地緩存監(jiān)控數(shù)據(jù)?

          • 抓取時間可能會不同步,延遲的數(shù)據(jù)將會被標記為陳舊數(shù)據(jù),當然你可以通過添加時間戳來標識,但就失去了對陳舊數(shù)據(jù)的處理邏輯。

          • 擴展性問題:Prometheus 適合大量小目標,而不是一個大目標,如果你把所有數(shù)據(jù)都放在了 Exposer 中,那么 Prometheus 的單個 Job 拉取就會成為 CPU 瓶頸。這個和 Pushgateway 有些類似,沒有特別必要的場景,都不是官方建議的方式。

          • 缺少了服務發(fā)現(xiàn)和拉取控制,Prom 只知道一個 Exposer,不知道具體是哪些 Target,不知道他們的 UP 時間,無法使用 Scrape_* 等指標做查詢,也無法用scrape_limit做限制。


          處理邏輯:https://www.robustperception.io/staleness-and-promql

          scrape_limit:https://www.robustperception.io/using-sample_limit-to-avoid-overload


          如果你的架構和 Prometheus 的設計理念相悖,可能要重新設計一下方案了,否則擴展性和可靠性反而會降低。


          prometheus-operator 的場景


          如果你是在 K8S 集群內(nèi)部署 Prometheus,那大概率會用到 prometheus-operator,他對 Prometheus 的配置做了 CRD 封裝,讓用戶更方便的擴展 Prometheus實例,同時 prometheus-operator 還提供了豐富的 Grafana 模板,包括上面提到的 master 組件監(jiān)控的 Grafana 視圖,operator 啟動之后就可以直接使用,免去了配置面板的煩惱。


          operator 的優(yōu)點很多,就不一一列舉了,只提一下 operator 的局限:


          • 因為是 operator,所以依賴 K8S 集群,如果你需要二進制部署你的 Prometheus,如集群外部署,就很難用上prometheus-operator了,如多集群場景。當然你也可以在 K8S 集群中部署 operator 去監(jiān)控其他的 K8S 集群,但這里面坑不少,需要修改一些配置。

          • operator 屏蔽了太多細節(jié),這個對用戶是好事,但對于理解 Prometheus 架構就有些 gap 了,比如碰到一些用戶一鍵安裝了operator,但 Grafana 圖表異常后完全不知道如何排查,record rule 和 服務發(fā)現(xiàn)還不了解的情況下就直接配置,建議在使用 operator 之前,最好熟悉 prometheus 的基礎用法。

          • operator 方便了 Prometheus 的擴展和配置,對于 alertmanager 和 exporter 可以很方便的做到多實例高可用,但是沒有解決 Prometheus 的高可用問題,因為無法處理數(shù)據(jù)不一致,operator目前的定位也還不是這個方向,和 Thanos、Cortex 等方案的定位是不同的,下面會詳細解釋。


          高可用方案


          Prometheus 高可用有幾種方案:


          • 基本 HA:即兩套 Prometheus 采集完全一樣的數(shù)據(jù),外邊掛負載均衡

          • HA + 遠程存儲:除了基礎的多副本 Prometheus,還通過 Remote Write 寫入到遠程存儲,解決存儲持久化問題

          • 聯(lián)邦集群:即 Federation,按照功能進行分區(qū),不同的 Shard 采集不同的數(shù)據(jù),由Global節(jié)點來統(tǒng)一存放,解決監(jiān)控數(shù)據(jù)規(guī)模的問題。

          • 使用 Thanos 或者 Victoriametrics,來解決全局查詢、多副本數(shù)據(jù) Join 問題。


          就算使用官方建議的多副本 + 聯(lián)邦,仍然會遇到一些問題:


          • 官方建議數(shù)據(jù)做 Shard,然后通過Federation來實現(xiàn)高可用,

          • 但是邊緣節(jié)點和Global節(jié)點依然是單點,需要自行決定是否每一層都要使用雙節(jié)點重復采集進行保活。也就是仍然會有單機瓶頸。

          • 另外部分敏感報警盡量不要通過Global節(jié)點觸發(fā),畢竟從Shard節(jié)點到Global節(jié)點傳輸鏈路的穩(wěn)定性會影響數(shù)據(jù)到達的效率,進而導致報警實效降低。

          • 例如服務Updown狀態(tài),Api請求異常這類報警我們都放在Shard節(jié)點進行報警。


          本質(zhì)原因是,Prometheus 的本地存儲沒有數(shù)據(jù)同步能力,要在保證可用性的前提下,再保持數(shù)據(jù)一致性是比較困難的,基礎的 HA Proxy 滿足不了要求,比如:


          • 集群的后端有 A 和 B 兩個實例,A 和 B 之間沒有數(shù)據(jù)同步。A 宕機一段時間,丟失了一部分數(shù)據(jù),如果負載均衡正常輪詢,請求打到A 上時,數(shù)據(jù)就會異常。

          • 如果 A 和 B 的啟動時間不同,時鐘不同,那么采集同樣的數(shù)據(jù)時間戳也不同,就不是多副本同樣數(shù)據(jù)的概念了

          • 就算用了遠程存儲,A 和 B 不能推送到同一個 TSDB,如果每人推送自己的 TSDB,數(shù)據(jù)查詢走哪邊就是問題了。


          因此解決方案是在存儲、查詢兩個角度上保證數(shù)據(jù)的一致:


          • 存儲角度:如果使用 Remote Write 遠程存儲, A 和 B后面可以都加一個 Adapter,Adapter做選主邏輯,只有一份數(shù)據(jù)能推送到 TSDB,這樣可以保證一個異常,另一個也能推送成功,數(shù)據(jù)不丟,同時遠程存儲只有一份,是共享數(shù)據(jù)。

          • 查詢角度:上邊的方案實現(xiàn)很復雜且有一定風險,因此現(xiàn)在的大多數(shù)方案在查詢層面做文章,比如 Thanos 或者 Victoriametrics,仍然是兩份數(shù)據(jù),但是查詢時做數(shù)據(jù)去重和 Join。只是 Thanos 是通過 Sidecar 把數(shù)據(jù)放在對象存儲,Victoriametrics 是把數(shù)據(jù) Remote Write 到自己的 Server 實例,但查詢層 Thanos-Query 和 Victor 的 Promxy的邏輯基本一致。


          存儲方案:https://blog.timescale.com/blog/prometheus-ha-postgresql-8de68d19b6f5/


          我們采用了 Thanos 來支持多地域監(jiān)控數(shù)據(jù)。


          高可用 Prometheus:Thanos 實踐:

          http://www.xuyasong.com/?p=1925


          容器日志與事件


          本文主要是 Prometheus 監(jiān)控內(nèi)容, 這里只簡單介紹下 K8S 中的日志、事件處理方案,以及和 Prometheus 的搭配。


          日志處理:


          • 日志采集與推送:一般是Fluentd/Fluent-Bit/Filebeat等采集推送到 ES、對象存儲、kafaka,日志就該交給專業(yè)的 EFK 來做,分為容器標準輸出、容器內(nèi)日志。

          • 日志解析轉 metric:可以提取一些日志轉為 Prometheus 格式的指標,如解析特定字符串出現(xiàn)次數(shù),解析 Nginx 日志得到 QPS 、請求延遲等。常用方案是 mtail 或者 grok


          日志采集方案:


          • sidecar 方式:和業(yè)務容器共享日志目錄,由 sidecar 完成日志推送,一般用于多租戶場景。

          • daemonset 方式:機器上運行采集進程,統(tǒng)一推送出去。


          需要注意的點:對于容器標準輸出,默認日志路徑是/var/lib/docker/containers/xxx, kubelet 會將改日志軟鏈到/var/log/pods,同時還有一份/var/log/containers 是對/var/log/pods的軟鏈。不過不同的 K8S 版本,日志的目錄格式有所變化,采集時根據(jù)版本做區(qū)分:


          • 1.15 及以下:/var/log/pods/{pod_uid}/

          • 1.15 以上:var/log/pods/{pod_name+namespace+rs+uuid}/


          事件:在這里特指 K8S Events,Events 在排查集群問題時也很關鍵,不過默認情況下只保留 1h,因此需要對 Events 做持久化。一般 Events 處理方式有兩種:


          • 使用 kube-eventer 之類的組件采集 Events 并推送到 ES

          • 使用 event_exporter 之類的組件將Events 轉化為 Prometheus Metric,同類型的還有谷歌云的 stackdriver 下的 event-exporter


          kube-eventer :https://github.com/AliyunContainerService/kube-eventer

          event_exporter:https://github.com/caicloud/event_exporter

          event-exporter:https://github.com/GoogleCloudPlatform/k8s-stackdriver/tree/master/event-exporter







          關注Java技術棧看更多干貨



          戳原文,獲取精選面試題!
          瀏覽 66
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99精产18在线观看 | 草比网址 | 我爱大香蕉欧美高清无 | 狂野欧美性爱 | 一级黄色视频免费看 |