上个月有个做教育投放的团队来找我,问得特别具体:手头两百多条分流规则,到底是接着全塞一个规则集里,还是按业务线拆成几个?他们的顾虑也挺实在——拆了吧,怕条件命中顺序变复杂;不拆吧,每次改一条规则都得动整个文件,心里没底。其实这个问题说到底就是规则集拆分粒度的事儿。拆到什么程度算合适,什么情况下别拆,拆完又该盯什么。我下面按三种前提分支来说,不追求一个放之四海皆准的答案,因为这种问题本来就没有。
先说结论:粒度由变更频率和责任人决定,不由规则条数决定
很多人一拍脑袋就按条数定,比如“超过 100 条就拆”。这个判据说实话不太靠得住。真正决定拆分粒度的是两个变量:规则变更的频率,还有改规则的人是不是同一拨。你想想,如果两百条规则里大部分是稳定的常规条件——按国家、按设备类型做基础分流那种——只有一小撮每周都在调,那按条数上限来拆反而给自己找麻烦,每次改都得跨文件确认依赖。反过来也一样,规则总数可能就六十条,但分属两条业务线、两个运营各自维护,那即便条数不多也值得拆开,因为合并维护的协调成本已经超过拆分带来的复杂度了。
这里我顺带提一个判断动作:拿出最近一个月的规则变更记录,按“变更次数”给规则排个序。如果前 20% 的规则贡献了 80% 的变更,那拆分的切口应该落在这些高频规则和低频规则之间,而不是简单按业务线对半切。这个动作花不了多少时间,但能帮你少走很多弯路。
分支一:什么情况下适合拆成多个规则集
有三个信号出现时,拆分是划算的。
- 责任人已经分开。两条业务线的规则由不同的人维护,且互不引用对方的条件。这种情况下不拆,每次合并发布都要互相等,发布节奏被拖慢。
- 变更频率差异明显。高频调整的规则和基本不动的规则混在一起,每次改高频部分都要重新过一遍全量回归测试,测试成本被低频规则拖累。把它们拆开之后,低频规则集的回归频率可以降下来。
- 条件命中顺序可以局部封闭。也就是说,某个子集内部的规则顺序自成体系,和外部的规则没有前后依赖。这种情况下拆分是安全的。
这里有个实操细节:拆分时建议保留一个“入口规则集”,负责把请求路由到对应的子规则集,子规则集内部再各自排顺序。这样主链路的可读性不会被拆散。关于条件命中顺序本身怎么排,可以参照规则优先级冲突调优里的思路,拆分只是把顺序管理的范围缩小,不是取消它。
分支二:什么情况下不适合拆
有些时候拆了反而更难管,主要是这几类。
- 规则之间存在大量交叉引用。A 规则集里的条件依赖 B 规则集里的中间结果,这种耦合下拆开,等于把一条完整判定链切成两段,排查问题时要在两个文件之间来回跳。
- 团队只有一个人维护。拆分带来的模块化收益,在单人维护场景下基本被“切换上下文”的成本抵消。一个人维护两百条规则,只要命名规范、注释清楚,未必比拆成四个文件更难。
- 规则总量不大且变更集中在头部。如果真正在动的就那十几条,拆分的收益有限,优先做的是把高频规则单独抽出来、加注释、固定顺序,而不是整体拆分。
遇到这三种情况,下一步该检查的不是“要不要拆”,而是规则命名和注释是否到位。粒度问题很多时候是文档问题的标识模拟。
分支三:拆完之后要盯的三件事
假设已经拆了,有三个点需要在上线后持续观察。
第一件是加载顺序。多个规则集的加载顺序如果没写死,不同节点上可能加载出不同的合并结果,导致同一份请求在不同机器上命中不同分支。这个和斗篷系统高频问答里提到的缓存一致性问题同源——拆分之后,规则集的加载与缓存策略需要一起重新确认。
第二件是兜底规则的位置。原来一个规则集里兜底规则放最后就行,拆成多个之后,每个子集要不要各自兜底,还是只在入口规则集兜底一次,需要明确。建议只在入口层做最终兜底,子集内部命中不到就返回“未命中”信号交回上层,避免多层兜底互相覆盖。第三件是回归测试的范围。拆分的初衷之一是缩小测试范围,但如果子集之间仍有隐式依赖,测试范围就缩不下来。上线后第一周的观察重点是:一次只改一个子集,看另一个子集的命中率有没有异常波动。有波动说明还有没识别出来的耦合。
小结
规则集拆分粒度没有标准答案,判断依据是变更频率和责任人划分,不是规则条数。适合拆的信号是责任人分开、变更频率差异大、子集内部顺序可封闭;不适合拆的信号是交叉引用多、单人维护、变更集中在头部。拆完之后盯加载顺序、兜底位置和回归范围这三件事。如果拆完发现排查反而更费劲,说明切口选错了,退回去按变更频率重新切。
常见问题
规则集拆多了会影响分流响应速度吗
会有影响,但通常不在你担心的那个环节。多加载几个规则集本身开销不大,真正可能拖慢的是加载顺序不确定导致的重复判定。只要加载顺序固定、子集之间没有循环引用,响应速度的变化一般感知不到。
小团队规则不多,需要提前按业务线拆分吗
这个要看情况。如果两条业务线确实是不同的人在管,哪怕规则只有几十条,拆开也省事。但如果就一个人维护,规则又不多,先别拆,把注释和命名做清楚更实在。说白了,拆分是为了解决协作问题,不是为了看起来整齐。
拆分之后发现有的请求命中不到任何规则怎么办
先确认入口规则集有没有做最终兜底。如果入口层有兜底,那命中不到会走默认页面,属于预期行为。如果入口层也没兜底,请求就会悬空,这时候要检查子集返回的“未命中”信号有没有被入口层正确接收。顺手把这类请求的日志单独打出来,观察一两天看量级。
延伸阅读
规则集拆分只是规则维护的一个切面,真正决定长期稳定性的还有规则变更的安全边界和回滚机制,下面这篇从风险角度补充了这部分内容。
斗篷技术安全合规边界与风险评估