使用 actor 确保租户内的查询公平性
Loki 使用随机分片来最大程度地减少查询器故障或行为不端的相邻租户对其他租户的影响。
当可能有许多不同的 actor(例如从 Grafana 访问 Loki 的用户、通过 LogCLI 或使用 HTTP API 的其他应用程序)使用同一个租户查询日志时,由于它们共享同一租户的资源,可能导致不同用户查询之间发生竞争。
在这种情况下,作为操作员,您可能希望在租户内部的这些 actor 之间确保一定程度的查询公平性。actor 可以是 Grafana 用户、CLI 用户或访问 API 的应用程序。为了实现这一点,Loki 在 2.9 版本中基于 LID 0003: Query fairness across users within tenants 引入了分层调度器队列,并且默认启用。
什么是分层队列以及它们如何工作
为了理解分层队列,我们首先需要知道在调度器组件中,每个租户都有自己的先进先出 (FIFO) 队列,用于排队子查询。子查询是客户端使用 HTTP 发送的查询经过拆分和分片后生成的查询。
租户队列是队列层次结构的第一个级别。当租户在没有进一步控制的情况下执行查询时,其所有子查询都会被排队到第一个级别的队列。
队列层次结构的第二个级别是租户可以拥有子队列。
类似于随机分片如何在租户级别分配查询,每次 Loki 调度器在查询层次结构的第二个级别进行轮询选择时,它会从租户的本地队列和子队列中选择一个查询。
上图显示租户队列有一个本地队列(它是队列树中的一个叶节点)和一组子队列。每个子队列,同样像租户队列一样,包含一个本地队列和可能的子队列,从而形成一个递归树结构。
那么,我们如何利用这些树状队列结构来实现查询公平性呢?
如何控制查询公平性
如前所述,默认情况下,子查询仅在队列树的第一个(租户)级别排队。租户信息由在多租户模式下运行 Loki 时必需的 X-Scope-OrgID
头部提供。
您可以使用 HTTP 头部 X-Loki-Actor-Path
来控制查询(或者更确切地说,其子查询)被排队到哪个子队列。
以下示例显示了一个 curl 命令,该命令调用范围查询的 HTTP 端点并传递 X-Scope-OrgID
和 X-Loki-Actor-Path
这两个头部。
curl -s https://:3100/loki/api/v1/query_range?xxx \
-H 'X-Scope-OrgID: grafana' \
-H 'X-Loki-Actor-Path: joe'
此请求调用的查询最终会进入 grafana
租户队列的 joe
子队列。另一个用户可以在 actor path 头部使用自己的名字,将其查询排队到自己的子队列。
由于调度器以轮询方式为租户选择下一个任务,当调度器将子查询出队发送给查询器时,两个 actor(在我们的例子中是人类用户)都能获得 50% 的份额。
如果有 N 个 actor,每个 actor 会获得他们份额的 1/N。在我们有两个用户的示例中,即使租户的本地队列中有子查询,本地队列获得 1/3 的份额,每个子队列也获得 1/3 的份额。
正如前面解释的实现和头部名称所示,可以将查询排队到多个层次深度。为此,您可以使用头部值中的 |
分隔符构造到子队列的路径,如下例所示。
curl -s https://:3100/loki/api/v1/query_range?xxx \
-H 'X-Scope-OrgID: grafana' \
-H 'X-Loki-Actor-Path: users|joe'
curl -s https://:3100/loki/api/v1/query_range?xxx \
-H 'X-Scope-OrgID: grafana' \
-H 'X-Loki-Actor-Path: apps|logcli'
路径深度以及队列树的深度是有限制的。这由 Loki 的 -query-scheduler.max-queue-hierarchy-levels
CLI 参数或其相应的 YAML 配置块控制。
query_scheduler:
max_queue_hierarchy_levels: 2 # defaults to 3
建议将层级保持在合理的水平(理想情况下 1 到 3 层),这既是为了性能考虑,也是为了便于理解如何在所有子队列之间确保查询公平性。
强制使用头部
在上面的示例中,直接向 Loki 发起查询的客户端也提供了控制子查询在队列树中排队位置的 HTTP 头部。但是,作为操作员,您通常希望避免这种情况,并自行控制头部设置的位置。
例如,在使用 Grafana 作为 Loki 用户界面时,您可以为同一个租户创建多个数据源,但每个数据源带有不同的附加 HTTP 头部 X-Loki-Actor-Path
,并限制哪些 Grafana 用户可以使用哪些数据源。
或者,如果您在 Loki 前面设置了用于认证的代理,您可以将认证后的(哈希过的)用户信息作为下游头部传递给 Loki。