实时交易规则
举例背景
在如今数字支付日益普及的时代,POS机的角色不可忽视。作为连接消费者与商家的纽带,POS机承载着大量的金融交易和数据传输。然而,随之而来的安全风险也日趋复杂和严峻。 本篇博客将带您踏入我们独特的世界,探索我是如何为POS机注入高强度的安全保护,提供无忧支付体验的。
早期方案
当产品提出某些需求,例如用户今日累计交易金额>10w
限制出款,然后由开发编码,在交易接口里面嵌入,然后执行发版,但是这种方案对实时性的得不到保障,以及发版带来影响交易的风险。
若过几天,产品又说,某一批商户用户今日累计交易金额>20w
限制出款,针对频繁的变动又该怎么办呢?
存在如下具有代表性的业务场景:
- 限制某个城市的机器不能交易
- 交易限额
- 针对有问题机器禁止消费
- 等
规则引擎带来的解决方案
在复杂多变的业务场景中,单靠我们日常处理判断的能力是不够的,规则变化快,不可 控因素多,业务场景复杂,都会加快开发人员处理规则的难度,减缓项目上线的难度,看我们如何使用规则引擎解决此时遇到的一些问题!
交易接口示例
处理交易调用规则核心代码,规则客户端代码内嵌在接口内,当触发交易时,首先请求配置的规则,由规则动态判断交易逻辑。
@Slf4j
@Service
public class TradeService {
@Resource
private RuleEngineClient ruleEngineClient;
@Resource
private DemoTransactionRecordsMapper demoTransactionRecordsMapper;
/**
* 交易处理
*
* @param tradeRequest 交易请求参数
* @return true交易成功
*/
@Transactional(rollbackFor = Exception.class)
public Boolean trade(TradeRequest tradeRequest) {
// 一些其他业务处理
// ...
try {
RuleSet ruleSet = this.ruleEngineClient.ruleSet();
TradeRuleModel tradeRuleModel = new TradeRuleModel();
// 复制参数,去请求规则引擎计算
BeanUtil.copyProperties(tradeRequest, tradeRuleModel);
// 调用规则引擎,并拿到返回结果
Output execute = ruleSet.execute(tradeRuleModel);
if (Objects.equals(execute.getClassType(), Boolean.class.getName())) {
Boolean value = (Boolean) execute.getValue();
if (!value) {
throw new RuntimeException("规则:交易失败!");
}
} else {
Object value = execute.getValue();
throw new RuntimeException("规则:" + value);
}
} catch (RuntimeException e) {
// 记录交易失败流水
// ..
throw e;
}
// 一些其他业务处理
// ...
// 记录成功交易流水
// ..
return true;
}
}
开发在不动以上稳定代码的情况下,如何保障业务正常迭代流转。规则示例如下,允许页面动态修改规则,不需要开发人员介入,提供了规则版本控制以及预览等,即能保证实时性,又能保证稳定性等
第一种需求:
判断此商户是否被限制消费,或被拉入黑名单,如果是,不可交易!
然后配置如下信息,不满足返回:已被限制消费!
第二种需求:
如果是优质商户,每天交易金额只能为100w
其他商户50w
配置如下信息,不满足返回:额度超限!
模拟请求参数,请求交易接口
{
"merNo": "M0001",
"sn": "A0001",
"factory": "厂商10",
"amount": 500000
}
请求接口后控制台日志打印如下:
2023-09-03 18:51:38 c.a.druid.pool.DruidAbstractDataSource : discard long time none received connection. , jdbcUrl : jdbc:mysql://rm-2ze27j116367ke9i93o.mysql.rds.aliyuncs.com:3306/rule_engine_v2?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8, version : 1.2.5, lastPacketReceivedIdleMillis : 1815124
2023-09-03 18:51:38 org.example.order.service.TradeService : 开始处理交易:TradeRequest(merNo=M0001, sn=A0001, factory=厂商10, amount=500000)
2023-09-03 18:51:38 c.r.c.h.FeignInvocationHandlerFactory : Request param is [ExecuteParam(code=tran-risk, input={factory=厂商10, amount=500000, merNo=M0001, sn=A0001})]
2023-09-03 18:51:39 c.r.c.h.FeignInvocationHandlerFactory : Direct result is Result(code=200, data=Output(value=[额度超限!], classType=java.util.Collections$SingletonList), message=执行成功, timestamp=2023-09-03 10:51:39)
2023-09-03 18:51:39 org.example.order.service.TradeService : 规则引擎返回结果:Output(value=[额度超限!], classType=java.util.Collections$SingletonList)
2023-09-03 18:51:39 org.example.order.service.TradeService : 规则限制交易:规则:[额度超限!]
第三种需求:
某个POS机厂商产品出现了问题,需限制交易!
配置如下信息,不满足返回:机器限制使用!
请求交易接口,日志打印如下:
2023-09-03 18:21:22 org.example.order.service.TradeService : 开始处理交易:TradeRequest(merNo=M0001, sn=A0001, factory=厂商1, amount=500000)
2023-09-03 18:21:22 c.r.c.h.FeignInvocationHandlerFactory : Request param is [ExecuteParam(code=tran-risk, input={factory=厂商1, amount=500000, merNo=M0001, sn=A0001})]
2023-09-03 18:21:22 c.r.c.h.FeignInvocationHandlerFactory : Direct result is Result(code=200, data=Output(value=[机器限制使用!], classType=java.util.Collections$SingletonList), message=执行成功, timestamp=2023-09-03 10:21:22)
2023-09-03 18:21:22 org.example.order.service.TradeService : 规则引擎返回结果:Output(value=[机器限制使用!], classType=java.util.Collections$SingletonList)
2023-09-03 18:21:22 org.example.order.service.TradeService : 规则限制交易:规则:[机器限制使用!]
处理第N个需求
....
实时风控
以上介绍了规则引擎的简单使用,但是如何做到针对某些行为以及事件实时限制商户、POS交易。以及如何预防、反洗钱等。
但是规则引擎处理的业务大部分应该是无状态的,应该如何巧妙的解决以上问题呢。
如果我们学过Flink
,它是有状态的,出色的流处理、事件时间处理、低延迟和高吞吐的特性,是不是可以把二者结合起来使用呢?
下期预告:基于Flink与规则引擎的实时风控