Prometheus 如何做到“活学活用”,大牛总结的避坑指南
公众号关注“杰哥的IT之旅”,
选择“星标”,重磅干货,第一时间送达!
作者丨徐亚松 来源丨http://www.xuyasong.com/?p=1921
监控是基础设施,目的是为了解决问题,不要只朝着大而全去做,尤其是不必要的指标采集,浪费人力和存储资源(To B商业产品例外)。
需要处理的告警才发出来,发出来的告警必须得到处理。
简单的架构就是最好的架构,业务系统都挂了,监控也不能挂。Google Sre 里面也说避免使用 Magic 系统,例如机器学习报警阈值、自动修复之类。这一点见仁见智吧,感觉很多公司都在搞智能 AI 运维。
Prometheus 是基于 Metric 的监控,不适用于日志(Logs)、事件(Event)、调用链(Tracing)。
Prometheus 默认是 Pull 模型,合理规划你的网络,尽量不要转发。
对于集群化和水平扩展,官方和社区都没有银弹,需要合理选择 Federate、Cortex、Thanos等方案。
监控系统一般情况下可用性大于一致性,容忍部分副本数据丢失,保证查询请求成功。这个后面说 Thanos 去重的时候会提到。
Prometheus 不一定保证数据准确,这里的不准确一是指 rate、histogram_quantile 等函数会做统计和推断,产生一些反直觉的结果,这个后面会详细展开。二来查询范围过长要做降采样,势必会造成数据精度丢失,不过这是时序数据的特点,也是不同于日志系统的地方。
cadvisor: 集成在 Kubelet 中。
kubelet: 10255为非认证端口,10250为认证端口。
apiserver: 6443端口,关心请求数、延迟等。
scheduler: 10251端口。
controller-manager: 10252端口。
etcd: 如etcd 写入读取延迟、存储容量等。
docker: 需要开启 experimental 实验特性,配置 metrics-addr,如容器创建耗时等指标。
kube-proxy: 默认 127 暴露,10249端口。外部采集时可以修改为 0.0.0.0 监听,会暴露:写入 iptables 规则的耗时等指标。
kube-state-metrics: K8S 官方项目,采集pod、deployment等资源的元信息。
node-exporter: Prometheus 官方项目,采集机器指标如 CPU、内存、磁盘。
blackbox_exporter: Prometheus 官方项目,网络探测,dns、ping、http监控
process-exporter: 采集进程指标
nvidia exporter: 我们有 gpu 任务,需要 gpu 数据监控
node-problem-detector: 即 npd,准确的说不是 exporter,但也会监测机器状态,上报节点异常打 taint
应用层 exporter: mysql、nginx、mq等,看业务需求。
通过主进程拉起N个 Exporter 进程,仍然可以跟着社区版本做更新、bug fix。
用Telegraf来支持各种类型的 Input,N 合 1。
Use 方法:Utilization、Saturation、Errors。如 Cadvisor 数据
Red 方法:Rate、Errors、Duration。如 Apiserver 性能指标
在线服务:如 Web 服务、数据库等,一般关心请求速率,延迟和错误率即 RED 方法。
离线服务:如日志处理、消息队列等,一般关注队列数量、进行中的数量,处理速度以及发生的错误即 Use 方法。
批处理任务:和离线任务很像,但是离线任务是长期运行的,批处理任务是按计划运行的,如持续集成就是批处理任务,对应 K8S 中的 job 或 cronjob, 一般关注所花的时间、错误数等,因为运行周期短,很可能还没采集到就运行结束了,所以一般使用 Pushgateway,改拉为推。
role:node 的,包括 cadvisor、 node-exporter、kubelet 的 summary、kube-proxy、docker 等指标。
role:endpoint 的,包括 kube-state-metric 以及其他自定义 Exporter。
普通采集:包括Etcd、Apiserver 性能指标、进程指标等。
如果做可视化,Grafana是可以做时区转换的。
如果是调接口,拿到了数据中的时间戳,你想怎么处理都可以。
如果因为 Prometheus 自带的 UI 不是本地时间,看着不舒服,2.16 版本的新版 Web UI已经引入了Local Timezone 的选项,区别见下图。
如果你仍然想改 Prometheus 代码来适应自己的时区,可以参考《修改源码更改prometheus的时区问题》。
RS 的服务加 Sidecar Proxy,或者本机增加 Proxy 组件,保证 Prometheus 能访问到。
LB 增加 /backend1 和 /backend2请求转发到两个单独的后端,再由 Prometheus 访问 LB 采集。
Prometheus 的内存消耗主要是因为每隔2小时做一个 Block 数据落盘,落盘之前所有数据都在内存里面,因此和采集量有关。
加载历史数据时,是从磁盘到内存的,查询范围越大,内存越大。这里面有一定的优化空间。
一些不合理的查询条件也会加大内存,如 Group 或大范围 Rate。
作者给了一个计算器,设置指标量、采集间隔之类的,计算 Prometheus 需要的理论内存值:计算公式。
Sample 数量超过了 200 万,就不要单实例了,做下分片,然后通过 Victoriametrics,Thanos,Trickster 等方案合并数据。
评估哪些 Metric 和 Label 占用较多,去掉没用的指标。2.14 以上可以看 Tsdb 状态。
查询时尽量避免大范围查询,注意时间范围和 Step 的比例,慎用 Group。
如果需要关联查询,先想想能不能通过 Relabel 的方式给原始数据多加个 Label,一条Sql 能查出来的何必用Join,时序数据库不是关系数据库。
通过 pprof分析:https://www.robustperception.io/optimising-prometheus-2-6-0-memory-usage-with-pprof
1.X 版本的内存:https://www.robustperception.io/how-much-ram-does-my-prometheus-need-for-ingestion
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,计算本地磁盘使用量。
如果是 Remote-Write,和已有的 Tsdb 共用即可。
如果是 Thanos 方案,本地磁盘可以忽略(2H),计算对象存储的大小就行。
采集频率 30s,机器数量1000,Metric种类6000,1000600026024 约 200 亿,30G 左右磁盘。
只采集需要的指标,如 match[], 或者统计下最常使用的指标,性能最差的指标。
大量使用 join 来组合指标或者增加 label,如将 kube-state-metric 中的一些 meta label和 node-exporter 中的节点属性 label加入到 cadvisor容器数据里,像统计 pod 内存使用率并按照所属节点的机器类型分类,或按照所属 rs 归类。
范围查询时,大的时间范围 step 值却很小,导致查询到的数量过大。
rate 会自动处理 counter 重置的问题,最好由 promql 完成,不要自己拿出来全部元数据在程序中自己做 rate 计算。
在使用 rate 时,range duration要大于等于step,否则会丢失部分数据
prometheus 是有基本预测功能的,如deriv和predict_linear(更准确)可以根据已有数据预测未来趋势
如果比较复杂且耗时的sql,可以使用 record rule 减少指标数量,并使查询效率更高,但不要什么指标都加 record,一半以上的 metric 其实不太会查询到。同时 label 中的值不要加到 record rule 的 name 中。
node-exporter 不支持进程监控,这个前面已经提到了。
node-exporter 只支持 unix 系统,windows机器 请使用 wmi_exporter。因此以 yaml 形式不是 node-exporter 的时候,node-selector 要表明os类型。
因为node_exporter是比较老的组件,有一些最佳实践并没有merge进去,比如符合Prometheus命名规范,因此建议使用较新的0.16和0.17版本。
一是在机器上启动两个版本的node-exporter,都让prometheus去采集。
二是使用指标转换器,他会将旧指标名称转换为新指标
对于一些简单的需求,我们使用了 Grafana 的报警能力,所见即所得,直接在图表下面配置告警即可,报警阈值和状态很清晰。不过 Grafana 的报警能力很弱,只是实验功能,可以作为调试使用。
对于常见的 pod 或应用监控,我们做了一些表单化,如下图所示:提取了 CPU、内存、磁盘 IO 等常见的指标作为选择项,方便配置。
使用 webhook 扩展报警能力,改造 alertmanager, 在 send message 时做加密和认证,对接内部已有报警能力,并联动用户体系,做限流和权限控制。
调用 alertmanager api 查询报警事件,进行展示和统计。
增加了 Queue 组件,多了一层依赖,如果 App与 Queue 之间连接失败,难道要在 App 本地缓存监控数据?
抓取时间可能会不同步,延迟的数据将会被标记为陈旧数据,当然你可以通过添加时间戳来标识,但就失去了对陈旧数据的处理逻辑。
扩展性问题:Prometheus 适合大量小目标,而不是一个大目标,如果你把所有数据都放在了 Exposer 中,那么 Prometheus 的单个 Job 拉取就会成为 CPU 瓶颈。这个和 Pushgateway 有些类似,没有特别必要的场景,都不是官方建议的方式。
缺少了服务发现和拉取控制,Prom 只知道一个 Exposer,不知道具体是哪些 Target,不知道他们的 UP 时间,无法使用 Scrape_* 等指标做查询,也无法用scrape_limit做限制。
因为是 operator,所以依赖 K8S 集群,如果你需要二进制部署你的 Prometheus,如集群外部署,就很难用上prometheus-operator了,如多集群场景。当然你也可以在 K8S 集群中部署 operator 去监控其他的 K8S 集群,但这里面坑不少,需要修改一些配置。
operator 屏蔽了太多细节,这个对用户是好事,但对于理解 Prometheus 架构就有些 gap 了,比如碰到一些用户一键安装了operator,但 Grafana 图表异常后完全不知道如何排查,record rule 和 服务发现还不了解的情况下就直接配置,建议在使用 operator 之前,最好熟悉 prometheus 的基础用法。
operator 方便了 Prometheus 的扩展和配置,对于 alertmanager 和 exporter 可以很方便的做到多实例高可用,但是没有解决 Prometheus 的高可用问题,因为无法处理数据不一致,operator目前的定位也还不是这个方向,和 Thanos、Cortex 等方案的定位是不同的,下面会详细解释。
基本 HA:即两套 Prometheus 采集完全一样的数据,外边挂负载均衡
HA + 远程存储:除了基础的多副本 Prometheus,还通过 Remote Write 写入到远程存储,解决存储持久化问题
联邦集群:即 Federation,按照功能进行分区,不同的 Shard 采集不同的数据,由Global节点来统一存放,解决监控数据规模的问题。
使用 Thanos 或者 Victoriametrics,来解决全局查询、多副本数据 Join 问题。
官方建议数据做 Shard,然后通过Federation来实现高可用,
但是边缘节点和Global节点依然是单点,需要自行决定是否每一层都要使用双节点重复采集进行保活。也就是仍然会有单机瓶颈。
另外部分敏感报警尽量不要通过Global节点触发,毕竟从Shard节点到Global节点传输链路的稳定性会影响数据到达的效率,进而导致报警实效降低。
例如服务Updown状态,Api请求异常这类报警我们都放在Shard节点进行报警。
集群的后端有 A 和 B 两个实例,A 和 B 之间没有数据同步。A 宕机一段时间,丢失了一部分数据,如果负载均衡正常轮询,请求打到A 上时,数据就会异常。
如果 A 和 B 的启动时间不同,时钟不同,那么采集同样的数据时间戳也不同,就不是多副本同样数据的概念了
就算用了远程存储,A 和 B 不能推送到同一个 TSDB,如果每人推送自己的 TSDB,数据查询走哪边就是问题了。
存储角度:如果使用 Remote Write 远程存储, A 和 B后面可以都加一个 Adapter,Adapter做选主逻辑,只有一份数据能推送到 TSDB,这样可以保证一个异常,另一个也能推送成功,数据不丢,同时远程存储只有一份,是共享数据。
查询角度:上边的方案实现很复杂且有一定风险,因此现在的大多数方案在查询层面做文章,比如 Thanos 或者 Victoriametrics,仍然是两份数据,但是查询时做数据去重和 Join。只是 Thanos 是通过 Sidecar 把数据放在对象存储,Victoriametrics 是把数据 Remote Write 到自己的 Server 实例,但查询层 Thanos-Query 和 Victor 的 Promxy的逻辑基本一致。
日志采集与推送:一般是Fluentd/Fluent-Bit/Filebeat等采集推送到 ES、对象存储、kafaka,日志就该交给专业的 EFK 来做,分为容器标准输出、容器内日志。
日志解析转 metric:可以提取一些日志转为 Prometheus 格式的指标,如解析特定字符串出现次数,解析 Nginx 日志得到 QPS 、请求延迟等。常用方案是 mtail 或者 grok
sidecar 方式:和业务容器共享日志目录,由 sidecar 完成日志推送,一般用于多租户场景。
daemonset 方式:机器上运行采集进程,统一推送出去。
1.15 及以下:/var/log/pods/{pod_uid}/
1.15 以上:var/log/pods/{pod_name+namespace+rs+uuid}/
使用 kube-eventer 之类的组件采集 Events 并推送到 ES
使用 event_exporter 之类的组件将Events 转化为 Prometheus Metric,同类型的还有谷歌云的 stackdriver 下的 event-exporter
参考资料
https://tech.meituan.com/2018/11/01/cat-in-depth-java-application-monitoring.html
https://dbaplus.cn/news-134-1462-1.html
https://www.infoq.cn/article/P3A5EuKl6jowO9v4_ty1
https://zhuanlan.zhihu.com/p/60791449
http://download.xuliangwei.com/jiankong.html#0-%E7%9B%91%E6%8E%A7%E7%9B%AE%E6%A0%87
https://aleiwu.com/post/prometheus-bp/
https://www.infoq.cn/article/1AofGj2SvqrjW3BKwXlN
http://bos.itdks.com/e8792eb0577b4105b4c9d19eb0dd1892.pdf
https://www.infoq.cn/article/ff46l7LxcWAX698zpzB2
https://www.robustperception.io/putting-queues-in-front-of-prometheus-for-reliability
https://www.slideshare.net/cadaam/devops-taiwan-monitor-tools-prometheus
https://www.robustperception.io/how-much-disk-space-do-prometheus-blocks-use
https://www.imooc.com/article/296613
https://dzone.com/articles/what-is-high-cardinality
https://www.robustperception.io/cardinality-is-key
https://www.robustperception.io/using-tsdb-analyze-to-investigate-churn-and-cardinality
https://blog.timescale.com/blog/prometheus-ha-postgresql-8de68d19b6f5/
https://asktug.com/t/topic/2618
往期资源回顾 需要可自取
推荐阅读
点个[在看],是对杰哥最大的支持!