第二章:系统架构设计——微服务选型、核心模块与高可用原则

好,咱们进入正题。上一章聊了反欺诈策略的痛点,这一章我重点讲讲系统架构怎么搭。说白了,就是要把一个「看起来能跑」的系统,变成「真正扛得住」的生产级平台。

我个人习惯,做架构设计前先问自己三个问题:

  • 业务量多大?——峰值 QPS 多少,延迟要求多高
  • 策略多复杂?——规则数量、模型调用、外部数据源
  • 容错多高?——挂了能不能降级,数据能不能丢

想清楚这些,再谈选型才有意义。

2.1 微服务架构选型:为什么我选 Spring Cloud + Kubernetes

先说说选型。市面上微服务框架不少,Dubbo、Spring Cloud、Service Mesh 都有。我在项目中遇到过用 Dubbo 做内部 RPC 的,性能确实好,但到了云原生时代,Kubernetes 成了事实标准,Spring Cloud Alibaba 这套生态更接地气。

我建议这么选:

  • 服务注册与发现:Nacos,比 Eureka 稳定,支持配置中心
  • 网关:Spring Cloud Gateway,性能比 Zuul 好一个量级
  • 熔断降级:Sentinel,比 Hystrix 更灵活,支持实时监控
  • 配置中心:Nacos Config,热更新策略参数很方便
  • 部署编排:Kubernetes + Docker,弹性伸缩是刚需

核心原则:微服务不是越细越好。我见过有人把「规则解析」和「规则执行」拆成两个服务,结果一次策略调用要跨 5 个服务,延迟直接翻倍。反欺诈场景对延迟敏感,一般控制在 200ms 以内,服务粒度要适中。

2.2 核心模块划分:六个关键服务

嗯,这里我画了一张架构图,你看一眼就明白了。

反欺诈策略自动化决策系统——微服务架构图 API 网关 (Spring Cloud Gateway) 策略编排服务 规则链、决策树、评分卡 规则引擎服务 Drools / EasyRules 模型推理服务 ONNX / PMML 模型 特征工程服务 实时特征、离线特征 外部数据网关 三方数据、黑名单 决策日志服务 全量审计、回放 Redis 缓存 特征缓存、限流计数 MySQL / TiDB 策略配置、元数据 Elasticsearch 日志检索、分析

这张图里,我把系统拆成了 6 个核心服务。你想想看,每个服务各司其职,互不干扰。

2.2.1 策略编排服务

这是大脑。负责把策略配置解析成可执行的决策流。我在项目中遇到过策略版本混乱的问题,后来引入了 DAG(有向无环图)来管理规则依赖,每个版本都生成快照,回滚时一秒搞定。

2.2.2 规则引擎服务

执行层。我建议用 Drools 做复杂规则,用 EasyRules 做简单规则。为什么?Drools 的 RETE 算法在规则超过 100 条时优势明显,但启动慢;EasyRules 轻量,适合几十条规则的场景。

避坑指南:我曾经把 500 条规则全塞进一个规则文件,结果每次修改都要重新编译。后来改成按业务域拆分——风控规则、营销规则、反洗钱规则各一个文件,互不影响。

2.2.3 模型推理服务

机器学习模型跑的地方。我习惯用 ONNX Runtime,支持跨框架模型。注意一点:模型推理要设置超时,我一般设 50ms,超时就走降级策略,别让模型拖垮整个决策链路。

2.2.4 特征工程服务

特征计算是反欺诈的命门。实时特征用 Flink 算,离线特征用 Spark 预计算。我建议把特征分为三类:

特征类型 计算方式 存储 延迟要求
实时特征 Flink CEP Redis < 10ms
近线特征 Kafka Streams Redis + MySQL < 1s
离线特征 Spark 批处理 HBase / TiDB 天级

2.2.5 外部数据网关

调用三方数据源的地方。我设计了一个「熔断+降级+缓存」三层保护:

  • 熔断:连续 5 次超时,直接熔断 30 秒
  • 降级:返回默认值或上次缓存值
  • 缓存:TTL 设置 5 分钟,避免重复请求

2.2.6 决策日志服务

这个容易被忽视,但极其重要。每次决策都要记录:入参、出参、命中规则、耗时、版本号。为什么?审计需要,复盘需要,模型迭代也需要。我建议用 Kafka 异步写日志,别阻塞主流程。

2.3 高可用设计原则:别让系统在半夜挂了

做反欺诈系统,最怕什么?半夜流量高峰,系统挂了,欺诈交易全放过去了。我经历过一次,第二天被老板叫去喝茶。从那以后,高可用成了我的第一优先级。

我总结了四条原则:

2.3.1 无状态 + 水平扩展

所有服务都设计成无状态的。规则引擎、模型推理这些,不保存任何本地状态。这样 Kubernetes 可以随意扩缩容,流量大了加 Pod,流量小了减 Pod。

关键点:Session 信息放 Redis,不要放本地内存。否则 Pod 重启,用户就掉线了。

2.3.2 熔断降级 + 舱壁隔离

我用 Sentinel 做熔断。每个服务都设置线程池隔离,比如外部数据网关最多用 20 个线程,占满了就拒绝新请求,别拖垮其他服务。

降级策略我一般这么设计:

  • 规则引擎挂了 → 走默认规则(只检查最关键的 3 条)
  • 模型推理挂了 → 走规则引擎兜底
  • 外部数据挂了 → 用缓存数据或默认值

2.3.3 多活部署 + 流量调度

我建议至少两个机房,异地多活。流量通过 DNS 或全局负载均衡分发。注意一点:数据库也要跨机房同步,我用 TiDB 的 Raft 协议,强一致性,但延迟会高一点。如果业务能接受最终一致性,用 MySQL 主从 + 消息队列同步也行。

2.3.4 全链路监控 + 告警

没有监控的高可用是假的。我一般这么搭:

  • 指标:Prometheus + Grafana,关注 P99 延迟、错误率、QPS
  • 链路:SkyWalking,看每个请求经过哪些服务,哪里慢
  • 日志:ELK,搜索异常日志
  • 告警:PagerDuty,P0 级别 5 分钟电话通知

警告:别只监控平均值。我见过一个系统,平均延迟 50ms,但 P99 延迟 2 秒。平均值会骗人,一定要看分位值。

2.4 一个真实案例:双十一的流量冲击

我记得有一年双十一,流量是平时的 20 倍。我们的反欺诈系统扛住了,靠的就是前面说的这些设计。

具体做法:

  1. 提前扩容:Kubernetes 自动扩到 200 个 Pod
  2. 限流:网关层按用户 ID 哈希限流,每个用户每秒最多 5 次
  3. 降级:模型推理降级为规则引擎,延迟从 150ms 降到 30ms
  4. 缓存:特征缓存命中率 90%,减少外部调用

结果呢?系统全程在线,P99 延迟 80ms,零故障。嗯,这就是架构设计的意义。


公众号:蓝海资料掘金营,微信deep3321