支付路由架构设计银行核心系统

支付路由-上

2018-12-10  本文已影响108人  飞天的猪_ba05

支付路由是我主导重构的,我觉得这应该是我得意作品之一吧。本次分享的话分为上下两块,上部分讲我是怎么设计的,下部分讲我是怎么重构的。

上部:我是用领域设计的方式来设计支付路由,领域设计是我之前在一家公司面试的时候,面试官问我知道领域设计吗?当时我有点懵逼。后来他引导我说java面向对象,一个类不仅应该有属性,还有方法。但是我们用MVC方式一个实体类只有属性,没有方法。后来回去后我看了相关的资料,领域设计是站在一个高点看待问题,抽取领域类和领域行为。(哈哈,这不就是面向对象的思想,抽象的看待一个问题)渐渐的喜欢上了这样的方式,是我以后解决问题的方法论

对于不熟悉支付的同学先介绍下什么是支付路由:用户在前端选择一种支付方式,比如使用招行借记卡来支付后,系统不一定就是调用招行的接口来执行支付。支付宝、京东、先锋等第三方支付平台以及银联等都支持招行借记卡支付。 这种将支付方式落地到具体的支付接口的模块,就是支付路由

需求背景

在公司快速发展的背景下,为了支付通道的稳定性,公司将陆续接入不同的支付渠道。在渠道出问题时,能快速的切换到其他支付渠道。不同的支付渠道的成本、稳定性、可靠性各不相同。需要选出综合最优的支付渠道在目前阶段,现阶段简易的支付路由,存在一些问题。路由代码阅读性差,难以维护和扩展。加之路由测试不好测试

设计目标

支付路由在支付系统中的核心作用,除了本职工作路由外,还承担如下职责:

领域设计

通用语言

通用语言是一种程序员和领域专家沟通的语言(和需求方沟通),只有相互理解需求,才能更好的开发需求

名词 解释
支付渠道 第三方支付公司,比如京东支付、翼支付、网信贷款、联动优势
支付通道 支付通道是支付渠道下开设的商户号,比如京东支付可以开通多个商户号,不同商户号直接没有关联
支付组 包含一个或多个支付通道
入金账户 功夫贷的贷款资金源,不同的资金源有一个主支付组和一个备用支付组
主支付组 资金方提供的支付通道
备用支付组 大树提供的支付通道
出金账户 用户还款时绑定支付的银行卡
入金账户 功夫贷的贷款资金源,不同的资金源有不同的支付渠道
路由 根据出金账户、金额、入金账户等因素进行筛选,最终获得一个最优的支付通道

领域思想

支付路由 当我们看到这个需求时其实有一些懵对不对?让我们一点一点的来补充这个语句

扩展一

支付路由分为两块,一个是业务路由,还有一个只支付通道路由

  1. 业务路由功能
    根据规则确定入金账户(大树的借款资金不是自己的,是不同的资金方。所以还款是还到响应借款时的资金方)
  2. 支付通道路由
    支付订单根据规则从支付组中确定最优的支付通道

上部分的话讲支付通道路由,所以下面讲的都是支付通道路由设计思想


扩展一

扩展二

支付订单根据规则确定最优的支付通道,那么规则有哪些呢?

熟悉支付的同学知道,有些支付通道是需要签协议的(协议支付)没有签协议是支付不成功的,支付通道还有限额,不同的银行限额还不同等。可以看到,要走这个通道不要满足这些必要条件的,我称这些条件为硬性规则

当然也有软性规则,支付通道错误次数(支付通道返回系统繁忙等)、用户在该支付通道错误次数(用户还款失败)等。这些失败并不代表支付通道不可使用,这些情况下我们可以把这些支付通道的权重下降。支付通道返回系统繁忙这样的事件在一小时内的统计达到一定数量,可以将该规则设置为硬性规则

到底有哪些规则呢?询问领域专家

硬性规则
软规则

为什么功夫贷日限额或者功夫贷日限次等为软规则呢?我们希望用户能尽量等还款成功,这边等限额是为了让功夫贷用支付通道支付金额等限制,比方我们限制用京东支付日限额100W,尽量的平分给其他等支付通道合作方。

扩展二

扩展三

我给这些领域对象添加些属性,大家也可以帮忙看下是不是合理

扩展三

扩展四

支付订单根据规则确定最优的支付通道,现在支付订单、支付通道、规则都有了。怎么使用他们呢?我之前在同盾使用规则引擎,能动态的修改规则,所以这次我把规则引擎引入了进来,使用Drools。

Drools 是一个基于Charles Forgy’s的RETE算法的,易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。 业务分析师人员或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。其他的自己去官网看吧

规则引擎的优点:数据位于“域对象”中,业务逻辑位于“规则”中。
现在规则有了,域对象是什么呢?---就是我们的支付订单和支付通道,其实就是我们运行规则的参数

扩展四

扩展五

现在我们的领域对象和行为都有了,现在给出它们的时序图

扩展五

从图中我们可以看到,执行规则路由只需要
1、构造支付订单
2、构造支付组下的支付通道
3、加载规则文件
4、运行规则

发现支付组下的支付通道是固定的数据,规则文件也是固定的。需要每次都去加载吗?所以这是一个优化点,可以加个缓存

扩展六

刚才说了,我们可以动态修改规则。可是现在规则是写在drl文件中怎么修改呢?
先看下drl的文件格式

rule "check 银行节假日"
    when
        $context: RouteContext($bankId          : payOrder.outPayAccount.bankId,
                              $holidays         : payPlatform.bankHolidays,
                              $current          : payOrder.payTime,
                              $channel          : payPlatform.code)

        $action  : RouteAction()

        eval(generalLogic.isHoliday($holidays,$current,$bankId))
    then
        HitRule hitRule = new HitRule();
        hitRule.setDesc("通道:"+$channel+",银行:"+$bankId+"正处于节假日");
        hitRule.setRuleName("check 银行升级");
        $action.addStrongRule(hitRule);
        $action.setInterrupt(true);
        drools.halt();
end

rule "check 通道节假日"
    when
        context: RouteContext($holidays     : payPlatform.payPlatformHolidays,
                              $current      : payOrder.payTime,
                              $channel      : payPlatform.code)

        $action  : RouteAction()

        eval(generalLogic.isHoliday($holidays,$current,"0"))
    then
        HitRule hitRule = new HitRule();
        hitRule.setDesc("通道:"+$channel+"正处于节假日");
        hitRule.setRuleName("check 通道节假日");
        $action.addStrongRule(hitRule);
        $action.setInterrupt(true);
        drools.halt();
end



rule "check 通道错误次数"
    when
        context: RouteContext($statistics           : payPlatform.payPlatformStatistics,
                              $stableWt             : payPlatform.payPlatformStableWt,
                              $channel              : payPlatform.code)
        $action  : RouteAction()

        PayPlatformStatistics($value:value) from statisticsService.query($channel,PayPlatformStatisticsType.ERROR_COUNT)

        PayPlatformStableWt($errorCountWtList:errorCountWt) from $stableWt

        eval( $value !=null && $errorCountWtList != null)
    then
        double score = generalLogic.getWeight($value,$errorCountWtList);

        HitRule hitRule = new HitRule();
        hitRule.setDesc("通道:"+$channel+",通道错误次数:"+ $value+",得分:"+score);
        hitRule.setRuleName("check 通道错误次数");
        hitRule.setScore(score);
        $action.addSoftRule(hitRule);
        if(score == 0){
            $action.setInterrupt(true);
            drools.halt();
        }
        $action.addScore(score);
end

rule "check 用户错误次数"
    when
        context: RouteContext($statistics           : payPlatform.payPlatformStatistics,
                              $stableWt             : payPlatform.payPlatformStableWt,
                              $accountNo               : payOrder.outPayAccount.accountNo,
                              $channel              : payPlatform.code)
        $action  : RouteAction()

        PayPlatformStatistics($value:value) from statisticsService.query($accountNo+"_"+$channel,PayPlatformStatisticsType.USER_FAILED_COUNT)

        PayPlatformStableWt($userErrorCountWtList:userErrorCountWt) from $stableWt

        eval( $value !=null && $userErrorCountWtList != null)
    then
        double score = generalLogic.getWeight($value,$userErrorCountWtList);

        HitRule hitRule = new HitRule();
        hitRule.setDesc("用户银行卡:"+$accountNo+",通道:"+$channel+",用户错误次数:"+ $value+",得分:"+score);
        hitRule.setRuleName("check 用户错误次数");
        hitRule.setScore(score);
        $action.addSoftRule(hitRule);
        if(score == 0){
            $action.setInterrupt(true);
            drools.halt();
        }
        $action.addScore(score);
end

观察规则 银行节假日与通道节假日、通道错误次数和用户错误次数。是不是感觉格式一样,只是参数类型不一样。

function holiday(bankId,holidays,currentDate,channel){
}

function count(statistics, stableWt,key,channel){
}

能否抽象出这样的模板呢?每个规则可以对应这样的模板,前端配置时选择模板,入参为支付订单或者支付通道中的属性。

扩展六

总结

这次主要是记录下我设计支付路由的思路,感觉没把领域设计思想说清楚,我总结下吧。
1、清晰的解读问题域(需求)
2、提取领域对象(在这个问题域中的实体对象)
3、建立归纳关系(即继承、泛化)
4、建立类间关联(聚合 组合 依赖)
5、开发关联类(类与类之间需要某个对象作为媒介)
6、时序图,描述了系统在运行时间的行为,包括系统如何完 成这些行为
7、代码开发

额,还不懂的话。可以看下面向对象分析与设计框架,这里说明了什么阶段,需要产出什么。更加详细一点。

感觉这次的分享比较枯燥,需要认真的看下了,感谢你坚持到了最后。接下来进入年底了,有几次期末考试,可能更新速度上会放慢。

上一篇下一篇

猜你喜欢

热点阅读