菜单
开源 RSS

使用混洗分片隔离租户工作流程

混洗分片是一种资源管理技术,用于将租户工作负载与其他租户工作负载隔离,从而在共享集群中为每个租户提供更接近单租户的体验。AWS 在其文章 使用混洗分片进行工作负载隔离 中解释了这种技术。在 Route53 Infima 库 中展示了一个参考实现。

混洗分片缓解的问题

混洗分片可以为查询路径配置。

查询路径默认是分片的,默认不使用混洗分片。每个租户的查询都会在所有 querier 上分片,因此工作负载会使用所有 querier 实例。

在多租户集群中,跨组件的所有实例进行分片可能会出现以下问题

  • 组件实例的任何中断都会影响所有租户
  • 行为异常的租户会影响所有其他租户

单个查询可能会给所有租户带来问题。单个租户或一组租户可能会发出一个开销很大的查询:导致 querier 组件发生内存不足错误,或导致 querier 组件崩溃。一旦发生错误,发出错误查询的租户将被重新分配到其他正在运行的 querier(请记住所有租户都可以使用所有可用的 querier),这反过来可能会影响被重新分配到的 querier。

混洗分片的工作原理

混洗分片的想法是将每个租户分配到由部分 Loki querier 组成的切片,旨在最大程度地减少不同租户之间的实例重叠。

行为异常的租户只会影响其切片的 querier。由于租户之间 querier 的重叠度很低,只有一小部分租户会受到行为异常租户的影响。混洗分片所需的资源不比默认分片策略多。

混洗分片并不能解决所有问题。如果一个租户重复发送有问题的查询,崩溃的 querier 将会从 query-frontend 断开,并且一个新的 querier 会立即分配给该租户的切片。这使得混洗分片的积极效果失效。在这种情况下,配置一个延迟——从 querier 因崩溃断开连接到崩溃的 querier 实际从租户的切片中移除并添加另一个健康的 querier 作为替换之间设置一个延迟——可以改善情况。在 query-frontend 中,使用配置参数 -query-frontend.querier-forget-delay=1m,以及在 query-scheduler 中,使用配置参数 -query-scheduler.querier-forget-delay=1m,1 分钟的延迟可能是一个合理的值。

实例重叠的低概率

如果一个示例 Loki 集群运行 50 个 querier,并为每个租户分配 50 个 querier 中的 4 个,并在租户之间混洗实例,则有 23 万种可能的组合。

统计上,随机选取两个不同的租户,有

  • 71% 的几率它们不会共享任何实例
  • 26% 的几率它们只会共享 1 个实例
  • 2.7% 的几率它们会共享 2 个实例
  • 0.08% 的几率它们会共享 3 个实例
  • 它们的实例完全重叠的几率只有 0.0004%

overlapping instances probability

配置

通过将 -frontend.max-queriers-per-tenant 设置为大于 0 且小于可用 querier 数量的值来启用混洗分片。租户级配置参数 max_queriers_per_tenant 的值设置了分配的 querier 数量。此选项仅在使用 query-frontend 时可用,无论是否带有调度器。

租户级配置参数 max_query_parallelism 描述了在查询拆分和查询分片之后,每个租户的每个请求可以同时调度的子查询数量。

配置参数 querier.concurrency 控制单个 querier 的工作线程(goroutine)数量。

在限制覆盖配置中,可以通过 max_queriers_per_tenant 在每个租户的基础上覆盖最大 querier 数量。

混洗分片指标

这些指标揭示了与混洗分片相关的信息

  • 整体 query-scheduler 队列持续时间,loki_query_scheduler_queue_duration_seconds_*

  • 每个租户的 query-scheduler 队列长度,loki_query_scheduler_queue_length

  • 每个租户的 query-scheduler 队列持续时间可以通过此查询找到

    max_over_time({cluster="$cluster",container="query-frontend", namespace="$namespace"} |= "metrics.go" |logfmt | unwrap duration(queue_time) | __error__="" [5m]) by (org_id)

这些指标中出现过多的峰值可能意味着

  • 特定租户试图使用比分配给他们的更多查询资源。
  • 该租户可能需要增加 max_queriers_per_tenant 的值。
  • Loki 实例可能资源不足。

一个有用的查询可以检查每个租户正在使用多少个 querier

count by (org_id) (sum by (org_id, pod) (count_over_time({job="$namespace/querier", cluster="$cluster"} |= "metrics.go" | logfmt [$__interval])))