Thanos设计简析

Thanos设计简析

Thanos是一个实现高可用和长时间存储prometheus方案的组件合集。其主要目标是操作简单并保留prometheus的高可靠性。
Prometheus的指标数据模型和其2.0的TSDB存储格式是Thanos各组件的基础,参见: prometheus/TSDB磁盘格式

架构

Thanos包括了多种目的的集群组件,分类为:

  • Metric sources(Data sources)
  • Stores
  • Queries

Data sources

数据取回

Data sources通过gRPC接口从集群后端存储里获取指标数据,并返回给对应的客户。
Thanos提供了两种组件作为 Data sources:the Prometheus sidecarrule nodes
Sidecar在prometheus的HTTP remote-read APIs基础上实现了gRPC服务获取指标数据。
Rule node则直接在prometheus的存储引擎API基础上实现了gRPC服务获取指标数据。

数据备份

Data sources基于Prometheus 2.0存储引擎实现长期数据存储。存储引擎周期产生固定时间段的持久化block。一个block包含该时间段的所有series和samples数据以及一些索引文件用于快速查询,其结构如下:

01BX6V6TY06G5MFQ0GPH7EMXRH
├── chunks
│   ├── 000001
│   ├── 000002
│   └── 000003
├── index
└── meta.json

一个block最上层是一个类似UUID的字符串,它将目录的创建时间进行了编码,并按字典序进行了排序。目录里的文件包括:

  • chunks文件每个512MB,保存series的sample数据,每个chunk里每个series数据都在一起并且严格对齐。
  • index文件用于根据label查询series以及其在chunk中的位置信息。
  • meta.json保存元数据信息,包括统计信息、时间范围和compaction level级别。

这些block文件可以备份到对象存储上并在后续用于其他组件的查询。当block被存储引擎创建之后,立即被上传到对象存储。在Sidecar上传时会修改meta.json文件,增加thanos区段,用于记录thanos自定义的元数据信息。目前主要是有一个外部标签用于标识block的生产者,用于查询时过滤相关的block。

┌────────────┬─────────┐         ┌────────────┬─────────┐     ┌─────────┐
│ Prometheus │ Sidecar │   ...   │ Prometheus │ Sidecar │     │   Rule  │
└────────────┴────┬────┘         └────────────┴────┬────┘     └┬────────┘
                  │                                │           │
                Blocks                           Blocks      Blocks
                  │                                │           │
                  v                                v           v
              ┌──────────────────────────────────────────────────┐
              │                   Object Storage                 │
              └──────────────────────────────────────────────────┘

Stores

Stores是一个gateway角色用于访问对象存储bucket里的block数据。它提供了和Data sources一样的gRPC API去获取block里所有的指标数据。
Stores持续的同步对象存储里写入的block信息,并将指标查询请求转换为对象存储的请求。它实现多种策略来降低对对象存储的访问频率,包括根据元数据信息过滤block,缓存高频访问的index文件等。
Prometheus 2.0存储引擎设计时为了降低读放大做了优化。如:同一个series的指标数据在chunk里是连续和对齐的,以及:具有相同指标名的series也是对齐的。Store node利用这些特性去降低查询时访问对象存储的请求数。每次请求可能访问多大上十万个chunk,这对降低访问次数以满足更大的查询请求来说是非常必要的。
目前只有index文件会被缓存,chunk也可以被缓存,但它要大几个数量级,并且目前获取chunk所消耗的时间在端到端查询中占比不大,因此chunk目前没有必要进行缓存以降低store node的资源消耗。

Stores & Data sources

因为Stores和Data sources实现了一样的gRPC store API,因此客户端可以把他们看成一样的,查询的时候不用在乎连接哪个组件。
每个store API的提供者也提供了元数据信息用于描述它所能提供的数据,因此客户端可以据此最小化查询的nodes来满足特定的数据查询。
本质上,store API提供了根据label matchers (PromQL)和时间范围去过滤查找数据的能力。它提供简单的数据查找返回接口,返回找到的block内压缩的chunk数据,并且不提供复杂的查询语句执行。

┌──────────────────────┐  ┌────────────┬─────────┐   ┌────────────┐
│ Google Cloud Storage │  │ Prometheus │ Sidecar │   │    Rule    │
└─────────────────┬────┘  └────────────┴────┬────┘   └─┬──────────┘
                  │                         │          │
         Block File Ranges                  │          │
                  │                     Store API      │
                  v                         │          │
                ┌──────────────┐            │          │
                │     Store    │            │      Store API
                └────────┬─────┘            │          │
                         │                  │          │
                     Store API              │          │
                         │                  │          │
                         v                  v          v
                       ┌──────────────────────────────────┐
                       │              Client              │
                       └──────────────────────────────────┘

Querier

Querier是无状态的,支持水平扩展,它基于集群中提供的store API实现了PromQL接口。Querier也参与集群中,用于获取集群中的data sources和store nodes。 同时query nodes也能被rule nodes发现用于评估聚合和告警规则。
基于data sources和store nodes提供的元数据,query node最小化查询提供store API的服务,以满足特定的查询请求。

┌──────────────────┐  ┌────────────┬─────────┐   ┌────────────┐
│    Store Node    │  │ Prometheus │ Sidecar │   │    Rule    │
└─────────────┬────┘  └────────────┴────┬────┘   └─┬──────────┘
              │                         │          │
              │                         │          │
              │                         │          │
              v                         v          v
        ┌─────────────────────────────────────────────────────┐
        │                      Query layer                    │
        └─────────────────────────────────────────────────────┘
                ^                  ^                  ^
                │                  │                  │
       ┌────────┴────────┐  ┌──────┴─────┐       ┌────┴───┐
       │ Alert Component │  │ Dashboards │  ...  │ Web UI │
       └─────────────────┘  └────────────┘       └────────┘

Compactor

Compactor它是一个单独的组件,不参与到Thanos集群中,即不跟其他组件发生联系。它专注于对象存储里的某个bucket进行block的合并。类似于Prometheus存储引擎的compactor,它的目的是降低存储空间,减少store node的查询次数和负载。
Compactor的另一个工作是block过期删除,以及down-sampling降精度。

Scaling

Thanos的任何组件都没有提供sharding,只有query nodes因为无状态是明确可以任意扩展的,存储能力的扩展则依赖外部的对象存储系统。
store, rule 和compactor节点通过新增单节点或者主备节点对来进行显示扩展。和Prometheus类似,sharding分片功能通常并没有存在的必要。
例如,rule规则可以分散配置到多个rule节点。store节点也可以通过配置为专门的区域/数据中心的bucket从而无需实现分片能力。
总之,分片方式的水平扩展能力虽然很好,但暂时不是Thanos考虑的重点,因为这样的场景不多。

Cost

Thanos引入的额外消耗包括存储和查询对象存储系统,以及store节点的运行消耗。
Queriers、compactors和rule节点则没有额外引入消耗,因为这些事情在原有的Prometheus上也需要。
数据从Prometheus传输到Thanos上引入了额外的网络消耗。

参考

https://thanos.io/tip/thanos/design.md

posted @ 2020-11-13 17:07  舰队  阅读(814)  评论(0编辑  收藏  举报