引言
通过上一篇文章技术架构篇,大家对风控平台的整体系统架构都有了一定的了解。这一篇文章,我们重点讲解一下风控平台的核心系统之一的规则引擎。从产品功能设计到技术实现,会深入到每一个细节,同时也会附带一些关键节点的代码。
一、为什么要使用规则引擎
我们为什么使要用规则引擎?传统的开发模式是不是也可以支持业务提出的需求?在回答这个问题前,我们先简单回顾一下上一篇文章提到的,业务人员对于系统的一些核心需求。
支持每个业务线可以独立运营。风控策略的部署需要立即生效,策略编辑界面需要对非技术人员友好一些。学习成本不能太高。
如果使用传统的开发模式,我们需要这么做:
1、业务产品运营与风控产品沟通需求,风控产品整理汇总业务需求,提给开发团队和测试团队并排期。
2、每条业务线由于业务特征不同,需定制不同的审核接口。
3、风控技术团队排期,开发、测试、发布,风控产品验收。
4、业务验收。
如果使用传统的开发模式,我们会遇到这些问题:
1、业务需求沟通成本太大且频繁。
2、业务需求迭代周期太长,无法满足业务快速响应的要求。
3、需求迭代成本过高且对产研团队价值不大。
4、技术接入成本太大,系统维护成本太大。
基于对传统开发模式的分析,我们就此得出结论:
1、传统开发模式无法高效的支持业务需求。
2、需求沟通和系统维护成本大,投入产出比低。
3、各个团队职责划分不清晰,无法高效的协同完成既定目标。
二、什么是规则引擎
规则引擎是一个低代码平台。既可以支持实时配置审核策略以及命中策略后的处置方式,也可以支持动态编排审核流程。
支持AB-TEST模式,可用于训练风控策略&优化运营策略。
支持不同版本之间的发布和回滚。
支持审核记录查询和各种报表统计。
不同的风险事件可以用于支持多个业务场景的审核需求,不同的风险事件数据是相互隔离的。
用户群体既可以是产研部门的同学,也可以是运营部门的同学。不需要懂技术,零编程经验的小白也可以使用。但是需要具备一定的逻辑思维能力。
三、技术选型
GROOVY
基于JVM的敏捷开发语言,与JAVA完美的兼容。用于动态执行规则脚本。规则的编辑及运行都是基于GROOVY做了一层封装。类加载机制与JAVA相同,开发者需要做好缓存的维护防止频繁的执行类加载流程。
MYSQL
针对B端场景对读写的性能没有要求。主要用于B端产品功能和报表功能的实现。
MONGO
用于C端审核功能相关数据存储及统计。选择MONGO主要基于以下4点考虑:
1、没有事务的需求。
2、读写性能优于MYSQL,复杂条件查询优于REDIS。
3、非结构化存储,完美的解决了不同业务场景,对于不同业务字段的存储问题。极大的节省了开发成本。
4、自带分库分表能力,不同业务场景可以根据风险事件自动拆分集合,无需引入第三方分库分表的插件。不同业务场景的数据天然的隔离,极大的方便了开发人员性能调优。
ROCKET MQ
用于系统模块与模块之间的解耦。
REDIS
用于无复杂查询需求的读写场景和临时数据缓存场景,例如:风控策略、审核任务结果、交易排行榜等。
四、产品功能划分
规则引擎
规则引擎属于B端的一套内部管理系统,他主要提供风险事件 的定义、风控策略 的部署、审核记录 的查询导出及汇总统计、风险名单 的管理以及风险预警消息查询这几大产品功能模块。
规则引擎的用户群体也是公司内部人员。因为是公司内部系统,业务部门与业务部门之间的数据权限和功能权限是需要横向隔离的。同时单个业务部门内部的分工不同,数据权限和功能权限也是需要纵向隔离的。所以需要配合账号权限系统,定义好组织架构,划分用户、用户组、角色以及角色权限,防止横向越权 和纵向越权的情况发生。针对一些业务的敏感信息需要脱敏展示。
先看一下功能清单,如下图:

1、风险事件
1.1、风险事件&风险管控
风险事件在风控平台里是全局唯一的。业务方接入时,由风控团队进行分配,调用风控审核接口时同步带入。每个业务场景都有属于自己的风险事件,不同风险事件下的数据都是隔离的,以此保证每个业务场景都可以独立运营,也便于数据和权限的管理。
对于每次风控审核都会输出一个风险等级,不同风险等级映射的风险处置也是需要在事前沟通确认。例如:通过(暂未发现风险、低风险),人工审核(中低风险、中风险),拦截(高风险,极高风险)。
1.2、风险指标
风险指标是规则引擎中最小粒度的单位。风控模型(规则集、评分卡、决策树等)是由多个规则(风险指标+逻辑表达式)组成的。例如:【交易金额】 > 1000。
风险事件 | 指标名称 | 指标编码 | 指标类型 | 数据类型 | 默认值 | 描述 |
---|---|---|---|---|---|---|
线下扫码支付 | 用户手机号 | customerPhone | 基础指标 | 字符串 | - | 用户手机号 |
线下扫码支付 | 商户ID | merchantId | 基础指标 | 字符串 | - | 商户ID |
线下扫码支付 | 交易金额 | orderAmount | 基础指标 | 浮点型 | - | 交易金额 |
线下扫码支付 | 支付金额 | payAmount | 基础指标 | 浮点型 | - | 支付金额 |
线下扫码支付 | 2小时内同一商户同一用户交易金额为1000的倍数上下浮动1%的交易笔数 | tiezheng1 | 衍生指标 | 整数型 | 0 | 贴整交易 |
线下扫码支付 | 2小时内同一商户同一用户交易金额为100的倍数上下浮动2%的交易笔数 | tiezheng2 | 衍生指标 | 整数型 | 0 | 贴整交易 |
风险指标又分为基础指标 和模板指标两种类型。
基础指标
不同的业务场景的基础指标是不完全一致的。会有场景通用的指标,也会有特定场景下特有的指标。基础指标是不需要加工的,调用风控审核接口时由业务方传入。可以直接应用在风控模型中。以交易场景 和用户登录场景为例,例如:
场景通用指标:【请求IP】【用户手机号】【用户设备】
场景特有指标:
交易场景:【交易金额】【支付金额】【抵用券金额】【订单号】【商户ID】
用户登录场景:【登录方式】
模板指标
模板指标是基于基础指标进行加工得出的。加工能力由风险特征平台提供。
例如:【最近X小时内,同一用户支付成功的总金额】【最近X小时内,同一商户支付成功的用户数量】。
这里就不展开了,下一篇文章会详细讲述。
2、策略中心
2.1、策略管理
2.1.1、功能描述:
一个风险事件由多条风控策略组成,每条风控策略都会预设策略阈值(即风险分对应的风险等级)。一条风控策略又由多条规则集组成。每条规则集会配置对应的风险分,命中时则会根据不同的策略模式记录或累加风险分。
风险等级可自定义划分,例如:暂未发现风险(0 ~ 20),低风险(20 ~ 40),中低风险(40 ~ 60),中风险(60 ~ 80),高风险(80 ~ 100),极高风险(>= 100)。
风控策略模式有3种,最坏匹配、权重匹配、自定义匹配。
最坏匹配:取所有命中规则集,风险分最高值,没有命中风险分默认为0。再通过策略阈值找到最终的风险等级。
权重匹配:取所有命中规则集,风险分累加值,没有命中风险分默认为0。再通过策略阈值找到最终的风险等级。
自定义匹配:自定义逻辑表达式,true为极高风险,false为暂未发现风险。例:(RULESET1 || RULESET2) && RULESET3
风控策略类型 有2种,实时审核 和离线审核 ,分别对应电商实时审核场景 和离线审核任务场景。
通过调整风控策略的执行优先级 和命中即终止可以决定每次审核任务的执行路径。
所有风控策略执行完毕后,取所有命中策略的风险等级中最高风险等级,再通过风险事件预设的管控配置得到最终的风控审核建议(通过、人工审核、拦截)。
2.1.2、案例讲解:
风险事件配置:
风险事件名称 | 管控结果 | 风险等级 |
---|---|---|
线下扫码支付 | 通过 | 暂未发现风险、低风险 |
线下扫码支付 | 人工审核 | 中低风险、中风险 |
线下扫码支付 | 拦截 | 高风险、极高风险 |
策略配置:
风险事件名称 | 策略名称 | 执行顺序 | 命中即终止 | 策略模式 | 规则集名称 | 命中规则集风险分 |
---|---|---|---|---|---|---|
线下扫码支付 | 风控策略A | 1 | 否 | 最坏匹配 | 非本地交易 | 40 |
线下扫码支付 | 风控策略A | 1 | 否 | 最坏匹配 | 大额交易 | 60 |
线下扫码支付 | 风控策略A | 1 | 否 | 最坏匹配 | 非营业时间交易 | 90 |
线下扫码支付 | 风控策略B | 2 | 否 | 权重匹配 | 交易频率 | 30 |
线下扫码支付 | 风控策略B | 2 | 否 | 权重匹配 | 交易额度 | 20 |
线下扫码支付 | 风控策略B | 2 | 否 | 权重匹配 | 用户刷单 | 50 |
策略执行:
风险事件名称 | 策略名称 | 执行顺序 | 命中即终止 | 策略模式 | 命中规则集 | 风险分 | 风险等级 |
---|---|---|---|---|---|---|---|
线下扫码支付 | 风控策略A | 1 | 否 | 最坏匹配 | 【非营业时间交易】 | 90 | 高风险 |
线下扫码支付 | 风控策略B | 2 | 否 | 权重匹配 | 【交易频率】【交易额度】 | 50 | 中低风险 |
风控审核结果:
高风险 -> 拦截,最终这笔风控审核结果为【拦截】。
2.2、规则管理
2.2.1、功能描述:
一个规则集由多个规则组成,一个规则就是一个逻辑表达式,一个逻辑表达式由一个或多个风险指标组成。
规则集模板类型有2种,统计模板和条件模板。
统计模板:
统计类的规则主要应用于防刷场景。统计时间为一个时间滑块,统计维度支持多个风险指标,计算方式有统计次数、统计个数、统计求和。
例:
业务场景:线下扫码支付
统计次数:5分钟之内同一个用户成功交易订单数。
统计个数:5分钟之内同一个商户成功交易的用户数。
统计求和:5分钟之内同一个商户成功交易金额。
条件模板:
条件类的规则可以支持任意场景的规则编排。规则本身是通用的,不具有任何的业务含义。真正的业务含义需要结合风险事件和风险指标来解释。
例:
业务场景:线下扫码支付
规则配置:【交易IP归属省】不等于【商户注册归属省】
业务含义:跨省交易
规则集执行条件有2种,满足以下所有条件和满足以下任意条件。
满足以下所有条件: 多个规则同时命中即为命中。
满足以下任意条件: 多个规则命中一个即为命中。
2.2.2、案例讲解:
规则集配置:
风险事件 | 应用策略 | 规则集名称 | 模板类型 | 执行条件 | 规则配置 |
---|---|---|---|---|---|
线下扫码支付 | 策略A | 用户刷单 | 统计模板 | 满足以下所有条件 | 5分钟内同一个用户支付成功订单数大于10 |
线下扫码支付 | 策略A | 异地大额交易 | 条件模板 | 满足以下所有条件 | 【交易IP归属省】 不等于 【商户注册归属省】 |
线下扫码支付 | 策略A | 异地大额交易 | 条件模板 | 满足以下所有条件 | 【支付金额】 大于 【10000】 |
规则集执行:
风险事件 | 应用策略 | 规则集名称 | 模板类型 | 执行条件 | 规则配置 | 规则命中 |
---|---|---|---|---|---|---|
线下扫码支付 | 策略A | 用户刷单 | 统计模板 | 满足以下所有条件 | 5分钟内同一个用户支付成功订单数大于10 | 未命中 |
线下扫码支付 | 策略A | 异地大额交易 | 条件模板 | 满足以下所有条件 | 【交易IP归属省】 不等于 【商户注册归属省】 | 命中 |
线下扫码支付 | 策略A | 异地大额交易 | 条件模板 | 满足以下所有条件 | 【支付金额】 大于 【10000】 | 未命中 |
规则集结果:
风险事件 | 应用策略 | 规则集名称 | 模板类型 | 执行条件 | 规则集命中 |
---|---|---|---|---|---|
线下扫码支付 | 策略A | 用户刷单 | 统计模板 | 满足以下所有条件 | 未命中 |
线下扫码支付 | 策略A | 异地大额交易 | 条件模板 | 满足以下所有条件 | 未命中 |
2.3、处置管理
一个风控策略可以配置一个处置管理,处置管理包含风险提示文案、安全验证方式。风控策略命中时触发映射到处置管理。
风险提示文案: 风控运营人员可针对不同策略配置多个不同的提示文案,若命中策略时有多个文案选择,则随机选择一个反悔。这样可以防止攻击者通过提示文案猜出拦截原因。
安全验证方式: 风控策略分析师可针对不同风险等级的策略,配置不同的验证方式,如滑块验证码、短信验证、安全密码验证等。与直接拦截不同的是,这样做既可以对非本人操作的风险进行拦截,又可以降低本人因环境或者设备的变化操作时引起的误拦截。
小额免密: 针对交易类场景的一种特殊的安全验证方式。如果用户在客户端开启了小额免密的开关并设置免密的额度上限,那么用户在实际的交易环节中命中了小额免密相关的风控策略,则可以跳过输入密码环节,直接完成支付动作。
3、风险名单
3.1、名单定义管理:
各个业务可以在各自的风险事件下,自定义名单类别并应用到风控策略中,风险名单在不同风险事件下是相互隔离的。
风险事件 | 名单类别 | 名单使用说明 | 关联数据总数 | 创建人 | 创建时间 |
---|---|---|---|---|---|
线下扫码支付 | 黑名单 | 用于拦截有风险的交易用户、商户、设备等。 | 100 | 哈哈少儿 | 2024-04-07 12:00:00 |
线下扫码支付 | 灰名单 | 黑名单的前置环节,用于留观后续情况再决定是否升级至黑名单。 | 200 | 哈哈少儿 | 2024-04-07 12:00:00 |
线下扫码支付 | 白名单 | 用于特定商户特定时间不受风控审核影响。 | 10 | 哈哈少儿 | 2024-04-07 12:00:00 |
3.2、名单数据管理:
3.2.1、名单数据定义:
名单数据挂载在名单下,不同类型的名单之间,数据是相互隔离的。名单数据的类型可以自定义,如手机号、商户ID、设备ID、身份证等。也可以设置数据有效期(生效时间~失效时间),满足业务对于不同业务场景,数据时效性的各类需求。
风险事件 | 名单名称 | 名单类型 | 名单值 | 名单有效期 | 名单来源 | 创建人 | 创建时间 |
---|---|---|---|---|---|---|---|
线下扫码支付 | 黑名单 | 手机号 | 13511131119 | 2028-04-07 | 风控运营 | 哈哈少儿 | 2024-04-07 12:00:00 |
商户入网 | 黑名单 | 营业执照号 | ABC12382393 | 2028-04-07 | 风控运营 | 哈哈少儿 | 2024-04-07 12:00:00 |
3.2.2、名单匹配策略:
技术实现上,我们采用了粗粒度匹配(redis bloomfilter) + 细粒度匹配(redis + mysql),这样可以大幅度提升系统的吞吐量。在使用bloomfilter时需要注意,他可以明确告诉你目标值不存在,但不能明确告诉你目标值一定存在,不清楚bloomfilter特性的小伙伴们在使用前最好先去学习一下,以免在理解上有所偏差。

执行顺序 | 匹配模式 | 实现方式 | 系统性能 | 目的 |
---|---|---|---|---|
1 | 粗粒度 | redis bloomfilter | 极高 | 判断目标值是否存在,不存在则返回,存在则继续下一步。 |
2 | 细粒度 | redis | 极高 | 判断目标值是否存在,有结果则返回,没有结果则继续下一步。 |
3 | 细粒度 | mysql | 低 | 判断目标值是否存在,并加入redis缓存。 |
4、风控大脑
4.1、风控审核记录
用于查询风控审核记录,业务人员可以根据实际需求,通过不同的搜索条件,查询或下载需要的数据。
不同的业务场景,审核记录的字段也是不一样的。审核记录由通用字段(风控域)和业务特有字段(业务域)组成。
例:
扫码支付:
事件名称 | 审核时间 | 命中策略 | 风险等级 | 管控状态 | 商户ID | 用户ID | 交易金额 | 支付金额 | 交易状态 | 支付方式 | 交易IP归属省 | 交易IP归属市 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
扫码支付 | 2025-4-5 12:00:00 | 异地交易,大额交易 | 高风险 | 拦截 | 1 | 2 | 120000 | 120000 | 待支付 | - | 上海市 | 上海市 |
扫码支付 | 2025-4-5 11:30:00 | - | 暂未发现风险 | 通过 | 1 | 2 | 50 | 50 | 支付成功 | 支付宝 | 上海市 | 上海市 |
扫码支付 | 2025-4-5 11:00:00 | 留观商户 | 中风险 | 人工审核 | 1 | 2 | 100 | 50 | 支付成功 | 微信 | 上海市 | 上海市 |
商户入网:
事件名称 | 审核时间 | 命中策略 | 风险等级 | 管控状态 | 营业执照号 | 营业执照名称 | 法人手机号 | 法人身份证号 |
---|---|---|---|---|---|---|---|---|
商户入网 | 2025-4-5 12:00:00 | 黑名单 | 高风险 | 拦截 | ABC | 上海哈哈少儿有限公司 | 135****4585 | 310110********1447 |
商户入网 | 2025-4-5 11:00:00 | 灰名单 | 中风险 | 人工审核 | DEF | 上海二哥有限公司 | 139****7983 | 310190********1337 |
商户入网 | 2025-4-5 10:00:00 | - | 暂未发现风险 | 通过 | GHI | 上海马格雷迪有限公司 | 136****9835 | 310910********9046 |
针对不同业务场景业务特有字段的不同,我们没有选择使用mysql来存储审核记录,而是选择使用mongoDB来存储审核记录。做出这样的选择,主要是基于以下几点考虑。
数据库 | 读性能 | 写性能 | 分库分表 | 扩展性 |
---|---|---|---|---|
MYSQL | 低 | 低 | 引入三方插件,不同业务场景以风险事件命名 + 固定名称,手动建表。 | 添加字段需要执行脚本,若此时数据量较大,执行耗时会很长。 |
MONGO | 高 | 高 | 无需三方插件,不同业务场景以风险事件命名 + 固定名称,自动建集合。 | 添加字段无需执行脚本,程序端直接写入数据即可。 |
4.2、监控报表
监控报表主要用于运营人员来查看风控策略的实际运行情况从而提升运营人员的工作效率。
通过监控报表我们可以直观的看到,在一个时间范围内,不同风险事件下的不同风控策略命中的数量以及拦截比例。也可以通过不同的维度汇总统计(商户ID、用户手机号、用户设备号、IP归属省、交易金额等)。
例:
统计日期 | 策略编号 | 策略名称 | 风险等级 | 审核总数 | 命中审核数 | 审核命中率 | 审核商户数量 | 命中商户数 | 商户命中率 | 审核用户数量 | 命中用户数 | 用户命中率 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2025-04-06 | HAHA1 | 异地交易 | 中风险 | 10000 | 2000 | 20% | 4000 | 400 | 10% | 7000 | 700 | 10% |
2025-04-06 | HAHA2 | 大额交易 | 高风险 | 10000 | 1000 | 10% | 4000 | 40 | 1% | 7000 | 70 | 1% |
2025-04-06 | HAHA3 | 用户刷单 | 低风险 | 10000 | 1000 | 20% | 4000 | 100 | 2.5% | 7000 | 100 | 2.5% |
4.3、交易排行榜
交易排行榜是针对交易类场景定制的一个功能,其中包含线下扫码支付、商城在线支付、团购在线支付等。通过交易排行榜我们可以查看到实时的交易情况。
交易排行榜的技术实现方式采用的是实时统计 和T+1离线统计。
实时统计: 消息队列回调 + redis zset。通过支付成功回调事件触发,根据不同维度(商户ID、用户手机号、设备ID等)同步计算相关的交易信息。如下表格:
交易排名 | 商户ID | 商户名称 | 成功交易数 ↓ | 成功交易金额 | 成功支付金额 |
---|---|---|---|---|---|
1 | 101 | 上海哈哈少儿有限公司 | 20000 | 500000 | 490000 |
2 | 102 | 上海马格雷迪有限公司 | 18000 | 600000 | 580000 |
3 | 103 | 上海林老二有限公司 | 16000 | 34000 | 30000 |
4 | 104 | 上海源律律师事务所 | 15000 | 89000 | 80000 |
5 | 105 | 上海宋老毛有限公司 | 13000 | 10000 | 9000 |
6 | 106 | 上海宋小工有限公司 | 10000 | 7800 | 7000 |
X | ...... | ...... | ...... | ...... | ...... |
T+1离线统计: 基于实时统计,以天为单位持久化到mysql表中,用于实现历史数据查询以及数据图表的展示。如下图:

4.4、交易审核概览
交易审核概览也是针对交易类场景定制的一个功能,可以把他认为是交易排行榜的衍生功能。
交易审核概览会把每一笔交易数据以小时粒度进行划分,按照不同的维度(交易金额分布、交易地区分布、交易时间分布)进行汇总统计。除了交易的相关指标外,也会统计审核的通过率和拦截率。如下表格。
风控审核报表:
统计维度 | 统计时间 | 审核总数量 | 通过数量 | 人工审核数量 | 拦截数量 | 拦截率 |
---|---|---|---|---|---|---|
交易 | 2025-04-07 | 200000 | 180000 | 1000 | 19000 | 10.55% |
商户 | 2025-04-07 | 40000 | 38000 | 1000 | 1000 | 2.5% |
用户 | 2025-04-07 | 100000 | 90000 | 1000 | 9000 | 9% |
交易金额分布报表:
金额类型 | 统计时间 | 金额范围 | 交易总数 | 成功交易数 |
---|---|---|---|---|
交易金额 | 2025-04-07 | 0 ~ 5000 | 5000 | 4900 |
交易金额 | 2025-04-07 | 5000 ~ 10000 | 8000 | 7900 |
交易金额 | 2025-04-07 | 10000 ~ 50000 | 1000 | 998 |
交易金额 | 2025-04-07 | 50000 ~ 100000 | 50 | 49 |
交易金额 | 2025-04-07 | > 100000 | 50 | 49 |
支付金额 | 2025-04-07 | 0 ~ 5000 | 5000 | 4900 |
支付金额 | 2025-04-07 | 5000 ~ 10000 | 8000 | 7900 |
支付金额 | 2025-04-07 | 10000 ~ 50000 | 1000 | 998 |
支付金额 | 2025-04-07 | 50000 ~ 100000 | 50 | 49 |
支付金额 | 2025-04-07 | > 100000 | 50 | 49 |
交易地域报表:
交易归属市 | 统计时间 | 交易总数 | 成功交易数 |
---|---|---|---|
上海市 | 2025-04-07 | 500000 | 490000 |
苏州市 | 2025-04-07 | 8000 | 7900 |
三亚市 | 2025-04-07 | 10000 | 9980 |
宁波市 | 2025-04-07 | 5000 | 4900 |
交易分时报表:

5、风险预警
风险预警的定位是一个辅助工具,帮助策略分析师或者业务运营人员可以及时的感知到风险并介入处理。这样就可以把资损控制在最小范围内。
风险预警策略以及触达方式可以提前自定义。触达方式也可以视不同的风险等级而定,从低到高,逐步升级。企业微信|飞书|钉钉 -> 短信 -> 业务负责人电话 -> 部门负责人电话。
例:
某日凌晨3点~5点,交易量偏离正常阈值范围数倍(正常阈值范围是根据以往的交易记录计算得来的),并且命中跨境交易策略的交易占比超过50%。此时风险预警系统感知到风险(命中风险预警策略)后会根据提前定义好的触达方式进行预警。

模型运行引擎
模型运行引擎的功能就比较简单,他属于风控策略的执行层。只需要处理风控网关发送的审核请求,通过风险事件关联到风控策略,执行并返回审核结果。
执行流程:

注意事项:
异常捕获粒度: 通常一个风险事件下,由N个策略 * M个规则集 * O个规则组成,执行过程中可能会由于基础指标(业务入参)、规则配置问题和其他未知因素导致执行异常。为了保证业务人员可以及时感知到异常,也为了保证影响面的最小化。我们会在规则执行层面捕获异常,当条规则默认未命中,不影响后续规则的执行。同时通过飞书、企微的方式触达到对应的业务人员,业务人员收到预警后需及时介入处理。
超时熔断降级: 规则引擎在向风险特征平台请求获取风险指标数据时,由于风险指标计算逻辑复杂、网络延迟等问题导致响应时间超出预期从而会影响整个风控审核的接口性能,风控审核的接口性能又可能会影响业务接口的性能。所以,为了保证风控审核能快速响应,单个风险指标加工请求需要做超时熔断,熔断后取风险指标的默认值。牺牲一定的策略完整性保证系统响应。
核心代码:
POM依赖
POM
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.9</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.9</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-jsr223</artifactId>
<version>3.0.9</version>
</dependency>
动态脚本模型定义
GroovyClassDTO
package cn.com.engine.exec.common.groovy;
import groovy.lang.Script;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class GroovyClassDTO {
private Script scriptDTO;
private Long updateTime;
}
动态脚本模型管理
GroovyClassManager
package cn.com.engine.exec.common.groovy;
import java.util.Map;
import com.google.common.collect.Maps;
import cn.com.engine.exec.common.util.MD5Util;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import lombok.Getter;
import lombok.Setter;
public class GroovyClassManager {
@Getter
@Setter
private static Map<String, GroovyClassDTO> classCache = Maps.newConcurrentMap();
public static int size() {
return classCache.size();
}
public static boolean isCached(String key) {
return classCache.containsKey(key);
}
public static Script getClass(String script) {
Map<String, GroovyClassDTO> map = classCache;
String key = MD5Util.md5(script);
GroovyClassDTO groovyClassDTO = map.get(key);
if(null != groovyClassDTO) {
groovyClassDTO.setUpdateTime(System.currentTimeMillis());
return groovyClassDTO.getScriptDTO();
}
Script scriptDTO = newClass(script);
map.put(key, new GroovyClassDTO(scriptDTO, System.currentTimeMillis()));
return scriptDTO;
}
private static Script newClass(String script) {
return new GroovyShell().parse(script);
}
}
动态脚本执行器
GroovyExecutor
package cn.com.engine.exec.common.groovy;
import java.util.Map;
import java.util.Map.Entry;
import javax.script.ScriptException;
import org.apache.commons.lang.StringUtils;
import org.codehaus.groovy.runtime.InvokerHelper;
import com.google.common.collect.Maps;
import groovy.lang.Binding;
import groovy.lang.Script;
public class GroovyExecutor {
private static final String GROOVY_KEY_PREFIX = "$";
private static Binding initLocalBinds(Map<String, Object> paramsMap, Binding binding) {
if (null == paramsMap || paramsMap.size() == 0)
return binding;
for (Entry<String, Object> entry : paramsMap.entrySet()) {
binding.setVariable(entry.getKey(), entry.getValue());
}
return binding;
}
public static Object execBySimple(String script, Map<String, Object> paramsMap)
throws NoSuchMethodException, ScriptException {
if (StringUtils.isEmpty(script)) {
return null;
}
Binding binding = initLocalBinds(paramsMap, new Binding());
Script sheel = GroovyClassManager.getClass(script);
return InvokerHelper.createScript(sheel.getClass(), binding).run();
}
public static String generatorFieldKey(String fieldCode) {
return GROOVY_KEY_PREFIX + fieldCode;
}
}
风控网关
风控网关是对外提供审核任务的唯一入口,他不处理具体的审核任务,只做一些简单的鉴权、参数合法性校验、幂等性校验、审核任务派发、审核记录落地、风险预警等功能。
执行流程:

技术对接文档
接口定义:
风控任务同步执行:cn.com.gateway.api.EngineTaskExecInterface#execSync
公共入参:
字段含义 | 字段名称 | 字段类型 | 是否必填 | 字段描述 |
---|---|---|---|---|
请求头 | header | Object | 是 | |
请求唯一标识 | requestId | String | 是 | 任务幂等 |
请求IP | requestIp | String | 是 | 外部请求IP |
请求时间 | requestTimestamp | Long | 是 | |
请求体 | body | Object | 是 | |
风险事件编码 | riskEventCode | String | 是 | 风控提供 |
模型类型 | referenceType | String | 否 | 风控提供 |
模型编码 | referenceCode | String | 否 | 风控提供 |
扩展参数 | paramsMap | Map<String,Object> | 是 | 业务场景自定义 |
交易场景扩展入参:
字段含义 | 字段名称 | 字段类型 | 是否必填 | 字段描述 |
---|---|---|---|---|
订单编号 | orderNo | String | 是 | |
订单状态 | orderStatus | Byte | 是 | 枚举(待支付、支付成功、支付取消、待安全验证) |
订单类型 | orderType | String | 是 | |
订单金额 | orderAmount | BigDecimal | 是 | |
支付金额 | payAmount | BigDecimal | 是 | |
抵用券金额 | discountAmount | BigDecimal | 是 | |
交易IP | requestIp | String | 是 | |
商户ID | merchantId | String | 是 | |
用户ID | customerId | String | 是 | |
用户手机号 | customerPhone | String | 是 | |
设备ID | deviceId | String | 是 | |
交易发起时间 | tradeTimestamp | Long | 是 | 时间戳 |
订单来源 | orderSource | String | 是 | 枚举(支付宝小程序、微信小程序、H5、APP) |
订单支付方式 | orderPayMethod | String | 是 | 枚举(支付宝、微信) |
订单支付卡类型 | orderCardType | String | 是 | 枚举(借记卡、信用卡) |
OPENID | openID | String | 是 | |
交易经度 | longitude | String | 否 | |
交易纬度 | latitude | String | 否 |
退款场景扩展入参:
字段含义 | 字段名称 | 字段类型 | 是否必填 | 字段描述 |
---|---|---|---|---|
退款编号 | refundNo | String | 是 | |
退款总金额 | refundTotalAmount | BigDecimal | 是 | |
退款支付金额 | refundPayAmount | BigDecimal | 是 | |
退款抵用券金额 | refundDiscountAmount | BigDecimal | 是 | |
订单编号 | orderNo | String | 是 | |
订单类型 | orderType | String | 是 | |
订单金额 | orderAmount | BigDecimal | 是 | |
支付金额 | payAmount | BigDecimal | 是 | |
抵用券金额 | discountAmount | BigDecimal | 是 | |
商户ID | merchantId | String | 是 | |
用户ID | customerId | String | 是 | |
用户手机号 | customerPhone | String | 是 | |
退款发起时间 | refundBeginTimestamp | Long | 是 | 时间戳 |
退款完成时间 | refundEndTimestamp | Long | 否 | 时间戳 |
退款失败原因 | refundFailReason | String | 否 |
公共出参:
字段含义 | 字段名称 | 字段类型 | 是否必填 | 字段描述 |
---|---|---|---|---|
响应编码 | code | String | 是 | |
响应信息 | message | String | 是 | |
响应体 | result | Object | 是 | |
风险事件编码 | riskEventCode | String | 是 | |
模型类型 | referenceType | String | 否 | |
模型编码 | referenceCode | String | 否 | |
风险分 | riskScore | BigDecimal | 是 | |
风险等级 | riskLevel | Integer | 是 | 枚举(0 ~ N),可以自行定义风险等级 |
管控建议 | riskSuggestion | String | 是 | 枚举(通过、人工审核、拦截),也可以自行定义管控建议 |
管控提示文案 | riskWarnText | String | 否 | |
处置建议 | disposeSuggestion | List | 否 | 枚举(验证方式编码) |
技术对接注意事项
1、接入方需要根据自身业务实际情况,设置接口超时熔断时间并做好降级措施。保证在极端情况下自身业务不受外部系统影响。
2、公共参数中请求唯一标识,需要结合实际业务场景设置。相同的请求唯一标识,规则引擎不会重复审核,会返回第一次请求返回的审核结果。
总结
到这里,规则引擎的内容就介绍完了。通过这篇文章,我们了解了规则引擎的系统构成以及如何对外提供风控审核能力。业务人员是如何通过规则引擎开展日常的工作。
接下来一篇文章,我会重点介绍风控平台另一个非常重要的系统-风险特征平台,作为规则引擎的数据提供方,机器审核最重要的环节之一,他是如何高效的为规则引擎提供强有力数据支持。