4. 规则引擎设计:规则定义、规则解析、规则执行链、规则优先级与冲突处理
在低延迟回测与灰度切换系统中,规则引擎是核心决策组件。它负责将业务逻辑(如“当订单簿价差超过阈值时切换路由”)从硬编码中解耦,实现可配置、可热更新的策略控制。本章围绕规则引擎的四个关键环节展开:规则定义(如何描述一条规则)、规则解析(如何将文本定义转为内存对象)、规则执行链(如何高效串联多条规则)、规则优先级与冲突处理(如何保证确定性)。
4.1 规则定义:结构化与可扩展的 DSL
规则定义采用轻量级领域特定语言(DSL),以 JSON 或 YAML 格式描述。每条规则包含三个核心部分:条件(Condition)、动作(Action)、元数据(Metadata)。
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
rule_id |
string | 全局唯一标识 | "rule_001" |
priority |
int | 数值越小优先级越高 | 10 |
condition |
object | 条件表达式树 | {"type":"gt","field":"spread","value":0.05} |
action |
object | 执行动作描述 | {"type":"switch_route","target":"route_b"} |
enabled |
bool | 是否启用 | true |
tags |
array | 用于分组/灰度标签 | ["gray_v2","exchange_a"] |
设计要点:条件表达式支持嵌套逻辑(AND/OR/NOT),动作字段保持原子性,避免在动作中嵌入复杂计算。元数据中的 tags 字段用于灰度切换时的规则分组过滤,是实现“按标签灰度”的关键。
4.2 规则解析:从文本到 AST 再到可执行对象
规则解析分为两个阶段:词法/语法分析生成抽象语法树(AST),语义分析将 AST 转换为可执行的条件函数与动作函数。解析器必须支持热加载,且解析延迟需控制在微秒级。
// 规则解析核心流程(伪代码)
Rule parseRule(JsonNode ruleJson) {
// 1. 解析元数据
RuleMeta meta = parseMeta(ruleJson.get("metadata"));
// 2. 解析条件表达式 -> AST
ConditionNode condAst = parseCondition(ruleJson.get("condition"));
// 3. 将 AST 编译为可执行条件函数
ConditionFunc condFunc = compileCondition(condAst);
// 4. 解析动作
ActionFunc actionFunc = parseAction(ruleJson.get("action"));
// 5. 组装为 Rule 对象
return new Rule(meta, condFunc, actionFunc);
}
低延迟优化:预编译条件函数为 JIT 字节码或直接生成机器码,避免运行时递归解释 AST。对于高频触发的规则(如 tick 级判断),使用线程本地缓存(ThreadLocal)存储解析后的规则对象,减少 GC 压力。
4.3 规则执行链:线性扫描与短路优化
规则执行链采用有序线性扫描模式,按优先级排序后依次执行。每条规则执行时,先评估条件,若为 true 则执行动作,并根据动作类型决定是否继续执行后续规则(短路)。
注意:线性扫描在规则数量较少(通常 < 100 条)时性能最优。若规则数量超过 1000 条,需引入索引结构(如规则标签哈希索引)进行预过滤,否则扫描延迟会线性增长。
4.4 规则优先级与冲突处理
规则优先级决定了执行顺序,而冲突处理则解决“多条规则同时满足条件时,最终执行哪个动作”的问题。系统采用优先级 + 确定性策略的组合方案。
4.4.1 优先级定义
- 数值优先级:整数类型,数值越小优先级越高。优先级 0 为最高,通常保留给系统级规则(如风控熔断)。
- 分组优先级:支持按规则组设置基础优先级,组内规则再设置相对优先级。例如“灰度组”基础优先级 50,“生产组”基础优先级 100。
- 动态优先级:运行时可根据上下文(如当前回测阶段、市场波动率)调整优先级,但需谨慎使用以避免不确定性。
4.4.2 冲突处理策略
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 优先级优先 | 仅执行优先级最高的匹配规则,忽略其他 | 风控规则、路由切换规则 |
| 合并动作 | 将多条匹配规则的动作合并执行(需动作可组合) | 日志记录、指标采集规则 |
| 标签覆盖 | 按灰度标签优先级覆盖:灰度标签 > 生产标签 | 灰度切换场景 |
| 报错回滚 | 检测到冲突时抛出异常,回滚到上一个安全状态 | 数据一致性要求高的场景 |
灰度切换中的冲突处理:当灰度规则与生产规则同时匹配时,系统默认采用“标签覆盖”策略——灰度标签优先级高于生产标签。例如,灰度规则设置
tags: ["gray_v2"],生产规则设置 tags: ["production"],在灰度切换期间,灰度规则优先执行。切换完成后,通过配置中心将灰度规则的 enabled 字段设为 false,即可平滑回退。
4.5 规则引擎性能指标
在低延迟回测系统中,规则引擎的延迟必须控制在纳秒级。以下是关键性能指标参考:
| 指标 | 目标值 | 测量方法 |
|---|---|---|
| 规则解析延迟(单条) | < 1 μs | 预热后,连续解析 10000 次取平均 |
| 规则执行延迟(单条) | < 100 ns | 条件为 false 时的最快路径 |
| 执行链扫描延迟(50 条规则) | < 5 μs | 全部规则条件为 false 时的最坏情况 |
| 热加载生效时间 | < 1 ms | 从配置变更到新规则生效 |
优化建议:将频繁使用的条件字段(如 spread、volume)映射为内存中的直接指针访问,避免反射或字典查找。对于条件中涉及的外部数据(如交易所状态),使用内存屏障(Memory Barrier)保证可见性,而非加锁。