Thanos分布式集群Prometheus方案设计

Posted by     "Pyker" on Friday, March 20, 2020

TOC

写在开头

本文是记录一次真实生产环境prometheus架构调整的的设计方案。

现有promethus架构

架构剖析

  • 采用4台作业prometheus抓取metrics。
  • 采用2台查询prometheus通过remote_read接口查询作业节点抓取的metrics。
  • 最终通过grafana关联2个查询prometheus的数据源进行数据绘图。

优点:

  1. 实现了监控数据的收集、查询节点分离,更容易实现高可用。
  2. 查询节点实现了数据指标的聚合,作业节点达到水平扩容。

缺点:

  1. 指标数据存放在本地,且分散在每台作业节点上,存在单点故障。
  2. 查询节点使用远程查询,依然没有解决磁盘IO的问题。
  3. 需要人工干预哪些指标应该被哪台prometheus监控。

prometheus分片

prometheus分片剖析

为什么要分片?

如果集群节点数量达到上千甚至几千的规模,对于一些节点级服务暴露的指标,它们这种单个服务背后的指标数据体量就非常大;针对这种场景,一个 Prometheus 实例可能连这单个服务的采集任务都扛不住。Prometheus 需要向这个服务所有后端实例发请求采集数据,由于后端实例数量规模太大,采集并发量就会很高,一方面对节点的带宽、CPU、磁盘 IO 都有一定的压力,另一方面 Prometheus 使用的磁盘空间有限,采集的数据量过大很容易就将磁盘塞满了,通常要做一些取舍才能将数据量控制在一定范围,但这种取舍也会降低数据完整和精确程度,不推荐这样做。那么针对服务做一下分片,将其拆分成多个 group,让一个 Prometheus 实例仅采集这个服务背后的某一个 group 的数据,这样就可以将这个大体量服务的监控数据拆分到多个 Prometheus 实例上。

如何分片?

利用consul_sd_configs或kubernetes_sd_configs等 服务发现,再利用 Prometheus relabel 配置的 hashmod 来对 node 做分片,每个 Prometheus 实例仅抓其中一个分片中的数据:

部分 prometheus.yaml 配置如下:

- job_name: 'cadvisor-1'
    metrics_path: /metrics/cadvisor
    kubernetes_sd_configs:
    - role: node
    tls_config:
      insecure_skip_verify: true
    relabel_configs:
    - source_labels: [__address__]
      modulus:       4    # 将节点分片成 4 个 group
      target_label:  __tmp_hash
      action:        hashmod
    - source_labels: [__tmp_hash]
      regex:         1  # 只抓第 2 个 group 中节点的数据(序号 0 为第 1 个 group)
      action:        keep

Thanos架构拓扑

Thanos原理剖析

Thanos Query它实现了 Prometheus 的 HTTP API,能够 执行 PromQL。这样,查询 Prometheus 监控数据的 client 就不直接查询 Prometheus 本身了,而是去查询 Thanos Query,Thanos Query 再去下游多个存储了数据的地方查数据,最后将这些数据聚合去重后返回给 client,也就实现了分布式 Prometheus 的数据查询。

那么 Thanos Query 又如何去查下游分散的数据呢?Thanos 为此抽象了一套叫 Store API 的内部 gRPC 接口,其它一些组件通过这个接口来暴露数据给 Thanos Query,它自身也就可以做到完全无状态部署,实现高可用与动态扩展。

那么这些分散的数据来自哪些地方呢?首先,Prometheus 会将采集的数据存到本机磁盘上,如果我们直接用这些分散在各个磁盘上的数据,可以给每个 Prometheus 附带部署一个 Sidecar,这个 Sidecar 实现 Thanos Store API,当 Thanos Query 对其发起查询时,Sidecar 就读取跟它绑定部署的 Prometheus 实例上的监控数据返回给 Thanos Query。

由于 Thanos Query 可以对数据进行聚合与去重,所以可以很轻松实现高可用:相同的 Prometheus 部署多个副本(都附带 Sidecar),然后 Thanos Query 去所有 Sidecar 查数据,即便有一个 Prometheus 实例挂掉过一段时间,数据聚合与去重后仍然能得到完整数据。

不过因为磁盘空间有限,所以 Prometheus 存储监控数据的能力也是有限的,通常会给 Prometheus 设置一个数据过期时间 (默认15天) 或者最大数据量大小,不断清理旧数据以保证磁盘不被撑爆。因此,我们无法看到时间比较久远的监控数据,有时候这也给我们的问题排查和数据统计造成一些困难。那么对于需要长期存储的数据,并且使用频率不那么高,最理想的方式是存进对象存储。Thanos Sidecar等组件支持将数据上传至对象存储。

那么这些被上传到了对象存储里的监控数据该如何查询呢?既然Thanos 抽象出了 Store API,那么只要实现了该接口的组件都可以作为 Thanos Query 查询的数据源,Thanos Store Gateway 这个组件也实现了 Store API,向 Thanos Query 暴露对象存储的数据。Thanos Store Gateway 内部还做了一些加速数据获取的优化逻辑,一是缓存了 TSDB 索引,二是优化了对象存储的请求 (用尽可能少的请求量拿到所有需要的数据)。

这里不对Ruler报警规则组件和Compact指标数据压缩组件做介绍。

Thanos Query和Thanos Sidecar拓扑

Thanos数据上传 和 查询对象存储数据拓扑

最终prometheus + thanos运行于K8S架构

K8S + Prometheus + Thanos优势

相比于目前公司prometheus架构,k8s+prometheus+thanos具有以下优势:

  • prometheus高可用:每个prometheus都可用配置多个副本集,从而解决单点故障的问题。
  • thanos高可用:每个thanos组件都可用配置多个副本集,从而解决thanos单点故障的问题。
  • 服务分片:将大量服务或者指标进行hashmod分片,水平扩展减轻单点prometheus的压力。
  • 数据聚合与去重:thanos query会自动将若干prometheus采集过来的数据聚合去重后返回。
  • 数据持久化:thanos sidecar和ruler会将prometheus采集的数据永久存储在对象存储中。
  • 时间序列降采样:查询时间范围较久的数据时,compact可提供降采样已保障查询性能。

「真诚赞赏,手留余香」

云原生与运维

真诚赞赏,手留余香

使用微信扫描二维码完成支付


comments powered by Disqus