Loki Ruler 远程规则评估(Remote Rule Evaluation)设计解析与实现指南
Loki Ruler 远程规则评估(Remote Rule Evaluation)设计解析与实现指南
导读
本文基于 Loki 社区 LID(Loki Improvement Document)0002-Remote Rule Evaluation(原文档)展开,深入讲解 Loki 的 ruler 组件如何从"本地评估"演进为可选的"远程评估"模式:将规则查询经 gRPC 转发给 query-frontend,从而复用 Loki 查询路径的加速能力(拆分、分片、缓存)与租户隔离能力。读完本文,你将掌握该方案的背景动机、设计取舍、源码级实现原理,以及 ruler.evaluation.mode: remote 模式下的完整配置方法与运维要点。
背景:ruler 组件与"本地评估"的现状
ruler 是 Loki 中负责评估告警规则(alerting rules)与录制规则(recording rules)的组件,它直接复用了 Prometheus 的规则评估引擎(详见 pkg/ruler 目录下的实现)。当前(即本 LID 提出时)的 ruler 工作方式如下:
ruler在内部初始化一个querier,并在本地评估所有规则,不依赖任何其他组件;- 每个规则组(rule group)并发执行,而组内规则按顺序依次评估——这一顺序语义继承自 Prometheus 的实现细节;
- 录制规则产生的指标序列会被发送到 Prometheus 兼容的 remote-write 端点(Loki 中由 RemoteWriteConfig 配置,对应
ruler.remote-write.*一系列 flag); - 告警规则在条件满足时向 Alertmanager 发送通知。
这两类规则在组织的可观测性体系中扮演关键角色,因此规则评估的可靠性至关重要。
从当前源码看,这一"双模式"设计已经落地:
EvaluationConfig中定义了Mode(local或remote)、MaxJitter(规则评估前随机等待的上限,用于避免并发执行时的争用)以及QueryFrontend传输配置,见 pkg/ruler/evaluator.go。
问题陈述:昂贵查询让整个 ruler 变得不可靠
规则查询可能非常昂贵。由于本地评估模式下 ruler 内置的 querier 不具备查询加速能力——而 Loki 的查询加速(拆分、分片、缓存等)恰恰由 query-frontend 组件负责——一条昂贵的规则查询就可能导致:
- 整实例资源耗尽甚至崩溃:昂贵查询会让单个
ruler实例占用过量资源; - 规则组内后续规则被延迟或漏跑:由于组内规则是顺序执行的,慢查询会拖累同组的其他规则,进而导致告警缺失或录制规则指标出现空洞;
- "吵闹邻居"(noisy neighbour)问题:个别租户的昂贵规则会挤占其他租户的规则评估资源。
目标与非目标
目标(Goals):
- 更快、更高效的规则评估;
- 更强的租户间隔离;
- 更可靠的服务。
非目标(Non-Goals):
本提案不打算让远程评估成为默认模式。由于它会增加运维复杂度,因此应作为可选项提供给用户。
方案对比:什么都不做,还是远程执行?
提案 0:什么都不做(Do nothing)
Loki 现有的 ruler 实现对于小规模部署、规则相对简单或查询开销低的场景已经足够。
- 优点:无需任何改动;
- 缺点:在规则查询昂贵的大型多租户环境中,
ruler会持续保持不可靠、低效的状态。
提案 1:远程执行(Remote Execution)
借鉴 Grafana Mimir 的远程模式实现思路,ruler 配置为通过 gRPC 将规则查询发送到 query-frontend。之后:
- 接收
query-frontend(或可选地经由query-scheduler)派发的querier实例处理请求,并把结果返回给query-frontend进行合并; ruler接收并处理这些响应,就如同查询是在本地执行的一样。
优点:
- 充分利用 Loki 的查询加速技术,规则评估更快、更高效;
- 运维简单:可直接复用现有的
query-frontend/query-scheduler/querier部署; - Loki 查询路径中已有的租户隔离能力(shuffle-sharding、按租户队列)可用于削减甚至消除"吵闹邻居"问题。
缺点:
- 组件间耦合度上升,跨组件网络交互增加;
- 与租户查询共享同一套
query-frontend/query-scheduler/querier时,昂贵查询可能反过来挤占规则评估的查询资源,反之亦然(建议参考文末"其他说明"单独复制一套查询路径用于规则评估); - 若需要为规则评估单独复制查询路径,会引入额外复杂度。
源码级实现:远程评估是如何落地的
该 LID 被接受后,远程评估功能已完整实现于当前仓库。下面按实现层次逐一解读。
1. Evaluator 抽象与评估模式配置
Evaluator 接口是所有规则评估器的统一抽象,核心方法为 Eval(ctx, qs, now),返回 logqlmodel.Result(见 pkg/ruler/evaluator.go):
type Evaluator interface {
Eval(ctx context.Context, qs string, now time.Time) (*logqlmodel.Result, error)
}
评估模式由 EvaluationConfig 控制,YAML 结构与命令行 flag 对应(pkg/ruler/evaluator.go):
type EvaluationConfig struct {
Mode string `yaml:"mode,omitempty"`
MaxJitter time.Duration `yaml:"max_jitter"`
QueryFrontend QueryFrontendConfig `yaml:"query_frontend,omitempty"`
}
-ruler.evaluation.mode:取值local或remote,未设置时默认local;-ruler.evaluation.max-jitter:规则评估前随机等待时长的上限(默认 0 即禁用),同一规则会得到一致的抖动值,用于避免大量规则并发执行时的争用;Validate()会拒绝除local/remote之外的任何取值。
2. RemoteEvaluator:把规则查询变成一次 gRPC 调用
RemoteEvaluator 是远程模式的执行核心(pkg/ruler/evaluator_remote.go),其成员包含一个 httpgrpc.HTTPClient(将 HTTP 请求封装进 gRPC)、RulesLimits(每租户覆盖限制)以及指标采集器。
Eval 的超时控制:Eval 会从 context 中提取租户 ID(X-Scope-OrgID),并以该租户的 ruler_remote_evaluation_timeout 限制(未配置时回退到 querier.query-timeout)创建带超时的 context;若超时,则上报 timeout 失败指标并返回错误(pkg/ruler/evaluator_remote.go)。
查询请求的构造(query 方法,pkg/ruler/evaluator_remote.go):
- 请求方法为
POST,路径为/loki/api/v1/query,Content-Type为表单类型,携带query、direction=forward、time参数; - 附加自定义请求头:
User-Agent: loki-ruler/<version>、X-Query-Tags: source=ruler,rule_name=<名称>,rule_type=<类型>(规则详情从 context 中取得),以及X-Scope-OrgID租户头; - 对非 2xx 响应、超过
ruler_remote_evaluation_max_response_size的响应分别上报upstream_error、max_size失败指标; - 响应体通过
loghttp.QueryResponse解码,目前支持vector与scalar两种结果类型,分别转换为 Prometheus 的promql.Vector/promql.Scalar(pkg/ruler/evaluator_remote.go)。
gRPC 客户端拨号:DialQueryFrontend(pkg/ruler/evaluator_remote.go)配置了 10s 的 keepalive、客户端负载均衡策略 round_robin、用户头拦截器与 OTel 链路追踪;要求地址为 DNS 地址(dns:/// 前缀)以启用客户端侧负载均衡。
配套指标(namespace loki_、subsystem ruler_remote_eval):
| 指标 | 类型 | 含义 |
|---|---|---|
loki_ruler_remote_eval_request_duration_seconds |
Histogram | 远程评估请求耗时(按租户) |
loki_ruler_remote_eval_response_bytes |
Histogram | 响应体大小(按租户) |
loki_ruler_remote_eval_response_samples |
Histogram | 响应样本数(按租户) |
loki_ruler_remote_eval_success_total |
Counter | 成功评估次数(按租户) |
loki_ruler_remote_eval_failure_total |
Counter | 失败评估次数(按原因 timeout/error/upstream_error/max_size 与租户) |
3. 每租户覆盖限制
远程评估受每租户(per-tenant)限制约束,定义于 pkg/validation/limits.go:
ruler_remote_evaluation_timeout:远程规则评估超时时间;未配置时回退到querier.query-timeout(pkg/validation/limits.go);ruler_remote_evaluation_max_response_size:远程评估允许的最大响应字节数;设为 0 表示不限制(默认)。
4. 模块装配:local 与 remote 的分流
在 pkg/loki/modules.go 中,initRuler 根据 t.Cfg.Ruler.Evaluation.Mode 分流:
local模式:创建删除请求客户端、LogQL 查询引擎,并构造NewLocalEvaluator;remote模式:调用ruler.DialQueryFrontend拨号query-frontend,随后构造NewRemoteEvaluator,将 gRPC 客户端与Overrides(每租户限制)注入;- 两种模式都会用
NewEvaluatorWithJitter包装,应用max_jitter配置。
对应测试覆盖了远程评估的成功、超时、非 2xx 响应、超大响应等路径,见 pkg/ruler/evaluator_remote_test.go。
配置实战:启用远程规则评估
以下配置以当前仓库中的真实字段为准。启用远程评估的 YAML 片段(ruler.evaluation 为顶层 ruler 配置块的一部分):
ruler:
evaluation:
mode: remote
query_frontend:
# gRPC 监听地址;必须使用 dns:/// 前缀以启用客户端侧负载均衡
address: dns:///query-frontend:9095
max_jitter: 0s
等价的命令行 flag 形式:
-ruler.evaluation.mode=remote
-ruler.evaluation.query-frontend.address=dns:///query-frontend:9095
在单二进制(monolithic)部署下,query-frontend 与 ruler 同进程运行,可参考 cmd/loki/loki-local-config.yaml 这类基础配置组合出符合自身拓扑的配置;微服务部署则需确保 ruler 能通过 DNS 解析到 query-frontend 的 gRPC 端口(Loki 默认 gRPC 端口为 9095)。
按租户覆盖限制的配置示例:
limits_config:
ruler_remote_evaluation_timeout: 30s
ruler_remote_evaluation_max_response_size: 0
适用前提与限制:
- 远程评估是可选项,默认仍是
local,因为远程模式会引入对query-frontend/query-scheduler/querier的依赖,增加运维复杂度; - 地址必须是 DNS 地址(
dns:///前缀),否则无法启用客户端侧负载均衡; - 建议为远程评估单独部署一套查询路径(见下文),避免与租户查询互相挤占资源。
与基于规则的规则分片(Rule-Based Sharding)的组合考量
文档特别指出了与规则分片功能(rule-based sharding,参见 Loki PR #8092 的相关讨论)搭配使用时的优化空间与挑战:
- 默认行为:
ruler默认按规则组(rule group)分片,规则组之间负载可能不均衡——若某些规则组的查询更昂贵,规则会被不均匀地分配到各ruler实例;同时由于组内规则顺序执行,昂贵查询会延迟甚至拖垮组内后续规则; - 规则分片的收益:按规则分片将规则均匀分布到所有
ruler实例上,每条规则各自成组。因此每个实例上的规则将并发评估。对拥有成百上千条规则的租户而言,若这些规则使用相同评估间隔或恰好重叠,就会在短时间内向query-frontend发送大批量查询; - 两者应分步实施:远程评估和规则分片可以(也应该)独立实施。运维方应先落地远程评估以提升
ruler可靠性;若仍因规则组顺序执行而漏跑规则,再进一步评估规则分片,或建议租户拆分规则组。
运维注意事项
假设远程规则评估与租户查询走的是同一条读路径,运行大型多租户集群的运维人员必须确保系统能够在可接受的时间范围内接收、排队并处理大量查询:
- 强烈建议启用
query-scheduler:它使query-frontend与querier可以横向扩容以承受规则评估带来的额外负载; - 实施 shuffle-sharding:确保负载特别大的租户不会挤占其他租户的查询资源;
- 配置告警:当规则评估被例行性漏跑、或某租户的查询队列已满时,及时通知运维人员;
- 必要时复制读路径:如果规则评估与租户查询相互拖慢,就需要复制一套读路径部署,使二者不共享查询执行资源。
总结
0002-Remote Rule Evaluation 为 Loki 的 ruler 组件开辟了一条"借力查询路径"的可靠性提升路线:通过把规则查询远程化,复用 query-frontend 的拆分、分片、缓存加速以及查询路径上的租户隔离能力,缓解昂贵规则查询导致的实例崩溃、规则漏跑与"吵闹邻居"问题。该设计如今已完整落地于仓库中(pkg/ruler/evaluator_remote.go 与 pkg/loki/modules.go),并提供了 local/remote 双模式、每租户超时与响应大小限制、完善的失败原因指标等工程化能力。对于规则负载较重的多租户生产环境,按本文所述步骤启用远程评估、配合 query-scheduler 与 shuffle-sharding,是提升规则评估可靠性的推荐路径。