高可用prometheus:thanos 实践

背景

prometheus 使用心得文章中有简单提到prometheus 的高可用方案,尝试了联邦、remote write 以后,咱们最终选择了 thanos 做为监控配套组件,利用其全局视图来管理咱们的多地域/上百个集群的监控数据。本文主要介绍 thanos 的一些组件使用和心得体会。html

prometheus官方的高可用有几种方案:node

  1. HA:即两套 prometheus 采集彻底同样的数据,外边挂负载均衡
  2. HA + 远程存储:除了基础的多副本prometheus,还经过Remote write 写入到远程存储,解决存储持久化问题
  3. 联邦集群:即federation,按照功能进行分区,不一样的 shard 采集不一样的数据,由Global节点来统一存放,解决监控数据规模的问题。

使用官方建议的多副本 + 联邦仍然会遇到一些问题,本质缘由是prometheus的本地存储没有数据同步能力,要在保证可用性的前提下再保持数据一致性是比较困难的,基本的多副本 proxy 知足不了要求,好比:git

  • prometheus集群的后端有 A 和 B 两个实例,A 和 B 之间没有数据同步。A 宕机一段时间,丢失了一部分数据,若是负载均衡正常轮询,请求打到A 上时,数据就会异常。
  • 若是 A 和 B 的启动时间不一样,时钟不一样,那么采集一样的数据时间戳也不一样,就多副本的数据不相同
  • 就算用了远程存储,A 和 B 不能推送到同一个 tsdb,若是每人推送本身的 tsdb,数据查询走哪边就是问题
  • 官方建议数据作Shard,而后经过federation来实现高可用,可是边缘节点和Global节点依然是单点,须要自行决定是否每一层都要使用双节点重复采集进行保活。也就是仍然会有单机瓶颈。
  • 另外部分敏感报警尽可能不要经过global节点触发,毕竟从Shard节点到Global节点传输链路的稳定性会影响数据到达的效率,进而致使报警实效下降。

目前大多数的 prometheus 的集群方案是在存储、查询两个角度上保证数据的一致:github

  • 存储角度:若是使用 remote write 远程存储, A 和 B后面能够都加一个 adapter,adapter作选主逻辑,只有一份数据能推送到 tsdb,这样能够保证一个异常,另外一个也能推送成功,数据不丢,同时远程存储只有一份,是共享数据。方案能够参考这篇文章
  • 存储角度:仍然使用 remote write 远程存储,可是 A 和 B 分别写入 tsdb1 和 tsdb2 两个时序数据库,利用sync的方式在 tsdb1 和2 以前作数据同步,保证数据是全量的。
  • 查询角度:上边的方案须要本身实现,有侵入性且有必定风险,所以大多数开源方案是在查询层面作文章,好比thanos 或者victoriametrics,仍然是两份数据,可是查询时作数据去重和join。只是 thanos是经过 sidecar 把数据放在对象存储,victoriametrics是把数据remote write 到本身的 server 实例,但查询层 thanos-query 和victor的 promxy的逻辑基本一致,都是为全局视图服务

实际需求

随着咱们的集群规模愈来愈大,监控数据的种类和数量也愈来愈多:如master/node 机器监控、进程监控、4 大核心组件的性能监控,pod 资源监控、kube-stats-metrics、k8s events监控、插件监控等等。除了解决上面的高可用问题,咱们还但愿基于 prometheus 构建全局视图,主要需求有:web

  • 长期存储:1 个月左右的数据存储,天天可能新增几十G,但愿存储的维护成本足够小,有容灾和迁移。考虑过使用 influxdb,但influxdb没有现成的集群方案,且须要人力维护。最好是存放在云上的 tsdb 或者对象存储、文件存储上。
  • 无限拓展:咱们有300+集群,几千节点,上万个服务,单机prometheus没法知足,且为了隔离性,最好按功能作 shard,如 master 组件性能监控与 pod 资源等业务监控分开、主机监控与日志监控也分开。或者按租户、业务类型分开(实时业务、离线业务)。
  • 全局视图:按类型分开以后,虽然数据分散了,但监控视图须要整合在一块儿,一个 grafana 里 n个面板就能够看到全部地域+集群+pod 的监控数据,操做更方便,不用多个 grafana 切来切去,或者 grafana中多个 datasource 切来切去。
  • 无侵入性:不要对已有的 prometheus 作过多的修改,由于 prometheus 是开源项目,版本也在快速迭代,咱们最先使用过 1.x,可1.x 和 2.x的版本升级也就不到一年时间,2.x 的存储结构查询速度等都有了明显提高,1.x 已经没人使用了。所以咱们须要跟着社区走,及时迭代新版本。所以不能对 prometheus 自己代码作修改,最好作封装,对最上层用户透明。

在调研了大量的开源方案(cortex/thanos/victoria/..)和商业产品以后,咱们选择了 thanos,准确的说,thanos只是监控套件,与 原生prometheus 结合,知足了长期存储+ 无限拓展 + 全局视图 + 无侵入性的需求。sql

thanos 架构

thanos 的默认模式:sidecar 方式docker


除了 这个sidecar 方式,thanos还有一种不太经常使用的reviver 模式,后面会提到。数据库

Thanos是一组组件,在官网上能够看到包括:json

  • Bucket
  • Check
  • Compactor
  • Query
  • Rule
  • Sidecar
  • Store

除了官方提到的这些,其实还有:后端

  • receive
  • downsample

看起来组件不少,但其实部署时二进制只有一个,很是方便。只是搭配不一样的参数实现不一样的功能,如 query 组件就是 ./thanos query,sidecar 组件就是./thanos sidecar,组件all in one,也就是代码也只有一份,体积很小。

其实核心的sidecar+query就已经能够运行,其余的组件只是为了实现更多的功能

最新版 thanos 在 这里下载release,对于 thanos这种仍然在修bug、迭代功能的软件,有新版本就不要用旧的。

组件与配置

下面会介绍如何组合thanos组件,来快速实现你的 prometheus 高可用,由于是快速介绍,和官方的 quick start有一部分雷同,且本文截止2020.1 月的版本,不知道之后会thanos 会迭代成什么样子

第 1 步:确认已有的 prometheus

thanos 是无侵入的,只是上层套件,所以你仍是须要部署你的 prometheus,这里再也不赘述,默认你已经有一个单机的 prometheus在运行,能够是 pod 也能够是主机部署,取决于你的运行环境,咱们是在 k8s 集群外,所以是主机部署。prometheus采集的是地域A的监控数据。你的 prometheus配置能够是:

启动配置:

"./prometheus
--config.file=prometheus.yml \
--log.level=info \
--storage.tsdb.path=data/prometheus \
--web.listen-address='0.0.0.0:9090' \
--storage.tsdb.max-block-duration=2h \
--storage.tsdb.min-block-duration=2h \
--storage.tsdb.wal-compression \
--storage.tsdb.retention.time=2h \
--web.enable-lifecycle"

web.enable-lifecycle必定要开,用于热加载reload你的配置,retention保留 2 小时,prometheus 默认 2 小时会生成一个 block,thanos 会把这个 block 上传到对象存储。

采集配置:prometheus.yml

global:
  scrape_interval:     60s
  evaluation_interval: 60s
  external_labels:
     region: 'A'
     replica: 0

rule_files:
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['0.0.0.0:9090']

  - job_name: 'demo-scrape'
    metrics_path: '/metrics'
    params:
    ...

这里须要声明external_labels,标注你的地域。若是你是多副本运行,须要声明你的副本标识,如 0号,1,2 三个副本采集如出一辙的数据,另外2个 prometheus就能够同时运行,只是replica值不一样而已。这里的配置和官方的 federation差很少。

对 prometheus 的要求:

  • 2.2.1版本以上
  • 声明你的external_labels
  • 启用--web.enable-admin-api
  • 启用--web.enable-lifecycle

第 2 步:部署 sidecar 组件

关键的步骤来了,最核心莫过于 sidecar组件。sidecar是 k8s 中的一种模式

Sidecar 组件做为 Prometheus server pod 的 sidecar 容器,与 Prometheus server 部署于同一个 pod 中。 他有两个做用:

  1. 它使用Prometheus的remote read API,实现了Thanos的Store API。这使后面要介绍的Query 组件能够将Prometheus服务器视为时间序列数据的另外一个来源,而无需直接与Prometheus API交互(这就是 sidecar 的拦截做用)
  2. 可选配置:在Prometheus每2小时生成一次TSDB块时,Sidecar将TSDB块上载到对象存储桶中。这使得Prometheus服务器能够以较低的保留时间运行,同时使历史数据持久且可经过对象存储查询。

固然,这不意味着Prometheus能够是彻底无状态的,由于若是它崩溃并从新启动,您将丢失2个小时的指标,不过若是你的 prometheus 也是多副本,能够减小这2h 数据的风险。

sidecar配置:

./thanos sidecar \
--prometheus.url="http://localhost:8090" \
--objstore.config-file=./conf/bos.yaml \
--tsdb.path=/home/work/opdir/monitor/prometheus/data/prometheus/
"

配置很简单,只须要声明prometheus.url和数据地址便可。objstore.config-file是可选项。若是你要把数据存放在对象存储(这也是推荐作法),就配置下对象存储的帐号信息。

thanos 默认支持谷歌云/AWS等,以 谷歌云为例,配置以下:

type: GCS
config:
  bucket: ""
  service_account: ""

由于thanos默认还不支持咱们的云存储,所以咱们在 thanos代码中加入了相应的实现,并向官方提交了 pr。

须要注意的是:别忘了为你的另外两个副本 1号 和 2号prometheus都搭配一个 sidecar。若是是 pod运行能够加一个 container,127 访问,若是是主机部署,指定prometheus端口就行。

另外 sidecar是无状态的,也能够多副本,多个 sidecar 能够访问一份 prometheus 数据,保证 sidecar自己的拓展性,不过若是是 pod 运行也就没有这个必要了,sidecar和prometheus 同生共死就好了。

sidecar 会读取prometheus 每一个 block 中的 meta.json信息,而后扩展这个 json 文件,加入了 Thanos所特有的 metadata 信息。然后上传到块存储上。上传后写入thanos.shipper.json 中

第 3 步:部署 query 组件

sidecar 部署完成了,也有了 3 个同样的数据副本,这个时候若是想直接展现数据,能够安装 query 组件

Query组件(也称为“查询”)实现了Prometheus 的HTTP v1 API,能够像 prometheus 的 graph同样,经过PromQL查询Thanos集群中的数据。

简而言之,sidecar暴露了StoreAPI,Query从多个StoreAPI中收集数据,查询并返回结果。Query是彻底无状态的,能够水平扩展。

配置:

"
./thanos query \
--http-address="0.0.0.0:8090" \
--store=relica0:10901 \
--store=relica1:10901 \
--store=relica2:10901 \
--store=127.0.0.1:19914 \
"

store 参数表明的就是刚刚启动的 sidecar 组件,启动了 3 份,就能够配置三个relica0、relica一、relica2,10901 是 sidecar 的默认端口。

http-address 表明 query 组件自己的端口,由于他是个 web 服务,启动后,页面是这样的:

和 prometheus 几乎同样对吧,有了这个页面你就不须要关心最初的 prometheus 了,能够放在这里查询。

点击 store,能够看到对接了哪些 sidecar。

query 页面有两个勾选框,含义是:

  • deduplication:是否去重。默认勾选表明去重,一样的数据只会出现一条,不然 replica0 和 一、2 彻底相同的数据会查出来 3 条。
  • partial response:是否容许部分响应,默认容许,这里有一致性的折中,好比 0、一、2 三副本有一个挂掉或者超时了,查询时就会有一个没有响应,若是容许返回用户剩下的 2 份,数据就没有很强的一致性,但由于一个超时就彻底不返回,就丢掉了可用性,所以默认容许部分响应。

第 4 步:部署 store gateway 组件

你可能注意到了,在第 3 步里,./thanos query有一条--store是 xxx:19914,并非一直提到的 3 副本,这个 19914 就是接下来要说的store gateway组件。

在第 2 步的 sidecar 配置中,若是你配置了对象存储objstore.config-file,你的数据就会定时上传到bucket 中,本地只留 2 小时,那么要想查询 2 小时前的数据怎么办呢?数据不被 prometheus 控制了,应该如何从 bucket 中拿回来,并提供如出一辙的查询呢?

Store gateway 组件:Store gateway 主要与对象存储交互,从对象存储获取已经持久化的数据。与sidecar同样,Store gateway也实现了store api,query 组能够从 store gateway 查询历史数据。

配置以下:

./thanos store \
--data-dir=./thanos-store-gateway/tmp/store \
--objstore.config-file=./thanos-store-gateway/conf/bos.yaml \
--http-address=0.0.0.0:19904 \
--grpc-address=0.0.0.0:19914 \
--index-cache-size=250MB \
--sync-block-duration=5m \
--min-time=-2w \
--max-time=-1h \

grpc-address就是store api暴露的端口,也就是query 中--store是 xxx:19914的配置。

由于Store gateway须要从网络上拉取大量历史数据加载到内存,所以会大量消耗 cpu 和内存,这个组件也是 thanos 面世时被质疑过的组件,不过当前的性能还算能够,遇到的一些问题后面会提到。

Store gateway也能够无限拓展,拉取同一份 bucket 数据。

放个示意图,一个 thanos 副本,挂了多个地域的 store 组件

到这里,thanos 的基本使用就结束了,至于 compact 压缩和 bucket 校验,不是核心功能,compact咱们只是简单部署了一下,rule组件咱们没有使用,就不作介绍了。

5.查看数据

有了多地域多副本的数据,就能够结合 grafana 作全局视图了,好比:

按地域和集群查看 etcd 的性能指标:

按地域、集群、机器查看核心组件监控,如多副本 master 机器上的各类性能

数据聚合在一块儿以后,能够将全部视图都集中展现,好比还有这些面板:

  • 机器监控:node-exporter、process-exporter
  • pod 资源使用: cadvisor
  • docker、kube-proxy、kubelet 监控
  • scheduler、controller-manager、etcd、apiserver 监控
  • kube-state-metrics 元信息
  • k8s events
  • mtail 等日志监控

Receive 模式

前面提到的全部组件都是基于 sidecar 模式配置的,但thanos还有一种Receive模式,不太经常使用,只是在Proposals中出现

由于一些网络限制,咱们以前尝试过Receive方案,这里能够描述下Receive的使用场景:

  1. sidecar 模式有一个缺点:就是2 小时内的数据仍然须要经过 sidecar->prometheus来获取,也就是仍然依赖 prometheus,并非彻底的数据在外部存储。若是你的网络只容许你查询特定的存储数据,没法达到集群内的prometheus,那这 2 小时的数据就丢失了,而 Receive模式采用了remote write 就没有所谓的 2 小时 block 的问题了。
  2. sidecar 模式对网络连通性是有要求的,若是你是多租户环境或者是云厂商,对象存储(历史数据)query 组件通常在控制面,方便作权限校验和接口服务封装,而 sidecar 和 prometheus却在集群内,也就是用户侧。控制面和用户侧的网络有时候会有限制,是不通的,这个时候会有一些限制致使你没法使用 sidecar
  3. 租户和控制面隔离,和第2 条相似,但愿数据彻底存在控制面,我一直以为Receive就是为了云厂商服务的。。

不过Receive毕竟不是默认方案,若是不是特别须要,仍是用默认的 sidecar 为好

一些问题

prometheus 压缩

压缩:官方文档有提到,使用sidecar时,须要将 prometheus 的--storage.tsdb.min-block-duration 和 --storage.tsdb.max-block-duration,这两个值设置为2h,两个参数相等才能保证prometheus关闭了本地压缩,其实这两个参数在 prometheus -help 中并无体现,prometheus 做者也说明这只是为了开发测试才用的参数,不建议用户修改。而 thanos 要求关闭压缩是由于 prometheus 默认会以2,25,25*5的周期进行压缩,若是不关闭,可能会致使 thanos 刚要上传一个 block,这个 block 却被压缩中,致使上传失败。

不过你也没必要担忧,由于在 sidecar 启动时,会坚持这两个参数,若是不合适,sidecar会启动失败
43a131c689d9fedba5a7844363876ee7

store-gateway

store-gateway: store 组件资源消耗是最大的,毕竟他要拉取远程数据,并加载到本地供查询,若是你想控制历史数据和缓存周期,能够修改相应的配置,如

--index-cache-size=250MB \
--sync-block-duration=5m \ 
--min-time=-2w \ 最大查询 1 周
--max-time=-1h \

store-gateway 默认支持索引缓存,来加快tsdb 块的查找速度,但有时候启动会占用了大量的内存,在 0.11.0以后的版本作了修复,能够查看这个issue

Prometheus 2.0 已经对存储层进行了优化。例如按照时间和指标名字,连续的尽可能放在一块儿。而 store gateway能够获取存储文件的结构,所以能够很好的将指标存储的请求翻译为最少的 object storage 请求。对于那种大查询,一次能够拿成百上千个 chunks 数据。

二在 store 的本地,只有 index 数据是放入 cache的,chunk 数据虽然也能够,可是就要大几个数量级了。目前,从对象存储获取 chunk 数据只有很小的延时,所以也没什么动力去将 chunk 数据给 cache起来,毕竟这个对资源的需求很大。

store-gateway中的数据:

每一个文件夹中实际上是一个个的索引文件index.cache.json

compactor组件

prometheus数据愈来愈多,查询必定会愈来愈慢,thanos提供了一个compactor组件来处理,他有两个功能,

  • 一个是作压缩,就是把旧的数据不断的合并。
  • 另一个是降采样,他会把存储的数据,按照必定的时间,算出最大,最小等值,会根据查询的间隔,进行控制,返回采样的数据,而不是真实的点,在查询特别长的时间的数据的时候,看的主要是趋势,精度是能够选择降低的。
  • 注意的是compactor并不会减小磁盘占用,反而会增长磁盘占用(作了更高维度的聚合)。

经过以上的方式,有效了优化查询,可是并非万能的。由于业务数据总在增加,这时候可能要考虑业务拆分了,咱们须要对业务有必定的估算,例如不一样的业务存储在不一样bucket里(须要改造或者多部署几个 sidecar)。例若有5个bucket,再准备5个store gateway进行代理查询。减小单个 store 数据过大的问题。

第二个方案是时间切片,也就是就是上面提到的store gateway能够选择查询多长时间的数据。支持两种表达,一种是基于相对时间的,例如--max-time 3d前到5d前的。一种是基于绝对时间的,19年3月1号到19年5月1号。例如想查询3个月的数据,一个store代理一个月的数据,那么就须要3个store来合做。

query 的去重

query组件启动时,默认会根据query.replica-label字段作重复数据的去重,你也能够在页面上勾选deduplication 来决定。query 的结果会根据你的query.replica-label的 label选择副本中的一个进行展现。可若是 0,1,2 三个副本都返回了数据,且值不一样,query 会选择哪个展现呢?

thanos会基于打分机制,选择更为稳定的 replica 数据, 具体逻辑在:https://github.com/thanos-io/...

参考

本文为容器监控实践系列文章,完整内容见:container-monitor-book

相关文章
相关标签/搜索