小陈是一家SaaS公司的技术总监,他们做的是中小企业CRM系统。
创业初期,产品功能单一,客户需求也趋同。但随着客户越来越多,问题就来了:
制造业客户说:“我们的客户分级逻辑和你们默认的不一样,要按年采购额而不是最近活跃度。”
金融客户说:“我们的审批流程需要四级会签,而且每个人的权限要动态计算。”
零售客户说:“我们的促销规则很复杂,除了满减还有满赠、换购、积分翻倍。”
为了拿下这些客户,小陈的团队疲于奔命。每个大客户都要单独fork代码分支,在分支上做定制开发。随着分支越来越多,合并代码变成了一场噩梦。
这就是SaaS厂商规模化扩张中普遍面临的困境。
一、租户隔离模式下的个性化挑战
1.个性化需求的三个层次
层次 | 示例 | 实现难度 |
参数配置 | 修改阈值、开关功能 | 低 |
流程调整 | 增加/删除审批节点 | 中 |
逻辑重构 | 改变算法、业务规则 | 高 |
前两个层次通过传统的配置系统可以解决,最麻烦的是第三个层次——业务逻辑的变化。
2. 传统做法的局限性
做法一:为每个大客户单独fork代码分支
问题:未来无法合并,维护成本随客户数线性增长
做法二:在代码中写满if-tenantId
问题:代码可读性急剧下降,改动一个地方需要测试所有租户
做法三:把所有逻辑都参数化
问题:参数数量爆炸,租户配置页面变得极其复杂
3. 更优的思路
将“业务规则”作为一等公民,和租户绑定。
核心思想是:规则不再是系统代码的一部分,而是租户的可配置资产。
- 系统提供规则的定义能力和执行环境
- 租户在自己的空间内配置规则
- 执行时根据租户ID加载对应的规则集
二、多租户规则管理的核心设计
1.变量的分层设计
规则中使用的变量,来自不同层级:
系统级变量
- 定义:所有租户共享、不可修改
- 示例:当前时间、请求来源IP、设备类型
租户级变量
- 定义:租户可以自定义的业务概念
- 示例:“高价值客户”的定义(消费>5000且活跃>30天)
应用级变量
- 定义:单次请求传入的临时数据
- 示例:当前用户ID、申请金额、商品ID
规则编写时可以引用任何层级的变量。系统自动解析依赖关系,在运行时注入正确的值。
2.规则的租户隔离
每个租户都有自己的规则空间:
- 租户A的规则只能被租户A的请求触发
- 修改租户A的规则不影响租户B
- 规则执行时使用的变量、数据源都是租户隔离的
存储设计:
每条规则记录都包含tenant_id字段。SQL查询时自动带上租户过滤条件,防止越权。
3.规则的继承与覆盖
这是降低配置成本的关键机制。
基础规则集
- 由SaaS厂商维护,是所有租户的默认配置
- 包含通用的业务规则模板
租户覆盖
- 租户可以“继承”基础规则集,然后选择覆盖其中部分规则
- 未被覆盖的规则仍然沿用基础规则
这种设计的好处:
- 新租户入驻时,默认拥有完整的基础规则,开箱即用
- 需要个性化时,只修改差异部分,不需要重头配置
- 基础规则集升级时,未覆盖的租户自动获得更新
4.规则的灰度发布
在多租户环境下,规则变更的风险被放大了,一个规则bug可能影响所有租户。
灰度发布流程:
- 在测试环境验证新规则
- 发布到生产环境,但只对白名单租户生效
- 观察这些租户的数据,确认无误
- 逐步扩大灰度范围(10% → 50% → 100%)
- 如有问题,立即回滚,只影响灰度租户
三、数据源层面的租户隔离
规则引擎不仅需要在规则层面隔离,还需要在数据访问层面隔离。
1.多数据源路由
不同的租户可能使用不同的数据库:
- 大租户:独立数据库实例
- 中小租户:共享数据库、独立schema
- 小微租户:共享数据库、共享schema(tenant_id区分)
规则引擎在执行时需要动态选择正确的数据源。
2.动态SQL生成
规则中可能包含对业务表的查询。这些查询语句需要自动附加租户过滤条件。
例如,规则中写“查询用户近30天的订单总额”,执行的SQL应该自动变成:
租户ID从当前请求上下文中隐式获取,规则编写者不需要手动传入。
四、实战案例:多租户CRM的审批流配置
1.场景描述
某SaaS CRM系统,客户(租户)的审批流程各不相同:
- 租户A:简单审批(销售→老板)
- 租户B:分级审批(销售→总监→财务→老板)
- 租户C:条件审批(<1万销售审批,1-5万总监审批,>5万老板审批)
2.规则引擎的表达方式
决策流配置
通过可视化的决策流编辑器,租户B可以自己画出审批节点和流转条件。
决策表配置
租户C的条件审批可以表达为一张决策表:
金额范围 | 下一审批人 |
<10000 | 销售主管 |
10000-50000 | 销售总监 |
>50000 | 总经理 |
租户C不需要开发介入,直接在后台配置这张表。
3.租户之间的互不影响
租户A修改了自己的审批流程,租户B和C完全感知不到。每个租户拥有独立的决策流实例和版本历史。
五、SaaS厂商需要考虑的其他问题
1.规则执行性能
多租户环境下,规则总数可能急剧膨胀。每个租户有自己的规则集,加起来可能有数万条规则。
性能优化策略:
- 规则预编译:将租户规则提前编译为可执行代码,缓存起来
- 租户级缓存:相同租户的相同请求,结果可以缓存
- 异步执行:非实时要求的场景,放入队列异步处理
2.版本回滚
租户修改规则后发现问题,需要能够一键回滚到之前的版本。
规则的历史版本应该保留,并提供可视化的差异对比(哪些规则变了、变前后有什么不同)。
3.操作审计
租户管理员可以查看本租户内的规则操作记录:谁、什么时候、改了什么。
SaaS厂商需要更高级别的审计:哪个租户在什么时间修改了什么规则(用于排障和合规)。
4.计费模式
规则引擎本身也可以作为计费的一个维度:
- 按规则数量阶梯收费
- 按决策调用次数收费
- 按租户使用的功能模块收费
结尾:
“千企千面”不是一句口号,而是SaaS企业的生存之道。
不能用硬编码的方式去应对每个客户的个性化需求,那是一条走不远的路。
规则引擎提供了另一种思路:把业务逻辑的执行权从开发人员手中,部分转移到租户或运营人员手中。系统提供能力和框架,租户根据自己的需要填充内容。这种模式下,开发团队可以专注于平台能力的建设,而不是陷入一个个定制需求的泥潭。
一套代码,千企千面,这才是SaaS应有的姿态。
如果您对规则引擎有疑问,可以与我们一起交流。若想体验,有在线Demo:https://rules.bctools.cn