配置 Grafana Pyroscope shuffle sharding
Grafana Pyroscope 利用 sharding 在单租户和多租户集群中横向扩展,使其容量超出单个节点的限制。
背景
Grafana Pyroscope 使用一种 sharding 策略,将工作负载分布在运行给定组件的部分实例上。例如,在写入路径上,每个租户的系列会被 sharded 到部分 ingester 上。此子集的大小(即实例数)通过 shard size
参数配置,默认为 0
。此默认值意味着每个租户使用所有可用实例,以便公平地平衡 CPU 和内存使用等资源,并最大化这些资源在集群中的利用率。
在多租户集群中,此默认值 (0
) 会带来以下缺点:
- 一次中断会影响所有租户。
- 某个行为异常的租户(例如,导致内存不足错误的租户)可能会对所有其他租户产生负面影响。
将 shard size 值配置为大于 0
可启用 shuffle sharding。shuffle sharding 的目标是减小中断的影响范围并更好地隔离租户。
关于 shuffle sharding
Shuffle sharding 是一种隔离不同租户工作负载的技术,即使它们运行在共享集群中,也能为每个租户提供单租户体验。有关 AWS 如何描述 shuffle sharding 的更多信息,请参阅 什么是 shuffle sharding?。
Shuffle sharding 为每个租户分配一个 shard,该 shard 由 Grafana Pyroscope 实例的子集组成。此技术可最大程度地减少两个租户之间重叠的实例数。Shuffle sharding 提供了以下优点:
- 某些 Grafana Pyroscope 集群实例或节点的中断仅影响部分租户。
- 行为异常的租户仅影响其 shard 实例。假设每个租户 shard 相对于集群中的总实例数而言相对较小,则任何其他租户很可能运行在不同的实例上,或者只有一部分实例与受影响的实例匹配。
使用 shuffle sharding 不需要更多资源,但可能导致实例不均衡。
低重叠实例概率
例如,在一个运行 50 个 ingester 且为每个租户分配 50 个 ingester 中四个的 Grafana Pyroscope 集群中,通过在每个租户之间 shuffling 实例,可能组合的数量为 23 万。
随机选取两个租户会产生以下概率:
- 它们不共享任何实例的概率为 71%
- 它们仅共享 1 个实例的概率为 26%
- 它们共享 2 个实例的概率为 2.7%
- 它们共享 3 个实例的概率为 0.08%
- 它们的实例完全重叠的概率为 0.0004%
Grafana Pyroscope shuffle sharding
Grafana Pyroscope 在以下组件中支持 shuffle sharding:
使用默认配置运行 Grafana Pyroscope 时,shuffle sharding 是禁用的,您需要通过全局或针对给定租户增加 shard size 来明确启用它。
注意:如果 shard size 值等于或高于可用实例数(例如,当
-distributor.ingestion-tenant-shard-size
高于 Grafana Pyroscope 集群中的 ingester 数时),则 shuffle sharding 将被禁用,并再次使用所有实例。
有保证的属性
Grafana Pyroscope shuffle sharding 实现提供以下优点:
- 稳定性
给定 hash ring 的一致状态,shuffle sharding 算法始终为给定租户选择相同的实例,即使在不同的机器上也是如此。 - 一致性
从 hash ring 中添加或移除实例最多只导致每个租户 shard 中一个实例发生更改。 - Shuffle
从概率上来说,对于足够大的集群,shuffle sharding 确保每个租户接收到不同的实例集,并减少两个租户之间重叠的实例数,从而改善故障隔离。
Ingester shuffle sharding
默认情况下,Grafana Pyroscope distributor 将接收到的 series 分配给所有运行的 ingester。
启用 ingester shuffle sharding 时,写入路径上的 distributor 将每个租户 series 分配给 -distributor.ingestion-tenant-shard-size
个 ingester,而在读取路径上,querier 仅查询持有给定租户 series 的 ingester 子集。
可以通过在运行时配置的 overrides 部分设置 ingestion_tenant_shard_size
,在每个租户基础上覆盖 shard size。
Ingester 写入路径
要在写入路径上为 ingester 启用 shuffle sharding,请在 distributor、ingester 和 ruler 上配置以下 flags(或其相应的 YAML 配置选项):
-distributor.ingestion-tenant-shard-size=<size>
<size>
:设置每个租户 series 应 sharded 到多少个 ingester。如果<size>
为0
或大于 Grafana Pyroscope 集群中可用 ingester 的数量,则租户 series 将 sharded 到所有 ingester 上。
Ingester 读取路径
假设您已为写入路径启用 shuffle sharding,要在读取路径上为 ingester 启用 shuffle sharding,请在 querier 上配置以下 flags(或其相应的 YAML 配置选项):
-distributor.ingestion-tenant-shard-size=<size>
默认情况下,已正确设置以下 flag,以便在读取路径上为 ingester 启用 shuffle sharding。如果您需要修改其默认值:
-querier.shuffle-sharding-ingesters-enabled=true
读取路径上的 ingester shuffle sharding 可以明确启用或禁用。- 如果启用 shuffle sharding,querier 将从所需的最小 ingester 集中获取内存中的 series,仅选择自“现在 -
-blocks-storage.tsdb.retention-period
”以来可能接收过 series 的 ingester。否则,请求会发送到所有 ingester。
- 如果启用 shuffle sharding,querier 将从所需的最小 ingester 集中获取内存中的 series,仅选择自“现在 -
如果您仅为写入路径启用 ingester shuffle sharding,则读取路径上的 querier 始终查询所有 ingester,而不是查询属于该租户 shard 的 ingester 子集。仅在写入路径上启用 ingester shuffle sharding 不会导致查询结果不正确,但可能会增加查询延迟。
rollout 策略
如果您运行的 Grafana Pyroscope 集群禁用了 shuffle sharding,并且想要为 ingester 启用它,请使用以下 rollout 策略以避免遗漏查询 ingester 中当前存在的任何 series:
- 通过
-querier.shuffle-sharding-ingesters-enabled=false
明确禁用读取路径上的 ingester shuffle-sharding,因为此选项默认是启用的。 - 在写入路径上启用 ingester shuffle sharding。
- 通过
-querier.shuffle-sharding-ingesters-enabled=true
在读取路径上启用 ingester shuffle-sharding。
限制:减少租户 shard size
Grafana Pyroscope 中当前的 shuffle sharding 实现有一个限制,当您在读取路径上启用 ingester shuffle sharding 时,它阻止您安全地减少租户 shard size。
如果租户的 shard size 减小,querier 当前无法知道之前租户 shard 有多大,因此它们可能会遗漏持有该租户数据的 ingester。用于选择自“现在 - -blocks-storage.tsdb.retention-period
”以来可能接收过 series 的 ingester 的 blocks-storage.tsdb.retention-period
,如果租户 shard size 减小,则无法正确找到租户 shard。
尽管不支持减少租户 shard size,但请考虑以下权宜之计:
- 通过
-querier.shuffle-sharding-ingesters-enabled=false
禁用读取路径上的 shuffle sharding。 - 减少配置的租户 shard size。
- 等待至少
-blocks-storage.tsdb.retention-period
指定的时间。 - 通过
-querier.shuffle-sharding-ingesters-enabled=true
重新启用读取路径上的 shuffle sharding。
Query-frontend 和 query-scheduler shuffle sharding
默认情况下,所有 Grafana Pyroscope querier 都可以为任何租户执行查询。
当您通过将 -query-frontend.max-queriers-per-tenant
(或其相应的 YAML 配置选项)设置为大于 0
且小于可用 querier 数量的值来启用 shuffle sharding 时,仅指定数量的 querier 有资格为给定租户执行查询。
请注意,此分配发生在 query-frontend 中,如果使用 query-scheduler,则在 query-scheduler 中发生。使用 query-scheduler 时,必须为 query-scheduler 组件设置 -query-frontend.max-queriers-per-tenant
选项。当您不使用 query-frontend(无论是否使用 query-scheduler)时,此选项不可用。
您可以通过在运行时配置的 overrides 部分设置 max_queriers_per_tenant
,在每个租户基础上覆盖最大 querier 数量。
“死亡查询”的影响
如果租户发送了一个导致 querier 崩溃的“死亡查询”,则崩溃的 querier 将从 query-frontend 或 query-scheduler 断开连接,并立即将另一个正在运行的 querier 分配给该租户的 shard。
如果该租户重复发送此查询,则分配给该租户 shard 的新 querier 也会崩溃,然后又会将另一个 querier 分配给该 shard。这种级联故障可能会导致所有正在运行的 querier 逐个崩溃,从而使 shuffle sharding 包含死亡查询影响范围的假设失效。
为了缓解这种负面影响,有一些实验性配置选项,允许您配置 querier 因崩溃断开连接到崩溃的 querier 被健康的 querier 替换之间的时间延迟。配置时间延迟后,重复发送“死亡查询”的租户在 querier 崩溃后将以降低的 querier 容量运行。该租户最终可能没有任何可用的 querier,但此配置降低了崩溃影响其他租户的可能性。
延迟 1 分钟可能是合理的权衡
- Query-frontend:
-query-frontend.querier-forget-delay=1m
- Query-scheduler:
-query-scheduler.querier-forget-delay=1m
Store-gateway shuffle sharding
默认情况下,租户的 blocks 会分配给所有 Grafana Pyroscope store-gateway。
当您通过将 -store-gateway.tenant-shard-size
(或其相应的 YAML 配置选项)设置为大于 0
且小于可用 store-gateway 数量的值来启用 store-gateway shuffle sharding 时,仅指定数量的 store-gateway 有资格为给定租户加载和查询 blocks。您必须在 store-gateway 和 querier 上设置此 flag。
您可以通过在运行时配置的 overrides 部分设置 store_gateway_tenant_shard_size
,在每个租户基础上覆盖 store-gateway shard size。
有关 store-gateway 的更多信息,请参阅store-gateway。
Compactor shuffle sharding
默认情况下,租户 blocks 可以由任何 Grafana Pyroscope compactor 压缩。
当您通过将 -compactor.compactor-tenant-shard-size
(或其相应的 YAML 配置选项)设置为大于 0
且小于可用 compactor 数量的值来启用 compactor shuffle sharding 时,仅指定数量的 compactor 有资格为给定租户压缩 blocks。
您可以通过在运行时配置的 overrides 部分设置 compactor_tenant_shard_size
,在每个租户基础上覆盖 compactor shard size。
Shuffle sharding 对 KV 存储的影响
Shuffle sharding 不会给 KV 存储增加额外的开销。Shard 是在客户端计算的,不存储在 ring 中。KV 存储的大小主要取决于使用 ring 的任何组件(例如 ingester)的副本数量以及每个副本的 token 数量。
但是,在某些组件中,每个租户的 shard 会在客户端缓存在内存中,这可能会略微增加其内存占用。内存占用增加主要可能发生在 distributor 中。