一个简易版支付路由实现
来源:互联网 发布:视频加文字软件 编辑:程序博客网 时间: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
- 一个简易版支付路由实现
- .NET Nancy 详解(二) 简易路由实现
- c++实现一个简易vector加强版
- 实现一个简易的Python版CountDownLatch
- 实现一个简易通讯录
- 一个简易计算器的实现
- QT一个简易画板实现
- 一个简易的libevent实现
- 一个简易JVM的实现
- 一个简易的WebServer实现
- python实现一个简易hashmap
- JS_实现一个简易计算器
- 实现一个简易的电子钟
- 分布式架构--简易版支付系统
- 第三方支付系统简易版支付系统部署
- 支付系统开发--简易版支付系统介绍
- 支付系统开发--简易版支付系统介绍
- nodejs服务器简易路由
- ASP程序传文件提示“ASP 0104 : 80004005”错误的原因及解决办法
- 学习笔记问题大全【整理】1 C++
- TCP+UDP通信实验的设计思路及所遇问题的解决方法
- 第七周.背包
- [NOI2005] 维修数列
- 一个简易版支付路由实现
- 根据硬件设备配置高性能的Nginx
- bzoj1711[Usaco2007 Open]Dingin吃饭
- Multiple markers at this line @Override的解决方法
- Ubuntu14.04 下 构建交叉开发环境
- node.js连接mongodb数据库警告:(Please ensure that you set the default write concern)
- 杂项
- 黑马程序员--7K面试 :银行调度系统面试题
- C语言的代码内存布局详解