一、为什么要把风控拆成三个服务?
先说说背景。我最早做风控系统时,所有逻辑都塞在一个单体应用里。
决策引擎、名单管理、额度计算,全搅在一起。刚开始还好,业务量一上来,问题就暴露了。
举个例子:名单服务需要高频更新黑名单,每次更新都要重启整个应用。决策服务那边还在跑实时交易,一重启就丢请求。你说尴不尴尬?
所以,拆分是必然的。但怎么拆?我踩过不少坑。
二、拆成三个服务:决策、名单、额度
2.1 决策服务
这是核心。它负责接收请求、编排规则、输出结果。说白了,就是「大脑」。
我习惯把决策服务做得尽量「无状态」。所有规则配置、模型参数都从外部加载。这样扩缩容特别方便。
关键设计原则:
- 决策服务不直接操作数据库
- 所有数据通过 RPC 或消息队列获取
- 规则引擎独立部署,支持热更新
2.2 名单服务
名单服务负责管理黑名单、白名单、灰名单。听起来简单,但坑不少。
我记得有一次,名单服务的内存缓存和数据库不一致,导致一个已经被拉黑的用户成功通过了审核。嗯,这事后来成了复盘的重点。
避坑指南:
我曾经在名单服务里直接用了 Redis 的过期策略,结果大量 key 同时过期,缓存雪崩。后来改成「主动过期 + 惰性删除」结合,才稳住。
2.3 额度服务
额度服务负责计算用户的可贷额度、可用额度。这个服务对一致性要求极高。
你想想看,如果两个请求同时修改额度,数据不一致了怎么办?
我建议用乐观锁 + 版本号机制。代码示例如下:
// 额度更新示例
public boolean updateQuota(String userId, double amount, long version) {
String sql = "UPDATE user_quota SET amount = amount - ?, version = version + 1 " +
"WHERE user_id = ? AND version = ?";
int rows = jdbcTemplate.update(sql, amount, userId, version);
return rows > 0;
}
三、拆分后我踩过的坑
3.1 坑一:服务间调用超时
拆分后,决策服务要调名单服务,名单服务要调额度服务。调用链一长,超时问题就来了。
我记得有一次,名单服务因为 GC 停顿了 2 秒,导致决策服务大量超时。整个风控链路都堵住了。
我的解决方案:
- 所有 RPC 调用设置合理的超时时间(建议 500ms 以内)
- 引入熔断机制,防止雪崩
- 关键路径上做本地缓存兜底
3.2 坑二:数据一致性
三个服务各自维护自己的数据库。但有些数据是共享的,比如用户的黑名单状态。
我曾经遇到过:名单服务更新了黑名单,但决策服务读到的还是旧数据。结果放行了一个高风险用户。
怎么解决?我建议用「最终一致性」方案:
- 使用消息队列同步变更事件
- 决策服务定期刷新本地缓存
- 关键场景下强制走主库查询
3.3 坑三:部署和运维复杂度
一个服务变成三个服务,部署、监控、日志收集的复杂度翻倍。
我刚开始没注意,结果每次上线都要手动改配置,累得够呛。
建议:
- 统一配置中心(如 Apollo、Nacos)
- 标准化日志格式,方便链路追踪
- 每个服务独立部署,互不影响
四、架构图:三个服务的协作关系
下面这张图展示了决策、名单、额度三个服务的核心协作流程:
五、总结一下
微服务拆分不是银弹。拆得好,系统灵活、可扩展。拆不好,复杂度翻倍、问题频出。
我个人觉得,最关键的是想清楚「边界」。每个服务该做什么、不该做什么,一开始就要定好。
另外,别追求完美。先拆出最核心的决策服务,名单和额度可以慢慢剥离。迭代着来,比一步到位稳妥得多。
最后送大家一句话:
拆分是为了解决问题,不是为了炫技。如果单体应用够用,就别瞎折腾。
公众号:蓝海资料掘金营,微信deep3321