基于Prometheus的监控系统实践

基于Prometheus的监控系统实践
监控作为底层基础设施的⼀环,是保障⽣产环境服务稳定性不可或缺的⼀部分,线上问题从发现到定位再到解决,通过监控和告警⼿段可以有效地覆盖了「发现」和「定位」,甚⾄可以通过故障⾃愈等⼿段实现解决,服务开发和运维⼈员能及时有效地发现服务运⾏的异常,从⽽更有效率地排查和解决问题。
⼀个典型的监控(如⽩盒监控),通常会关注于⽬标服务的内部状态,例如:
单位时间接收到的请求数量
单位时间内请求的成功率/失败率
请求的平均处理耗时
⽩盒监控很好地描述了系统的内部状态,但缺少从外部⾓度看到的现象,⽐如:⽩盒监控只能看到已经接收的请求,并不能看到由于 DNS 故障导致没有发送成功的请求,⽽⿊盒监控此时便可以作为补充⼿段,由探针(probe)程序来探测⽬标服务是否成功返回,更好地反馈系统的当前状态。
某⽇需要为服务搭建⼀个监控系统来采集应⽤埋点上报的指标,经过⼀番对⽐,最终选择了 Prometheus 来作为我们的业务监控,因为它具有以下优点:
⽀持 PromQL(⼀种查询语⾔),可以灵活地聚合指标数据
部署简单,只需要⼀个⼆进制⽂件就能跑起来,不需要依赖分布式存储
Go 语⾔编写,组件更⽅便集成在同样是Go编写项⽬代码中
原⽣⾃带 WebUI,通过 PromQL 渲染时间序列到⾯板上
⽣态组件众多,Alertmanager,Pushgateway,Exporter……
Prometheus 的架构图如下:
制作无纺布手提袋在上⾯流程中,Prometheus 通过配置⽂件中指定的服务发现⽅式来确定要拉取监控指标的⽬标(Target),接着从要拉取的⽬标(应⽤容器和Pushgateway)发起HTTP请求到特定的端点(Metric Path),将指标持久化⾄本⾝的TSDB中,TSDB最终会把内存中的时间序列压缩落到硬盘,除此之外,Prometheus 会定期通过 PromQL 计算设置好的告警规则,决定是否⽣成告警到 Alertmanager,后者接收到告警后会负责把通知发送到邮件或企业内部聊中。
Prometheus 的指标名称只能由 ASCII 字符、数字、下划线以及冒号组成,⽽且有⼀套命名规范:
使⽤基础 Unit(如 seconds ⽽⾮ milliseconds)
指标名以 application namespace 作为前缀,如:
process_cpu_seconds_total
http_request_duration_seconds
⽤后缀来描述 Unit,如:
http_request_duration_seconds
node_memory_usage_bytes
http_requests_total
process_cpu_seconds_total
foobar_build_info
Prometheus 提供了以下基本的指标类型:看门狗电路
Counter:代表⼀种样本数据单调递增的指标,即只增不减,通常⽤来统计如服务的请求数,错误数等。
Gauge:代表⼀种样本数据可以任意变化的指标,即可增可减,通常⽤来统计如服务的CPU使⽤值,内存占⽤值等。
Histogram 和 Summary:⽤于表⽰⼀段时间内的数据采样和点分位图统计结果,通常⽤来统计请求耗时或响应⼤⼩等。
Prometheus 是基于时间序列存储的,⾸先了解⼀下什么是时间序列,时间序列的格式类似于(timestamp,value)这种格式,即⼀个时间点拥有⼀个对应值,例如⽣活中很常见的天⽓预报,如:[(14:00,27℃),(15:00,28℃),(16:00,26℃)],就是⼀个单维的时间序列,这种按照时间戳和值存放的序列也被称之为向量(vector)。
再来举另⼀个例⼦,如上图所⽰,假如有⼀个指标 http_requests,它的作⽤是统计每个时间段对应的总请求量是多少,这时候它即为上⾯提到的是⼀个单维矩阵,⽽当我们给这个指标加上⼀个维度:主机名,这时候这个指标的作⽤就变成了统计每个时间段各个主机名对应的请求量是多少,这时候这个矩阵区域就变成拥有多列向量(每⼀列对应⼀个主机名)的时间序列,当给这个时间序列再添加多个标签
(key=value)时,这个矩阵就相应会变成⼀个多维矩阵。
每⼀组唯⼀的标签集合对应着⼀个唯⼀的向量(vector),也可叫做⼀个时间序列(Time Serie),当在某⼀个时间点来看它时,它是⼀个瞬时向量(Instant Vector),瞬时向量的时序只有⼀个时间点以
及它对于的⼀个值,⽐如:今天 12:05:30 时服务器的 CPU 负载;⽽在⼀个时间段来看它时,它是⼀个范围向量(Range Vector),范围向量对于着⼀组时序数据,⽐如:今天11:00到12:00时服务器的CPU负载。
类似的,可以通过指标名和标签集来查询符合条件的时间序列:
0402封装http_requests{host="host1",service="web",code="200",env="test"}
查询结果会是⼀个瞬时向量:
http_requests{host="host1",service="web",code="200",env="test"} 10
http_requests{host="host2",service="web",code="200",env="test"} 0
http_requests{host="host3",service="web",code="200",env="test"} 12
⽽如果给这个条件加上⼀个时间参数,查询⼀段时间内的时间序列:
http_requests{host="host1",service="web",code="200",env="test"}[:5m]
结果将会是⼀个范围向量:
内孔撑圆涨紧夹具
http_requests{host="host1",service="web",code="200",env="test"} 0 4 6 8 10
http_requests{host="host2",service="web",code="200",env="test"} 0 0 0 0 0
http_requests{host="host3",service="web",code="200",env="test"} 0 2 5 9 12
拥有了范围向量,我们是否可以针对这些时间序列进⾏⼀些聚合运算呢?没错,PromQL就是这么⼲的,⽐如我们要算最近5分钟的请求增长速率,就可以拿上⾯的范围向量加上聚合函数来做运算:
rate(http_requests{host="host1",service="web",code="200",env="test"}[:5m])
⽐如要求最近5分钟请求的增长量,可以⽤以下的 PromQL:
increase(http_requests{host="host1",service="web",code="200",env="test"}[:5m])
要计算过去10分钟内第90个百分位数:
histogram_quantile(0.9, rate(employee_age_bucket_bucket[10m]))
在 Prometheus 中,⼀个指标(即拥有唯⼀的标签集的 metric)和⼀个(timestamp,value)组成了⼀个样本
(sample),Prometheus 将采集的样本放到内存中,默认每隔2⼩时将数据压缩成⼀个 block,持久化到硬盘中,样本的数量越
多,Prometheus占⽤的内存就越⾼,因此在实践中,⼀般不建议⽤区分度(cardinality)太⾼的标签,⽐如:⽤户IP,ID,URL地址等等,否则结果会造成时间序列数以指数级别增长(label数量相乘)。
除了控制样本数量和⼤⼩合理之外,还可以通过降低 storage.tsdb.min-block-duration 来加快数据落盘时间和增加 scrape interval 的值提⾼拉取间隔来控制 Prometheus 的占⽤内存。
通过声明配置⽂件中的 scrape_configs 来指定 Prometheus 在运⾏时需要拉取指标的⽬标,⽬标实例需要实现⼀个可以被 Prometheus 进⾏轮询的端点,⽽要实现⼀个这样的接⼝,可以⽤来给 Prometheus 提供监控样本数据的独⽴程序⼀般被称作为 Exporter,⽐如⽤来拉取操作系统指标的 Node Exporter,它会从操作系统上收集硬件指标,供 Prometheus 来拉取。
在开发环境,往往只需要部署⼀个 Prometheus 实例便可以满⾜数⼗万指标的收集。但在⽣产环境中,应⽤和服务实例数量众多,只部署⼀个 Prometheus 实例通常是不够的,⽐较好的做法是部署多个Prometheus实例,每个实例通过分区只拉取⼀部分指标,例如Prometheus Relabel配置中的hashmod功能,可以对拉取⽬标的地址进⾏hashmod,再将结果匹配⾃⾝ID的⽬标保留:
relabel_configs:
- source_labels: [__address__]
modulus:      3
target_label:  __tmp_hash
action:        hashmod
第n个空间- source_labels: [__tmp_hash]
regex:        $(PROM_ID)
action:        keep
或者说,我们想让每个 Prometheus 拉取⼀个集的指标,⼀样可以⽤ Relabel 来完成:
relabel_configs:
- source_labels:  ["__meta_consul_dc"]
regex: "dc1"
action: keep
现在每个 Prometheus 都有各⾃的数据了,那么怎么把他们关联起来,建⽴⼀个全局的视图呢?官⽅提供了⼀个做法:联邦集(federation),即把 Prometheuse Server 按照树状结构进⾏分层,根节点⽅向的 Prometheus 将查询叶⼦节点的 Prometheus 实例,再将指标聚合返回。
不过显然易见的时,使⽤联邦集依然不能解决问题,⾸先单点问题依然存在,根节点挂了的话查询将会变得不可⽤,如果配置多个⽗节点的话⼜会造成数据冗余和抓取时机导致数据不⼀致等问题,⽽且叶⼦节点⽬标数量太多时,更加会容易使⽗节点压⼒增⼤以⾄打满宕机,除此之外规则配置管理也是个⼤⿇烦。
还好社区出现了⼀个 Prometheus 的集解决⽅案:Thanos,它提供了全局查询视图,可以从多台Pr
ometheus查询和聚合数据,因为所有这些数据均可以从单个端点获取。
1. Querier 收到⼀个请求时,它会向相关的 Sidecar 发送请求,并从他们的 Prometheus 服务器获取时间序列数据。
2. 它将这些响应的数据聚合在⼀起,并对它们执⾏ PromQL 查询。它可以聚合不相交的数据也可以针对 Prometheus 的⾼可⽤组进⾏
数据去重。
再来说到存储,Prometheus 查询的⾼可⽤可以通过⽔平扩展+统⼀查询视图的⽅式解决,那么存储的⾼可⽤要怎么解决呢?在Prometheus 的设计中,数据是以本地存储的⽅式进⾏持久化的,虽然本地持久化⽅便,当也会带来⼀些⿇烦,⽐如节点挂了或者Prometheus 被调度到其他节点上,就会意味
着原节点上的监控数据在查询接⼝中丢失,本地存储导致了 Prometheus ⽆法弹性扩展,为此 Prometheus 提供了 Remote Read 和 Remote Write 功能,⽀持把 Prometheus 的时间序列远程写⼊到远端存储中,查询时可以从远端存储中读取数据。
血仓其中⼀个例⼦中就是M3DB,M3DB是⼀个分布式的时间序列数据库,它提供了Prometheus的远程读写接⼝,当⼀个时间序列写⼊到
M3DB集后会按照分⽚(Shard)和复制(Replication Factor)参数把数据复制到集的其他节点上,实现存储⾼可⽤。除了M3DB 外,Prometheus⽬前还⽀持InfluxDB、OpenTSDB等作为远程写的端点。
解决了 Prometheus 的⾼可⽤,再来关注⼀下 Prometheus 如何对监控⽬标进⾏采集,当监控节点数
量较⼩时,可以通过 Static Config 将⽬标主机列表写到 Prometheus 的拉取配置中,但如果⽬标节点⼀多的话这种⽅式管理便有很⼤问题了,⽽且在⽣产环境中,服务实例的IP通常不是固定的,这时候⽤静态配置就没办法对⽬标节点进⾏有效管理,这时候 Prometheus 提供的服务发现功能便可以有效解决监控节点状态变化的问题,在这种模式下,Prometheus 会到注册中⼼监听查询节点列表,定期对节点进⾏指标的拉取。
如果对服务发现有更灵活的需求,Prometheus 也⽀持基于⽂件的服务发现功能,这时候我们可以从多个注册中⼼中获取节点列表,再通过⾃⼰的需求进⾏过滤,最终写⼊到⽂件,这时候 Prometheus 检测到⽂件变化后便能动态地替换监控节点,再去拉取⽬标了。
前⾯看到 Prometheus 都是以拉模式定期对⽬标节点进⾏抓取的,那假如有⼀种情况是⼀些任务节点还没来得及被拉取就运⾏完退出了,这时候监控数据就会丢失,为了应对这种情况,Prometheus 提供了⼀个⼯具:Pushgateway,⽤来接收来⾃服务的主动上报,它适⽤于那些短暂存活的批量任务来将指标推送并暂存到⾃⾝上,借着再由Prometheus 来拉取⾃⾝,以防⽌指标还没来得及被 Prometheus 拉取便退出。
除此以外 Pushgateway 也适⽤于在 Prometheus 与应⽤节点运⾏在异构⽹络或被防⽕墙隔绝时,⽆法主动拉取节点的问题,在这种情况下应⽤节点可以通过使⽤Pushgateway的域名将指标推送到Pushga
teway实例上,Prometheus就可以拉取同⽹络下的Pushgateway 节点了,另外配置拉取 Pushgateway 时要注意⼀个问题:Prometheus 会把每个指标赋予 job 和instance标签,当Prometheus拉取Pushgateway时,job和instance则可能分别是Pushgateway和Pushgateway主机的ip,当pushgateway上报的指标中也包含job和instance标签时,Prometheus会把冲突的标签重命名为exported_job和exported_instance,如果需要覆盖这两个标签的话,需要在Prometheus中配置honor_labels: true。
Pushgateway可以替代拉模型来作为指标的收集⽅案,但在这种模式下会带来许多负⾯影响:
Pushgateway 被设计为⼀个监控指标的缓存,这意味着它不会主动过期服务上报的指标,这种情况在服务⼀直运⾏的时候不会有问题,但当服务被重新调度或销毁时,Pushgateway 依然会保留着之前节点上报的指标。⽽且,假如多个 Pushgateway 运⾏在LB下,会造成⼀个监控指标有可能出现在多个 Pushgateway 的实例上,造成数据重复多份,需要在代理层加⼊⼀致性哈希路由来解决。
在拉模式下,Prometheus可以更容易的查看监控⽬标实例的健康状态,并且可以快速定位故障,但在推模式下,由于不会对客户端进⾏主动探测,因此对⽬标实例的健康状态也变得⼀⽆所知。
最后再来聊⼀下Alertmanager,简单说 Alertmanager 是与 Prometheus 分离的告警组件,主要接收 Promethues 发送过来的告警事件,然后对告警进⾏去重,分组,抑制和发送,在实际中可以搭配 we
bhook 把告警通知发送到企业或钉钉上,其架构图如下:

本文发布于:2024-09-23 07:23:26,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/160786.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:指标   时间   监控   节点
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议