做者:徐亚松 原文:http://www.xuyasong.com/?p=1921
监控系统的历史悠久,是一个很成熟的方向,而 Prometheus 做为新生代的开源监控系统,慢慢成为了云原生体系的事实标准,也证实了其设计很受欢迎。node
本文主要分享在 Prometheus 实践中遇到的一些问题和思考,若是你对 K8S 监控体系或 Prometheus 的设计还不太了解,能够先看下容器监控系列。mysql
几点原则:nginx
Prometheus 当前最新版本为 2.16,Prometheus 还在不断迭代,所以尽可能用最新版,1.X版本就不用考虑了。git
2.16 版本上有一套实验 UI,能够查看 TSDB 的状态,包括Top 10的 Label、Metric.github
Prometheus 属于 CNCF 项目,拥有完整的开源生态,与 Zabbix 这种传统 agent 监控不一样,它提供了丰富的 exporter 来知足你的各类需求。你能够在这里看到官方、非官方的 exporter。若是仍是没知足你的需求,你还能够本身编写 exporter,简单方便、自由开放,这是优势。sql
可是过于开放就会带来选型、试错成本。以前只须要在 zabbix agent里面几行配置就能完成的事,如今你会须要不少 exporter 搭配才能完成。还要对全部 exporter 维护、监控。尤为是升级 exporter 版本时,很痛苦。非官方exporter 还会有很多 bug。这是使用上的不足,固然也是 Prometheus 的设计原则。docker
K8S 生态的组件都会提供/metric接口以提供自监控,这里列下咱们正在使用的:数据库
还有各类场景下的自定义 exporter,如日志提取后面会再作介绍。segmentfault
k8s 集群运行中须要关注核心组件的状态、性能。如 kubelet、apiserver 等,基于上面提到的 exporter 的指标,能够在 Grafana 中绘制以下图表:后端
模板能够参考dashboards-for-kubernetes-administrators,根据运行状况不断调整报警阈值。
这里提一下 Grafana 虽然支持了 templates 能力,能够很方便地作多级下拉框选择,可是不支持templates 模式下配置报警规则,相关issue
官方对这个功能解释了一堆,可最新版本仍然没有支持。借用 issue 的一句话吐槽下:
It would be grate to add templates support in alerts. Otherwise the feature looks useless a bit.
Prometheus 体系中 Exporter 都是独立的,每一个组件各司其职,如机器资源用 Node-Exporter,Gpu 有Nvidia Exporter等等。可是 Exporter 越多,运维压力越大,尤为是对 Agent作资源控制、版本升级。咱们尝试对一些Exporter进行组合,方案有二:
另外,Node-Exporter 不支持进程监控,能够加一个Process-Exporter,也能够用上边提到的Telegraf,使用 procstat 的 input来采集进程指标。
采集的指标有不少,咱们应该关注哪些?Google 在“Sre Handbook”中提出了“四个黄金信号”:延迟、流量、错误数、饱和度。实际操做中可使用 Use 或 Red 方法做为指导,Use 用于资源,Red 用于服务。
Prometheus 采集中常见的服务分三种:
对 Use 和 Red 的实际示例能够参考容器监控实践—K8S经常使用指标分析这篇文章。
在 K8S 1.16版本,Cadvisor 的指标去掉了 pod_Name 和 container_name 的 label,替换为了pod 和 container。若是你以前用这两个 label 作查询或者 Grafana 绘图,须要更改下 Sql 了。由于咱们一直支持多个 K8S 版本,就经过 relabel配置继续保留了原来的**_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集群内采集是很方便的,用官方给的Yaml就能够,但咱们由于权限和网络须要部署在集群外,二进制运行,采集多个 K8S 集群。
以 Pod 方式运行在集群内是不须要证书的(In-Cluster 模式),但集群外须要声明 token之类的证书,并替换address,即便用 Apiserver Proxy采集,以 Cadvisor采集为例,Job 配置为:
- job_name: cluster-cadvisor 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 须要提早生成,这个参考官方文档便可。记得 base64 解码。
对于 cadvisor 来讲,__metrics_path__
能够转换为/api/v1/nodes/{1}/proxy/metrics/cadvisor
,表明Apiserver proxy 到 Kubelet,若是网络能通,其实也能够直接把 Kubelet 的10255做为 target,能够直接写为:{1}:10255/metrics/cadvisor,表明直接请求Kubelet,规模大的时候还减轻了 Apiserver 的压力,即服务发现使用 Apiserver,采集不走 Apiserver
由于 cadvisor 是暴露主机端口,配置相对简单,若是是 kube-state-metric 这种 Deployment,以 endpoint 形式暴露,写法应该是:
- job_name: cluster-service-endpoints 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
对于 endpoint 类型,须要转换__metrics_path__
为/api/v1/namespaces/{1}/services/{2}:${3}/proxy/metrics,须要替换 namespace、svc 名称端口等,这里的写法只适合接口为/metrics的exporter,若是你的 exporter 不是/metrics接口,须要替换这个路径。或者像咱们同样统一约束都使用这个地址。
这里的__meta_kubernetes_service_annotation_prometheus_io_port来源就是 exporter 部署时写的那个 annotation,大多数文章中只提到prometheus.io/scrape: ‘true’,但也能够定义端口、路径、协议。以方便在采集时作替换处理。
其余的一些 relabel 如kubernetes_namespace 是为了保留原始信息,方便作 promql 查询时的筛选条件。
若是是多集群,一样的配置多写几遍就能够了,通常一个集群能够配置三类job:
nvidia-smi能够查看机器上的 GPU 资源,而Cadvisor 其实暴露了Metric来表示容器使用 GPU 状况,
container_accelerator_duty_cycle container_accelerator_memory_total_bytes container_accelerator_memory_used_bytes
若是要更详细的 GPU 数据,能够安装dcgm exporter,不过K8S 1.13 才能支持。
Prometheus 为避免时区混乱,在全部组件中专门使用 Unix Time 和 Utc 进行显示。不支持在配置文件中设置时区,也不能读取本机 /etc/timezone 时区。
其实这个限制是不影响使用的:
关于 timezone 的讨论,能够看这个issue。
假如你有一个负载均衡 LB,但网络上 Prometheus 只能访问到 LB 自己,访问不到后面的 RS,应该如何采集 RS 暴露的 Metric?
随着规模变大,Prometheus 须要的 CPU 和内存都会升高,内存通常先达到瓶颈,这个时候要么加内存,要么集群分片减小单机指标。这里咱们先讨论单机版 Prometheus 的内存问题。
缘由:
这里面有必定的优化空间。
个人指标须要多少内存:
以咱们的一个 Prometheus Server为例,本地只保留 2 小时数据,95 万 Series,大概占用的内存以下:
有什么优化方案:
2.14 以上能够看 Tsdb 状态
Prometheus 内存占用分析:
相关 issue:
容量规划除了上边说的内存,还有磁盘存储规划,这和你的 Prometheus 的架构方案有关。
Prometheus 每2小时将已缓冲在内存中的数据压缩到磁盘上的块中。包括Chunks、Indexes、Tombstones、Metadata,这些占用了一部分存储空间。通常状况下,Prometheus 中存储的每个样本大概占用1-2字节大小(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)不变的状况下,若是想减小本地磁盘的容量需求,只能经过减小每秒获取样本数(ingested_samples_per_second)的方式。
查看当前每秒获取的样本数:
rate(prometheus_tsdb_head_samples_appended_total[1h])
有两种手段,一是减小时间序列的数量,二是增长采集样本的时间间隔。考虑到 Prometheus 会对时间序列进行压缩,所以减小时间序列的数量效果更明显。
举例说明:
采集频率 30s,机器数量1000,Metric种类6000,1000600026024 约 200 亿,30G 左右磁盘。
只采集须要的指标,如 match[], 或者统计下最常使用的指标,性能最差的指标。
以上磁盘容量并无把 wal 文件算进去,wal 文件(Raw Data)在 Prometheus 官方文档中说明至少会保存3个 Write-Ahead Log Files,每个最大为128M(实际运行发现数量会更多)。
由于咱们使用了 Thanos 的方案,因此本地磁盘只保留2H 热数据。Wal 每2小时生成一份Block文件,Block文件每2小时上传对象存储,本地磁盘基本没有压力。
关于 Prometheus 存储机制,能够看这篇。
若是你的 Prometheus 使用了 kubernetes_sd_config 作服务发现,请求通常会通过集群的 Apiserver,随着规模的变大,须要评估下对 Apiserver性能的影响,尤为是Proxy失败的时候,会致使CPU 升高。固然了,若是单K8S集群规模太大,通常都是拆分集群,不过随时监测下 Apiserver 的进程变化仍是有必要的。
在监控Cadvisor、Docker、Kube-Proxy 的 Metric 时,咱们一开始选择从 Apiserver Proxy 到节点的对应端口,统一设置比较方便,但后来仍是改成了直接拉取节点,Apiserver 仅作服务发现。
Prometheus 中的 Counter 类型主要是为了 Rate 而存在的,即计算速率,单纯的 Counter 计数意义不大,由于 Counter 一旦重置,总计数就没有意义了。
Rate 会自动处理 Counter 重置的问题,Counter 通常都是一直变大的,例如一个 Exporter 启动,而后崩溃了。原本以每秒大约10的速率递增,但仅运行了半个小时,则速率(x_total [1h])将返回大约每秒5的结果。另外,Counter 的任何减小也会被视为 Counter 重置。例如,若是时间序列的值为[5,10,4,6],则将其视为[5,10,14,16]。
Rate 值不多是精确的。因为针对不一样目标的抓取发生在不一样的时间,所以随着时间的流逝会发生抖动,query_range 计算时不多会与抓取时间完美匹配,而且抓取有可能失败。面对这样的挑战,Rate 的设计必须是健壮的。
Rate 并不是想要捕获每一个增量,由于有时候增量会丢失,例如实例在抓取间隔中挂掉。若是 Counter 的变化速度很慢,例如每小时仅增长几回,则可能会致使【假象】。好比出现一个 Counter 时间序列,值为100,Rate 就不知道这些增量是如今的值,仍是目标已经运行了好几年而且才刚刚开始返回。
建议将 Rate 计算的范围向量的时间至少设为抓取间隔的四倍。这将确保即便抓取速度缓慢,且发生了一次抓取故障,您也始终可使用两个样本。此类问题在实践中常常出现,所以保持这种弹性很是重要。例如,对于1分钟的抓取间隔,您可使用4分钟的 Rate 计算,可是一般将其四舍五入为5分钟。
若是 Rate 的时间区间内有数据缺失,他会基于趋势进行推测,好比:
若有错误或其它问题,欢迎小伙伴留言评论、指正。若有帮助,欢迎点赞+转发分享。
欢迎你们关注民工哥的公众号:民工哥技术之路