4. Rego 策略缓存机制:OPA 内部缓存类型与命中场景
在准入控制场景中,OPA 每次收到 Kubernetes API Server 的准入请求时,都需要执行 Rego 策略。如果每次执行都重新解析、编译策略并重新查询外部数据,延迟将不可接受。OPA 通过三层缓存机制来降低重复计算开销:AST 缓存、规则缓存 和 HTTP 缓存。理解这三层缓存的命中与未命中场景,是定位策略缓存延迟故障的基础。
4.1 三层缓存架构总览
下图展示了 OPA 内部三层缓存的协作关系,以及请求数据在缓存层之间的流动路径。
4.2 AST 缓存(模块解析缓存)
作用对象:Rego 源文件(.rego 模块)。
缓存粒度:每个模块文件独立缓存。
缓存键:模块文件路径 + 文件内容 SHA256 哈希。
当 OPA 启动或通过 Bundle API 加载策略时,会先检查 AST 缓存。如果模块内容未变化,则直接使用缓存的 AST 语法树,跳过词法分析和语法解析阶段。
| 场景 | 缓存状态 | 对延迟的影响 |
|---|---|---|
| 策略文件未修改,OPA 重启 | 未命中(缓存为空) | 首次加载需完整解析,延迟增加 10-50ms |
| 策略文件未修改,Bundle 热更新 | 命中(内容哈希一致) | 跳过解析,延迟降低至接近 0 |
| 策略文件内容变更 | 未命中(哈希变化) | 重新解析,延迟增加 10-50ms |
| 大量策略模块同时加载 | 逐模块检查,部分命中 | 未命中模块累积延迟 |
bundle_loading 事件,确认模块是否被重复解析。
4.3 规则缓存(编译缓存)
作用对象:编译后的规则集(Intermediate Representation, IR)。
缓存粒度:按策略包(package)粒度缓存。
缓存键:包名 + 所有依赖模块的 AST 版本戳。
规则缓存是三层缓存中最关键的一层。在准入控制场景中,同一个策略包可能被数千个请求反复调用。如果规则缓存命中,OPA 可以直接执行编译后的 IR,无需重新编译。
| 场景 | 缓存状态 | 对延迟的影响 |
|---|---|---|
| 同一策略包连续处理多个准入请求 | 命中 | 执行延迟仅 0.1-0.5ms |
| 策略包依赖的模块发生变更 | 未命中(版本戳变化) | 重新编译,延迟增加 20-100ms |
策略包使用 data 引用外部包 |
部分命中(依赖链检查) | 依赖包未命中时级联重新编译 |
| OPA 内存压力触发缓存逐出 | 未命中(LRU 淘汰) | 下次请求需重新编译 |
4.4 HTTP 缓存(外部数据缓存)
作用对象:通过 http.send 获取的外部数据。
缓存粒度:每个 HTTP 请求独立缓存。
缓存键:HTTP 方法 + URL + 请求头 + 请求体哈希。
缓存控制:遵循 HTTP 响应头中的 Cache-Control 和 ETag。
在准入控制场景中,策略经常需要查询外部服务(如镜像仓库、RBAC 系统)。HTTP 缓存可以避免重复的网络往返,但缓存策略配置不当会导致数据陈旧或缓存穿透。
| 场景 | 缓存状态 | 对延迟的影响 |
|---|---|---|
| 外部数据未变化,请求参数相同 | 命中 | 延迟降低至 0.1-1ms(无网络开销) |
外部数据变化,但 Cache-Control 未过期 |
命中(陈旧数据) | 延迟低但策略决策可能错误 |
外部服务返回 Cache-Control: no-cache |
未命中(强制回源) | 每次请求都发起 HTTP 调用,延迟 10-200ms |
| 大量并发请求查询同一外部端点 | 缓存雪崩(同时失效) | 瞬时大量 HTTP 请求,延迟飙升 |
4.5 缓存命中与未命中的完整决策流程
以下 SVG 图展示了 OPA 在处理一个准入请求时,三层缓存的逐级检查顺序以及未命中时的回退路径。
4.6 缓存延迟故障的典型模式
- AST 缓存频繁未命中:通常由 Bundle 推送过于频繁或 OPA 实例频繁重启导致。检查
opa_bundle_loading_seconds指标。 - 规则缓存级联失效:当策略包依赖链较深时,底层模块变更会引发上层所有包重新编译。使用
opa inspect命令分析依赖树。 - HTTP 缓存穿透:外部服务未返回有效的
Cache-Control头,或请求参数(如时间戳)每次都不同,导致缓存无法命中。检查opa_http_cache_hit_ratio指标。 - 缓存逐出导致抖动:OPA 内存不足时,LRU 缓存会逐出最近最少使用的条目。如果准入请求的流量模式突然变化,冷启动延迟会显著增加。
opa eval --metrics 命令可以查看每次策略评估的缓存命中情况。
# 查看策略评估的缓存指标
opa eval --metrics --format pretty 'data.kubernetes.admission.deny' \
--input input.json \
--data policy.rego
# 输出示例(关注 cache_hit 相关指标)
# ast_cache_hit: 1
# rule_cache_hit: 1
# http_cache_hit: 0
# eval_time: 0.002ms
4.7 缓存配置参数速查表
| 缓存类型 | 相关配置参数 | 默认值 | 建议调整场景 |
|---|---|---|---|
| AST 缓存 | --ast-cache-max-size |
1000 个模块 | 策略模块数量超过 500 时适当增大 |
| 规则缓存 | --rule-cache-max-size |
500 个包 | 准入策略包数量多时增大,注意内存开销 |
| HTTP 缓存 | --http-cache-max-size |
1000 个条目 | 外部数据查询量大时增大,配合 TTL 使用 |
| 全局缓存逐出 | --cache-eviction-interval |
5 分钟 | 流量抖动大时缩短间隔,减少冷启动 |