Envoy CEL 正则预编译运行时开关移除解析:envoy.reloadable_features.enable_cel_regex_precompilation的演进与现状
【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy
导读
本篇文章围绕 Envoy 当前版本 changelog 中的一条移除记录展开:changelogs/current/removed_config_or_runtime/rbac__cel-regex-precompilation.rst宣布移除运行时开关envoy.reloadable_features.enable_cel_regex_precompilation及其 legacy 代码路径。对于使用 RBAC、ExtProc 等依赖 CEL(Common Expression Language)表达式做策略匹配的开发者而言,这标志着 CEL 正则预编译从"可回退的灰度能力"正式固化为默认行为。读完本文,你将理解该开关引入的历史背景、其背后的 CEL 求值器实现原理、移除后的实际影响,以及升级时需要关注的兼容性事项。
一、changelog 条目解读:一句话背后的完整信息
changelogs/current/removed_config_or_runtime/rbac__cel-regex-precompilation.rst全文内容如下:
Removed runtime flag
envoy.reloadable_features.enable_cel_regex_precompilationand legacy code paths.
这是 Envoy 标准化的removed_config_or_runtime类 changelog 条目,共包含两层信息:
- 运行时开关被移除:
envoy.reloadable_features.enable_cel_regex_precompilation这个 Runtime Flag 不再存在。用户无法再通过 runtime 配置将其设置为false来关闭 CEL 表达式中的正则预编译行为。 - legacy 代码路径被清理:原先为实现"预编译可开关"而保留的旧分支代码被删除,代码库中只保留预编译开启的单一执行路径。
在 Envoy 的演进策略中,removed_config_or_runtime目录专门记录这类"功能已默认化、开关已退役"的变更。该条目没有附带说明文档,因为它对应的是内建行为的固化——这正是理解本文主题的关键:这个功能早已成为默认行为,本次只是移除"关闭它的能力"。
二、功能背景:该开关从何而来
要理解这次移除,需要回溯该开关的引入记录。在 changelogs/1.35.0.yaml 中可以看到对应的cel变更条目:
Precompile regexes in CEL expressions. This can be disabled by setting the runtime guard
envoy.reloadable_features.enable_cel_regex_precompilationtofalse.
也就是说,从 Envoy 1.35.0 开始,CEL 表达式中的正则表达式会被"预编译",并且该行为默认开启,同时提供了一个可回退的 runtime guard,允许运营者将其显式设置为false以临时禁用。本次 changelog 条目即是在若干版本之后,宣布这个灰度开关已完成使命,正式退役。
这种"新功能默认开启 + runtime flag 可回退 → 观察期结束后移除开关与旧代码路径"的做法,是 Envoy 引入新行为时的标准生命周期,同一目录下的其他removed_config_or_runtime条目也遵循该模式。
三、底层实现:CEL 表达式构建器中的正则预编译
理解该开关的意义,关键在于看 Envoy 实际构造 CEL 表达式求值器(Expression Builder)的代码。核心实现位于 source/extensions/filters/common/expr/evaluator.cc 的createBuilder函数:
BuilderConstPtr createBuilder(OptRef<const envoy::config::core::v3::CelExpressionConfig> config, Protobuf::Arena* arena) { ASSERT_IS_MAIN_OR_TEST_THREAD(); google::api::expr::runtime::InterpreterOptions options; // Security-oriented defaults. options.enable_comprehension = false; options.enable_regex = true; options.regex_max_program_size = 100; options.enable_qualified_identifier_rewrites = true; // Resolve options from configuration or fall back to security-oriented defaults. bool enable_string_functions = false; if (config.has_value()) { options.enable_string_conversion = config->enable_string_conversion(); options.enable_string_concat = config->enable_string_concat(); enable_string_functions = config->enable_string_functions(); } else { options.enable_string_conversion = false; options.enable_string_concat = false; } options.enable_list_concat = false; // Performance-oriented defaults. options.enable_regex_precompilation = true; // Enable constant folding with arena if provided for RBAC backward compatibility optimization. if (arena != nullptr) { options.constant_folding = true; options.constant_arena = arena; } auto builder = google::api::expr::runtime::CreateCelExpressionBuilder(options); ... }3.1 预编译开关的固化位置
注意第 131 行:
// Performance-oriented defaults. options.enable_regex_precompilation = true;在移除该 runtime flag 之后,options.enable_regex_precompilation = true被无条件硬编码,不再有任何 runtime 检查来读取envoy.reloadable_features.enable_cel_regex_precompilation的值。InterpreterOptions是 CEL-C++ 求值器库(eval/public/cel_expr_builder_factory.h)的配置结构体,enable_regex_precompilation开启后,表达式中使用的正则字面量会在表达式编译阶段被一次性编译成std::regex对象并缓存复用,而不是在每次求值(如每个请求到达时)都重新编译正则。
3.2 与安全相关默认值的配合
预编译并非孤立选项,它与该函数中设置的其他安全导向默认值共同构成 CEL 求值器的基线:
| 选项 | 值 | 作用 |
|---|---|---|
enable_comprehension | false | 禁用 CEL 的 comprehension 语法,防止基于迭代结构的复杂(潜在昂贵)表达式 |
enable_regex | true | 允许在表达式中使用正则匹配函数 |
regex_max_program_size | 100 | 限制正则程序规模上限,防止超大正则拖垮求值性能 |
enable_qualified_identifier_rewrites | true | 启用限定标识符重写 |
enable_string_conversion/enable_string_concat | 默认false,可经CelExpressionConfig开启 | 控制字符串转换与拼接扩展函数 |
enable_list_concat | false | 禁用列表拼接 |
enable_regex_precompilation | true(本次固化) | 正则预编译 |
也就是说,正则预编译默认开启并非一次性决定,而是 Envoy 对 CEL 求值器"性能优先 + 安全兜底"整体策略的一部分。
3.3 常量折叠与 arena
createBuilder还根据调用方是否传入Protobuf::Arena决定是否启用常量折叠:
if (arena != nullptr) { options.constant_folding = true; options.constant_arena = arena; }注释明确说明这是"RBAC backward compatibility optimization"——即为了保持 RBAC 过滤器既有的常量折叠语义而保留的优化。这意味着:当 RBAC 等调用方在 arena 上构造激活(Activation)上下文时,表达式中的常量子表达式会被提前折叠求值,进一步降低运行期开销,与正则预编译形成互补。
3.4 Builder 缓存:预编译成果的复用机制
正则预编译的收益最终通过 Builder 缓存落地。同文件中的BuilderCache(source/extensions/filters/common/expr/evaluator.cc)以配置 proto 的哈希为键缓存BuilderInstance:
BuilderInstanceSharedConstPtr BuilderCache::getOrCreateBuilder( OptRef<const envoy::config::core::v3::CelExpressionConfig> config) { ASSERT_IS_MAIN_OR_TEST_THREAD(); ConfigHash hash = 0; if (config.has_value()) { hash = MessageUtil::hash(config.ref()); } ... }缓存以weak_ptr持有实例,允许在 xDS 配置卸载后释放,同时保证相同配置的过滤器共享同一个已预编译的求值器。该缓存通过单例管理器注册(SINGLETON_MANAGER_REGISTRATION(builder_cache)),由getBuilder统一获取。正则预编译 + Builder 缓存的组合,意味着相同 CEL 表达式在不同请求之间不会重复付出正则编译成本——这正是本次移除的 legacy 开关所要守卫的默认路径。
四、该功能服务的实际场景:谁在用 CEL 正则
移除条目路径中的rbac__前缀表明,这一变更与 RBAC 过滤器强相关,但 CEL 表达式的使用面更广。从源码引用关系看,filters/common/expr/evaluator被以下模块使用:
- RBAC 过滤器:source/extensions/filters/common/rbac/matchers.h 中的 matcher 实现会使用 CEL 表达式构建器,将策略中的表达式编译为可复用求值器;
- ExtProc 过滤器:source/extensions/filters/http/ext_proc/config.cc 与 source/extensions/filters/network/ext_proc/matching_utils.h 等用于外部处理请求/响应的匹配;
- 其他通过
CelExpressionConfig或createBuilder/getBuilder接入 CEL 的过滤器与匹配逻辑。
对于 RBAC 这类"每个请求都要对策略表达式求值"的高频路径,表达式中的正则若每次请求都重新编译,会带来明显的 CPU 开销;预编译后则退化为一次编译、多次执行。这也是该功能最初被引入并最终被固化的直接动机。
五、升级与运维影响:移除开关后你需要知道什么
5.1 行为不再可回退
在 1.35.0 引入该功能时,若预编译在特定部署中引发问题,运营者可以通过 runtime 配置将envoy.reloadable_features.enable_cel_regex_precompilation设为false临时回退。本次移除后,该回退通道关闭,预编译行为成为不可配置的固定行为。若你的配置中仍显式引用了该 flag,需要将其从 runtime 配置(如 bootstrap 的runtime_layer或RuntimeDiscoveryService提供的配置)中删除,避免维护无效配置项。
5.2 对现有配置无破坏性影响
由于预编译自 1.35.0 起即默认开启,只要你的部署没有显式将其关闭,本次移除不会改变任何现有 CEL 表达式的求值结果,仅会带来更确定的性能特性。需要重点关注的是那些曾在生产环境中设置过enable_cel_regex_precompilation: false的部署——它们在升级后将自动切换到预编译路径,建议在升级前用真实流量或压测验证正则匹配语义与性能符合预期。
5.3 从源码确认当前状态
升级后如需确认预编译是否生效,可检查 source/extensions/filters/common/expr/evaluator.cc 中options.enable_regex_precompilation = true;的固定赋值,以及构建后的二进制中是否还存在enable_cel_regex_precompilation字符串引用(移除后应不存在 legacy 分支)。此外,changelogs/1.35.0.yaml 保留了该功能的引入记录,可作历史追溯依据。
六、小结
envoy.reloadable_features.enable_cel_regex_precompilation的移除是 Envoy 功能生命周期管理的一个典型案例:新能力(CEL 正则预编译)在 1.35.0 默认开启并以 runtime flag 提供回退,经过若干版本的稳定运行后,在本次变更中连同 legacy 代码路径一并清理。从实现角度看,createBuilder中固化的enable_regex_precompilation = true与BuilderCache缓存机制共同保证了高频 CEL 求值路径(RBAC、ExtProc 等)的性能确定性;从运维角度看,这要求使用方删除已失效的 runtime 配置,并确认未显式关闭过该特性的部署可直接平滑升级。
【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考