Prometheus Cortex架构概述(水平可扩展、高可用、多租户、长期存储)

2022-05-10 00:00:00 查询 数据 多个 请求 租户

Cortex包含一系列可水平扩展的微服务。每个微服务采用了合适的技术来实现水平拓展;大部分是无状态的,可以处理任意用户的请求,也有一些如ingesters则是半有状态的,依赖一致性哈希。这篇文档提供了Cortex的架构概览。



Prometheus的角色
Prometheus从监控目标获取样本,并通过remote_write API推送给Cortex。该API通过HTTP push请求的body,发出批量的Snappy压缩的Protocol buffers(Protocol Buffers | Google Developers)消息。

Cortex要求每个HTTP请求都带有一个指定租户ID的header。请求的验证和授权由外部的反向代理处理。

传入的样本(来自的Prometheus)由distributor处理,传入的读请求(来自PromQL查询)则由querier或者query frontend处理。

存储
Cortex目前支持两种存储引擎,来存储和查询时序数据:

Chunks(已弃用)
Blocks
两种存储引擎共享相同的Cortex架构,些微的差别在后续部分列出。

Chunks storage(已弃用)
Chunks存储将每一时间序列存入一个称为Chunk的对象中。每个Chunk包含一个指定时间段的样本(默认为12h)。Chunk使用时间范围及标签进行索引,以实现大量Chunk(百万级)的快速查询。

因此,chunk存储包括:

索引,支持:
Amazon DynamoDB
Google Bigtable
Apache Cassandra
对象存储,支持:
Amazon DynamoDB
Google Bigtable
Apache Cassandra
Amazon S3
Google Cloud Storage
Microsoft Azure Storage
Block存储
Block存储基于Prometheus TSDB:它将每个租户的时间序列存储在各自的TSDB中,TSDB将这些序列写入磁盘上的Block(默认时间范围为2h)。每个Block由存储chunks和block索引的多个文件构成。

TSDB chunk文件包含多个序列的样本。这些Chunk中的序列由一个block级别的index进行索引,索引通过chunk文件中的指标名称及标签建立。

Block存储无需专用的存储后端来存储索引,只需要一个存储Block文件的对象存储,支持:

Amazon S3
Google Cloud Storage
Microsoft Azure Storage
OpenStack Swift (实验性)
Local Filesystem (仅支持单节点)
Services
Cortex拥有一个基于服务的架构,整个系统被分为多个执行不同任务的组件。这些组件独立的并行运行。Cortex也可以运行在单进程模式下,即所有的组件在一个进程中执行。单进程模式可以方便地用于本地测试及开发。

Cortex的是一个无共享系统(大部分)。系统每一层的每个组件可以运行多个实例,层中的多个组件之间无需关联或通信。

Cortex的服务包括:

Distributor
Ingester
Querier
Query frontend (可选)
Ruler (可选)
Alertmanager (可选)
Configs API (可选)
Distributor
Distributor服务负责处理Prometheus传入的采样数据。这是数据写入路径的站。Distributor在接收到采样后,会验证每个采样的正确性,并确保它在配置的租户范围内,如果不在指定的租户范围内,则返回默认值。已验证的样本将被分批并行地发送给ingesters。

Distributor的验证内容包括:

指标的标签名形式正确
指标的标签数遵守配置的大值
标签的名称和值遵守配置的大长度
时间戳在配置的小/大实践范围内
Distributor是无状态的,可以根据需要进行伸缩。

High Availability Tracker
Distributor拥有一个High Availability Tracker特性。如果启用了该特性,Distributor将从冗余的Prometheus传入的样本中的剔除重复数据。这一特性将允许我们部署多个Prometheus HA副本,将相同的序列写入Cortex,然后在Distributor中剔除重复的数据。

HA Tracker根据集群和副本标签剔除传入的重复样本。集群标签标识特定租户的冗余Prometheus服务器集群,而副本标签标识Prometheus集群内的副本。如果传入的样本由集群中不是当前主节点的任何副本发送,则将其视为重复样本(并因此丢弃)。

HA Tracker需要键值(Key/Value)存储来协调当前选择的副本。Distributor将只接受来自当前leader的样本。带有一个标签或者没有副本和集群标签的样本默认被接受,并且不进行重复数据剔除。
HA Tracker支持的KV存储包括:

consul
Etcd
注意:不支持memberlist。基于memberlist的KV store使用gossip传播更新,这对于HA来说非常缓慢:结果是不同的Distributor可能会将不同的Prometheus服务器视为选定的HA副本,这显然是不可取的。

Prometheus侧的配置可以参考:Config for sending HA Pairs data to Cortex | Cortex (cortexmetrics.io)

Hashing
Distributor使用一致性哈希,连同一个可配置的复制因子(replication_factor)来决定哪一个ingester实例应该接收给定的序列。

Cortex支持两种哈希策略:

哈希指标名称和租户ID(默认)
哈希指标名称、标签和租户ID(通过-distributor.shard-by-all-labels=true参数启用)
后一种策略会使写入在多个ingester之间更加均衡,但同时也会造成每个查询都需要与所有ingester交互,因为拥有不同标签集的指标可能回分布在多个ingester中。

Hashing ring
哈希环(存储在KV存储中)用于实现ingesters间序列分片和复制的哈希一致性。所有的ingester都使用自己拥有的一组token将自己注册到哈希环中;每个token都是一个随机的32位无符号数字。每个传入的序列在Distributor中计算哈希值,然后推送给拥有序列哈希值范围token的ingester及环中后续N-1个ingester,其中N为replication_factor的值。

为了进行哈希查找,Distributor会找到一个小合适的token,且其值大于等于序列的哈希值。如果replication_factor值大于1,则后续N-1个(哈希环中顺时针方向)属于不同ingester的token,也会被包含在结果当中。

这种哈希配置的效果是,每个ingesters拥有的token负责处理某些范围内的哈希。例如有三个值为0,25,50的token,那么值为3的哈希将会被分发给token值为25(判断方式为:小且大于等于3)的ingester;即token值为25的ingester负责处理值在1-25内的哈希。

哈希环支持的KV存储包括:

Consul
Etcd
Gossip memberlist
仲裁一致性
由于所有的Distributor共享相同的哈希环,因此可以将写请求发送到任一Distributor上,因此可以在Distributor前配置无状态负载均衡器。

为了确保查询结果的一致性,Cortex在读写操作上使用Dynamo风格的仲裁一致性。这意味着,在成功响应Prometheus写入请求之前,将等待一半加一数量的ingester(1/2*选中的ingester数+1)发来正确响应。

Distributor间的负载均衡
我们建议在distributor实例间随机分发写请求。例如,如果在Kubernetes集群中运行Cortex,可以以Service形式运行Distributor。

Ingester
Ingester服务在写路径上负责将Distributor传入的序列写入长期存储后端,在读路径上负责返回查询出的内存中的采样数据。

传入的序列不会立刻写入到存储中,而是会先保存在内存中,然后定期刷新到存储中(chunk默认12h,block默认2h)。因此,queriers在读路径上执行查询时可能需要同时从后端存储及ingester中获取数据。

Ingesters包含一个lifecycler用来管理ingester的生命周期及存储ingester的状态到哈希环中。每个ingester可能处在如下状态中:

PENDING:ingester刚刚启动。在此状态下,ingester不会接收到任何读写请求。但如果使用了chunk存储并启用了hand-over(Chunks storage with WAL disabled (hand-over)),则可能是在等待其它ingester向其传输时序数据。
JOINING:ingester已经启动,正在加入哈希环。在此状态下,ingester不会接收到任何读写请求。如果启用了hand-over,ingester将使用已脱离环的ingester的token加入哈希环,否则将从磁盘中加载token(如果通过-ingester.tokens-file-path指定了路径)或者生成一个随机的新token。
ACTIVE:ingester已启动并在运行。此状态下,ingester可以接收读写请求。
LEAVING:ingester正在关闭并离开哈希环。在此状态下ingester不会接收任何写请求,但可能会接收读请求。
UNHEALTHY:ingester未能向环的KV存储发送心跳信号,在此状态下,distributor在创建分发集时会跳过该ingester,并且ingester不会接收到任何读写请求。
ingester状态在Cortex内部有多种用途,包括由chunk storage支持的序列hand-over过程。更多信息可参看Chunks storage with WAL disabled (hand-over)

ingester是半有状态的。

Ingester崩溃及数据丢失
如果ingester进程崩溃或突然退出,则在内存中尚未刷新到长期存储的数据将会丢失。有两种主要的方式来缓解此故障:

Replication
Write-ahead log(WAL)
Replication用于在ingesters中保存时序的多个副本(通常为3副本)。如果Cortex集群丢失了一个ingester,则配置了副本的情况下,丢失的ingester内存中保存的数据同时也被复制到其他至少一个ingester中,因此数据不会丢失。只有所有保存相同时序的ingester同时发生故障,数据才可能丢失。

WAL用于将所有传入的数据写入持久化磁盘中,知道数据被刷新到长期存储中。如果一个ingester发生故障,随后重启的进程将读取WAL并恢复原先内存中的数据。

与Replication不同的是,加入持久化磁盘上的数据没有丢失,那么即使多个ingester同时发生故障,重启后也可以恢复内存中的数据。但仍然推荐使用Replication以防止在某个ingester崩溃时读路径出现临时性的故障。

Chunk存储的WAL默认被禁用,但block存储则总是启用WAL。

Ingester的写去放大(write de-amplification)
Ingester将近接收到的数据存储在内存中,以便执行写“去放大”。如果ingester立即将接收到的数据写入长期存储中,那么系统将会变得非常难以扩展,因为存储的压力会变得很大。因此,ingester会将内存中的数据进行批处理和压缩,然后定期刷新到存储中。

写去放大是Cortex拥有低“总拥有成本”(TCO, total cost of ownership)的主要原因。

Querier
querier服务负责处理PromQL查询请求。

Querier从存储及ingester(因为ingester内存中有尚未刷新到存储中额数据)中获取数据。由于复制因子(replication factor)的存在,querier可能会获取到重复的数据,因此,querier还会对数据进行去重(删除相同时间戳的数据)。

Querier是无状态的,可根据需要进行伸缩。

Query frontend
Query frontend是一个可选服务,提供Querier的API端点,可用于加入读路径。当部署了query frontend时,查询请求应被定向到query frontend而不是querier。集群中仍然需要querier来执行真正的查询。

Query frontend在内部执行一些查询调整,并将查询保存在内部队列中。在此设置下,queriers充当工人,从队列中提取作业、执行作业,并将作业结果返回query frontend进行聚合。Querier需要通过参数 -querier.frontend-address配置query frontend的地址。

query frontend是无状态的。但是,由于内部队列的工作方式,建议运行一些副本以获得公平调度的好处。在大多数情况下,两个副本就足够了。

当使用query frontend时查询流程如下:

Query frontend接收到查询请求,对其进行拆分或从缓存中提供数据。
Query frontend将查询存入内存队列中,并等待querier提取查询。
Querier提取查询,并执行查询。
Querier将结果返回给Query frontend,Query frontend再将结果返回给客户端。
Queueing
Query frontend的队列机制用于:

确保可能导致querier OOM(out of memory)的大型查询,在失败时被重试。这允许管理员为querier提供较低内存,或者进而选择并行地运行更多的小查询,这有助于降低TCO。
通过使用先进先出队列(FIFO)将多个大型查询分发到多个querier上,防止所有大型查询运行在单个querier上。
通过公平地安排租户的查询,防止因为单个租户的问题使得无法为其他租户提供服务。
Splitting
Query frontend会将跨多天的查询拆分为多个单日查询,在querier中并行执行,并将返回的结果重新聚合。这可以防止大型查询造成单个querier OOM(out of memory),并加快查询速度。

Caching
Query frontend支持缓存查询结果,并在后续的查询中重用。如果缓存的结果不完整,query frontend将计算所需的子查询,然后在querier中并行执行。Query frontend可以启用align_queries_with_step参数,以提高查询结果的可缓存性。查询缓存可与任何Cortex缓存后端(如memcached、redis和in-memory cache)兼容。

Query Scheduler
Query Scheduler是一个可选服务,负责将内部队列从query frontend移动到独立组件中。这使得我们可以独立地扩展query frontend和队列(query scheduler)的数量。

如果使用了query scheduler,则query frontend和querier均需指定query scheduler的地址。(通过参数-frontend.scheduler-address和-querier.scheduler-address)。

当使用了query scheduler后,查询流程变为:

query frontend接收到查询请求,对其进行拆分或从缓存中提供数据。
query frontend将请求转发给随机的query scheduler进程。
query scheduler将查询存入内存队列中,然后等待querier来提取查询。
querier提取查询并执行。
querier将查询结果返回给query frontend,随后query frontend将结果返回给客户端。
Query Scheduler是无状态的,推荐运行2副本,已保证一个副本重启时仍能提供查询服务。

Ruler
Ruler是一个可选服务,用于执行recording rules和alert的PromQL查询。Ruler需要一个数据库来存储每个租户的recording rules和alert。

Ruler是一个半有状态服务,可以水平扩展。Ruler的有状态部分主要表现在,内存运行中的rule和ruler初始化环是有状态的。如果所有的Ruler都崩溃重启了,Prometheus拥有一项特性,即如果alert在其有效期内且处于active状态,则该alert将被恢复并返回到触发状态。但是,recording rules生成的序列将会有中断。

Alertmanager
Alertmanager是一个可选服务,负责接收来自ruler的告警消息,对其进行去重和分组,并路由到正确的通知通道如如Email、PagerDuty或OpsGenie。

Cortex的Alertmanager基于Prometheus Alertmanager构建,并增加了多租户支持。与Ruler一样,Alertmanager也需要一个数据库来存储每个租户的配置。

Alertmanager是半有状态的。Alertmanager将静默及active告警信息持久化到本地磁盘。如果所有的Alertmanager同时发生故障,则可能会丢失数据。

Configs API
Configs API是一个可选服务,用于管理Ruler和Alertmanager的配置,提供了获取、修改、更新ruler和alertmanager配置的API,并能将这些配置存入后端。目前支持的后端为PostgreSQL和本地内存。

Configs API是无状态的。

总结
各个组件的作用总结如下:

Distributor:收集数据,进行验证并分发给Ingester
Ingester:缓存接收到的数据到内存,并定期刷新进存储。
Querier:执行查询语句,从存储及Ingester内存中获取数据。
Query frontend (可选):拆分查询请求,分发查询请求到querier,并缓存查询结果。
Query Scheduler(可选):缓存查询队列。
Ruler (可选):执行rules查询(包括recording rules和alerts)。
Alertmanager (可选):处理告警信息。
Configs API (可选):管理Ruler和Alertmanager配置。
————————————————
版权声明:本文为CSDN博主「洒满阳光的午后」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sinat_32582203/article/details/121335978

相关文章