一个简易版支付路由实现

来源:互联网 发布:视频加文字软件 编辑:程序博客网 时间:2024/06/05 20:45

一个简易版支付路由实现

By 马冬亮(凝霜  Loki)

一个人的战争(http://blog.csdn.net/MDL13412)

缘起

今天跟小伙伴晚上出去吃饭,聊到:假如用户选着工行支付,总共有1000单,其中300单给财付通,100 单给百付宝,600给支付宝(支付渠道)

算法设计

我们先看一种简单的情况:取一个大小为1000的数组,其中[0-300)分配给财富通,[300,400)分配给百付宝,[400,1000)分配给支付宝(当然可以约分后再计算,这里为了清晰,不进行约分),如下图所示:


对于这个数组,我们将对应区间内的内容填充为相应支付渠道的引用,使用一个计数器,每次有支付请求到来时,就将计数器加1并对1000取余,并用这个计数器去引用数组中的支付渠道,就可以按比例分配的目的。

这个算法的一些弊端:

  • 支付渠道分配不均匀,一段时间内的请求,都会是某个支付渠道;
  • 动态添加、删除支付渠道困难;
  • 动态改变支付渠道所占比例困难;
  • 在支付路由集群中,会造成比例不稳定;

下面我们对这一算法进行改进:

按照支付渠道的数量开一个数组,里面维护一些计算比例的基本信息,如下图所示:


这次,计数器在支付渠道之间自增、取余,而对应的支付渠道,利用hitRate和curHitCount两个变量来模拟上一个算法中区间的比例;

例如,当前有1001次支付请求:

第1次,选择财付通渠道,对应的财付通渠道curHitCount加1,其值小于对应的hitRate,因此可以选择;

第2次,选择百付宝渠道,符合条件,选取;

第3次,选择支付宝渠道,符合条件,选取;

第4次,选择财付通渠道,符合条件,选取;

第5次,选择百付宝渠道,符合条件,选取;

......

第300次,选择支付宝渠道,符合条件,选取;

第301次,选择百付宝渠道,因为此时其curHitCount = 100,大于等于其hitRate,按照其权重,其不再进行分配,选择下一渠道支付宝,符合条件,选取;

第302次,因为上次百付宝选取失败,选择了支付宝,因此这次计数器取余后的结果为0,因此选取财付通渠道,符合条件,选取;

第303次,选择百付宝渠道,同样因为权重问题,跳过,选择下一渠道支付宝,符合条件,选取;

....

在700次请求后,财付通渠道的权重用完,因此后续的300次支付全部使用支付宝渠道;

第1001次,因为所有支付渠道权重全部用完,因此需要重置个系统的curHitCount,开始新一轮的分配。

实现

为了让算法更清晰,去掉了各种校验以及多线程的处理,让读者更容易理解。

#include <cstdlib>#include <iostream>#include <utility>#include <list>#include <vector>#include <map>using namespace std;class BankRouter{    typedef map<string, int>            BankHistRateIndexMapping_t;    struct BankHitRateCounter    {        BankHitRateCounter(const string name, const unsigned int rate) :            hitRate(rate),            curHitCount(0),            disabled(false),            bankName(name)        {        }        unsigned int    hitRate;        unsigned int    curHitCount;        bool            disabled;        const string    bankName;    };    typedef vector<BankHitRateCounter>  BankRateArray_t;public:    typedef pair<string, unsigned int>  BankHitRate_t;public:    BankRouter(list<BankHitRate_t> bankHitRate)    {        int index = 0;        for (list<BankHitRate_t>::const_iterator iter = bankHitRate.begin();                bankHitRate.end() != iter; ++iter) {            // 去重、校验等逻辑省略...            bankRateArray_.push_back(                    BankHitRateCounter(iter->first, iter->second));            bankRateMapping_[iter->first] = index++;        }        bankRateLength_ = bankRateArray_.size();    }    virtual ~BankRouter()    {    }    string nextBank()    {        if (curBankPtr_ >= bankRateLength_) {            curBankPtr_ = 0;        }        int curBankPtrBk = curBankPtr_;        bool flag = false;        while (true) {            if (curBankPtr_ >= bankRateLength_) {                curBankPtr_ = 0;                flag = true;            }            // 如果遍历一遍还没有合适的银行可供选择,则说明所有银行均不可用            // 或者计数器已满,需要重置            if (curBankPtrBk == curBankPtr_ && flag) {                // 检测是否全部为disabled,防止死循环,略...                resetBankRateArray();                curBankPtr_ = 0;                curBankPtrBk = 0;                flag = false;            }            if (bankRateArray_[curBankPtr_].disabled) {                ++curBankPtr_;            } else {                if (++bankRateArray_[curBankPtr_].curHitCount <=                        bankRateArray_[curBankPtr_].hitRate) {                    return bankRateArray_[curBankPtr_++].bankName;                } else {                    ++curBankPtr_;                }            }        }    }    void enableBank(string bankName)    {        bankRateArray_[bankRateMapping_[bankName]].disabled = false;    }    void dienableBank(string bankName)    {        bankRateArray_[bankRateMapping_[bankName]].disabled = true;    }private:    void resetBankRateArray()    {        for (BankRateArray_t::iterator iter = bankRateArray_.begin();                bankRateArray_.end() != iter; ++iter) {            iter->curHitCount = 0;        }    }private:    BankRouter(const BankRouter &);    BankRouter &operator =(const BankRouter &);private:    BankRateArray_t                 bankRateArray_;    int                             curBankPtr_;    int                             bankRateLength_;    BankHistRateIndexMapping_t      bankRateMapping_;};void test(BankRouter &br, const int n){    for (int i = 0; i < n; ++i) {        cout << br.nextBank() << endl;    }}int main(int argc, const char *argv[]){    list<BankRouter::BankHitRate_t> l;    l.push_back(make_pair("cft", 3));    l.push_back(make_pair("bfb", 1));    l.push_back(make_pair("zfb", 6));    BankRouter br(l);    test(br, 20);    cout << "--------------------" << endl;    br.dienableBank("cft");    test(br, 14);    cout << "--------------------" << endl;    br.enableBank("cft");    test(br, 20);    return 0;}

运行结果(大家可以观察支付渠道的切换):

cftbfbzfbcftzfbcftzfbzfbzfbzfbcftbfbzfbcftzfbcftzfbzfbzfbzfb--------------------bfbzfbzfbzfbzfbzfbzfbbfbzfbzfbzfbzfbzfbzfb--------------------cftcftcftcftbfbzfbcftzfbcftzfbzfbzfbzfbcftbfbzfbcftzfbcftzfb

0 0
原创粉丝点击