技术栈:Java+Groovy+Lua+Springboot+Mysql+Redis+Drools+Velocity+RabbitMQ+Spring Data Jpa
一、背景
此篇文章我们来片命中部分设计,在上一篇中我们确定了命中维度是交易类型,首先支付系统上送的报文中肯定有交易类型字段,或者通过某种方式可以将某字段转换出交易类型,总之我们肯定知道了此交易是何种交易类型,是代扣、是代付还是快捷等等...那么我们要做的就是,从对接的支付渠道中筛选出满足此笔交易的支付渠道。
二、分析设计
1.分析

在router_rule_table中存储着我们的规则,也就是以交易类型为维度的规则。
我们以代扣交易为例:讲我们的设计演进,首先交易系统上送到路由系统的主要基本参数有:交易类型(deduct)、交易金额(100.00)、开户行(0801)、卡类型(E)等,假如此时我们规则表中有如上三条规则(1.2.3),那么我们可以根据上送的报文参数-交易类型为条件
sql:select * from router_rule_table where trans_code=deduct;
那么就命中出来了规则表中第一条规则,达到了我们想要的目的了,本部分不就是要以交易类型为维度命中我们的规则吗?看似没有任何问题,但是我只想说,这种设计后期绝对能把人恶心吐了。我们接着分析,如果我们又接了一个通道A,并且也接入其代扣交易类型(规则4),然鹅此通道并非提供给原来业务线使用,假如原来业务线是话费代扣业务线,现在提供给水电煤代缴,那么你上一个sql这么写还对吗?不对了吧,这时候怎么办,为了区分不同产品线,这时候你又机智的在表中加了个字段-product_code,又将历史数据的product_code进行编制填充,经过一波猛如虎的操作,暂时满足了需求,
sql改为:select * from router_rule_table where trans_code=deduct and product_code=001;
没过了多久,又来需求,区分移动端和pc端,规则表又要加字段场景码scene,又重复上一波操作,扩表加字段改sql,
最终sql改为:select * from router_rule_table where trans_code=deduct and product_code=001 and scene=002;
只要规则增加条件就来一波如上操作,这样的系统谁后期负责谁恶心,这种设计不仅是存在后期扩展上的问题,也仅仅是简单的=判断逻辑,可以说毫无扩展可言吧。
2.设计
那么我们该如何解决如上问题呢?
首先我们要确定几个问题,第一根据交易类型维度进行规则命中是没有问题的,第二命中的条件不应该横向扩展在规则表中,如果横向扩展那么在增加命中条件时你就躲不开对表进行扩展,既然不能横向扩展,那么就纵向扩展,怎么个纵向法,如下图:
增加rule_condition表,独立表挂靠命中条件,同时设定where条件不仅仅是简单的=了,更强大的条件判断规则,如=、!=、in、!in、>、<、>=、<=等,如果基本运算满足不了还可以切入Groovy脚本进行数据计算处理,那么我们的规则存储方式变为如下:
当使用纵向扩展方式,同时使用Drools规则引擎和Velocity模板引擎结合使用来组织这些规则条件,难度等级上了不止一个层次了,但是这样的系统,运营使用起来会非常爽,简单的配置就可以满足业务需求了,运营操作页面如下图,请忽略原型图的丑陋:

如上图路由规则编辑页面所示,从上到下分为细分四部分,基本信息、校验链、输出结果、规则条件,下面我们简单的介绍下这个四部分:
- 基本信息:
- 规则名称按照实际业务自定义;
- 优先级由于标识此规则的优先级,如果一次命中多条规则会从高优先级到底优先级进行筛选;
- 权重由于分流使用,如果经过层层过滤还有多条可用渠道则根据权重进行分流;
- 评分阈值搭配监控系统进行自动规则降级使用;
- 状态-初始化-启用-禁用,没啥好说的了;
- 备注随意填写。
- 校验链:
- 校验链对规则引擎命中的支付渠道进一步筛选的,比如累计限额呀,单笔限额,因为我们规则条件只是配置了若干个条件,毕竟筛选出一条最优支付渠道要经过很多条件的。
- 输出结果:
- 输出结果即命中这条规则对应的支付渠道的此交易类型。
- 规则条件:
- 规则条件也就是命中此条规则要满足的条件。
如上四分部即对应这两个表,规则表router_rule_table和条件表rule_condition。
对比模式一设计和采用模式二设计,你知道差距在哪里了吧。
三、总结
此篇我们分析了一般设计的弊端,即将规则与条件放在一张表中作为一条数据,使用sql查询方式来做规则的命中,规则的添加需要伴随着表结构的变更(横向变更),这个是我们所不能容忍的。
然后我们为了避免此设计模式,将规则与条件进行拆分为两张表,即规则表和条件表(1:n),规则的变更只需要在条件表增加一条规则(纵向变更),避免了由于规则的变更而引起的表结构的变更。