云原生下监控实践-prometheus push推送方式
1、前言Prometheus大家都不会陌生,其在提供实用、可靠、廉价的监控解决方案的同时,Prometheus自身的稳定性和强大的 API、查询语言和集成协议(例如 Remote Write 和 OpenMetrics)使其备受瞩目。
现在大多数it角色都希望部署的软件有一个Prometheus可以抓取的 HTTP/HTTPS/metrics端点。 通过这些应用自带的或者第三方插件式的exporter来达到应用性能的可观察性。可观察性范式发生了变化,从而也提高了软件弹性、可调试性和数据驱动的决策!
2、日常使用方式
众所周知Prometheus默认是采用的Pull方式来获取监控数据,即使用PushGateway从采集端看是推送到Pushgateway但是对于Prometheus来说还是Pull的方式去拉去Pushgateway当中的监控数据。
image-1.jpg
通常我们为了确保 Prometheus 服务的高可用性,我们只需要部署多个 Prometheus 实例,然后采集相同的 metrics 数据,我们日常中使用的较轻量化的方案如下:
1)、主备多副本实例:
通过部署多实例Prometheus然后为其添加远程存储来保证数据持久化。在给 Prometheus 配置上远程存储过后,我们就不用担心数据丢失的问题。同时我们通过主备实例的方式来解决多副本的Prometheus指标采集多写导致的数据不一致的问题。那么这个主备的实现方式有多种比如:修改原代码,在Prometheus启动的时候往注册中心进行注册的方式获取锁,获取成功的节点成为 Leader 执行任务,若主节点宕机,从节点获取锁成为 Leader 并接管服务,这种方式涉及到定制化的修改不太合适;另一种就是我们通过haproxy的对backend的健康检查辅以脚本或工具来实现上面类似主备切换的逻辑;
image-2.jpg
2)、联邦集群:
一个Prometheus服务节点所能接管的主机数量有限,接入过多的指标会将其压垮。而联邦模式允许Prometheus服务器从另一个 Prometheus 服务器抓取特定数据。有分层联邦和跨服务联邦,分层联邦较为常用,且配置简单。日常中我们通过联邦的方式来将整个集群监控的target划分到不同的Promthues实例中,达到我们对整个集群监控指标的分片处理,比如一个Prometheus负责采集节点的指标数据,另外一个 Prometheus 负责采集应用业务相关的监控指标数据,最后在上层通过一个 Prometheus 对数据进行汇总。
image-3.jpg
上面的日常用法通常适用于集群规模不太大的集群,而对于大规模集群社区对Prometheus部署模型扩展到单节点之外(例如 Cortex、Thanos 等);Cortex的定位是提供Prometheus as a Service,采用中心化的架构。Prometheus可能来自于多个不同的地域,所有的数据都汇入一个Cortex数据中心,由Cortex集中写入,查询和告警。Thanos采用的是分散式的架构,其数据可以分散在多个数据中心,且分别存储于多个对象存储桶中。对于数据的写入,查询和告警可分散也可集中。其次cortex通过插件支持多租户的数据隔离,而Thanos则不支持。具体的使用方式还是以业务场景为准。
3、云原生下的实践
随着我们应用交付的方式由传统私有化部署交付转变到现在面对公有云、私有云或混合云这样“云原生”方式的交付,面对这样的转变我们迎接的将会是更多的限制,比如跨网的限制、安全规则的限制等等。不怕袖子一拉,干,正所谓易穷则变,变则通,通则久。
1)、Prometheus Agent:
在“云原生”环境下Prometheus随处可见,更不用说采用 Prometheus 的 API 和数据模型的云供应商(例如 Amazon Managed Prometheus、Google Cloud Managed Prometheus、Grafana Cloud 等)。这里介绍一种新的运行 Prometheus 的操作模式,官方称为“代理”。它直接内置在 Prometheus 二进制文件中。Agent 模式针对远程写入进行了优化 Prometheus,它禁用查询、警报和本地存储,并将其替换为自定义的 TSDB WAL(在成功写入后立即删除数据。如果它无法到达远程端点,它会将数据临时保存在磁盘上,直到远程端点重新联机)。其他一切都保持不变:抓取逻辑、服务发现和相关配置。我们可以直接使用Prometheus Agent模式来将采集的到的数据转发到远程 Prometheus 服务器或任何其他符合 Remote-Write 的项目。
image-4.jpg
Prometheus 远程写入协议允许我们将 Prometheus 收集的所有或部分指标转发(流式传输)到远程位置。因此我们可以在全局级别部署 Prometheus 以接收该流并跨集群聚合数据。
如何使用这种方式呢?我们可以在最新的Prometheus v2.32.0版本中通过"--enable-feature=agent"这个flag来开启Prometheus的agent模式。
2)、remote write集成:
既然官方给出了这样的使用方式,那么我们完全可以按照这样的思路去实现一个简单的更轻量化的代理工具,将这个代理工具以sidecar方式部署到我们每个应用pod内或者集成到我们自己的应用中去。
查阅了Prometheus源码后其自身的远程写协议大致流程是初始化一个远程写客户端然后该客户会启动一个协程来从本地的WAL日志中获取sampels数据然后进行protobuf序列化,然后在将序列化的数据通过snapy进行压缩,最后发送数据到远程端点,远程端点接受到后跟prometheus做的事情正好相反,先进行sappy的解压缩,然后再protobuf反序列化,得到真实的数据。
好了说了这么多我们开始干,这里我们在全局级别部署Prometheus v2.25.0版本该版本开始支持将Prometheus自身作为远程存储用于接收来自其它Prometheus server的remote write或者实现了remote wrie协议的应用写入监控指标数据。然后我们去实现remote write的方式,相对Prometheus的 Agent模式我们剔除了wal的过程,我们只实现我们想要的内容从而更轻量化的集成。(Prometheus sever开启remote write的方式也是在启动运行服务的时候增加"--enable-feature=remote-write-receiver"配置项即可)
第一步定义我们需要的配置:
image-5.jpg
第二步实现我们需要的协议:
这里我们实现了往pushgateway和prometheus推送的两种功能,这里仅介绍prometheus相关的,我们先定义一个接口,该接口下有两个方法。
WriteProto:用于直接将抓取的原生timeseries类型的数据进行推送;WriteMetricPointList:用于我们从指定的exporter抓取的数据对其进行格式化后推送;
image-6.jpg
核心的推送其实就是一个http的POST请求,将解析好的数据转成流来传输;
.........data, err := proto.Marshal(promWR) //对sample数据进行序列化if err != nil { return result, writeError{err: fmt.Errorf("unable to marshal protobuf: %v", err)}}encoded := snappy.Encode(nil, data) //对序列化的数据进行压缩body := bytes.NewReader(encoded)req, err := http.NewRequest("POST", c.writeURL, body)if err != nil { return result, writeError{err: err}}.........resp, err := c.httpClient.Do(req.WithContext(ctx)) //向remoteSotre发起请.........
第三步测试:
我们先运行一个没有抓取任何target的Prometheus server:
image-7.jpg
运行我们的工具:
等待任务的周期推送结果。
然后我们查看刚刚部署的那个仅仅做为remoteStorage的Prometheus server,发现我们remote write的数据成功写入,同时也带上了我们自定义的label:
image-8.jpg
image-9.jpg
好了到此为止了,有人会说这样做是不是有点多此一举了直接用pushgateway不就好了么,是的用pushgateway是能完成上诉的过程但是pushgateway在高并发的情况下还是比较消耗资源的,特别是开启一致性检查,高并发写入的时候特别慢。而通过remote write的方式不仅保证了性能的同时我们还能兼容更多开源的平台,如上面提到的Cortex、Thanos又或者其它提供了Prometheus 的API和数据模型的云供应商,当然该模式也可以用在边缘计算的场景下也更适合。以上是我们在私有云的云原生环境下的实践。
后续若有需求这部分代码将会推到个人代码仓库中!
页:
[1]