C++漏斗限流法
我们可以看到,就像一个漏斗一样,进来的水量就好像访问流量一样,而出去的水量就像是我们的系统处理请求一样。当访问流量过大时这个漏斗中就会积水,如果水太多了就会溢出。 一般来说,这个“漏斗”是用一个队列来实现的,当请求过多时,队列就会开始积压请求,如果队列满了,就会开拒绝请求。很多系统都有这样的设计,比如TCP。当请求的数量过多 时,就会有一个sync backlog的队列来缓冲请求,或是TCP的滑动窗口也是用于流控的队列。
// g++ bucket_limit.cpp -std=c++11
#include<iostream>
#include<sys/time.h>
#include<unordered_map>
#include<map>
#include <unistd.h>
using namespace std;
// 漏斗限流
class BucketLimit {
public:
BucketLimit(int rate, int bucket):rate_(rate), bucket_(bucket), cur_bucket_(0), last_time_(now_micro_seconds() / kMicroSecondsPerSecond) {
}
void refresh() {
int now = now_micro_seconds() / kMicroSecondsPerSecond; // 当前时间,单位为s
cout << "now:" << now << " last_time_:" << last_time_ << endl;
int consumer = (now - last_time_) * rate_; // 距离上次请求,这段时间已经消费多少请求
cur_bucket_ = max(0, cur_bucket_ - consumer); // 当前剩余水桶中水量
last_time_ = now;
++cur_bucket_; // 水量增加1
}
bool allow() {
refresh();
cout << "cur_bucket_:" << cur_bucket_ << " bucket_:" << bucket_ << endl;
if(cur_bucket_ < bucket_) {
return true;
}
return false;
}
private:
int rate_; // 单位:r/s,每秒多少个request,qps
int bucket_; // 水桶容量,超过水桶容量请求会被拒绝
int64_t last_time_; // 以秒为单位,保存上一次请求的时间戳
int cur_bucket_; // 当前水桶中存在的水量
// 获取当前时间,单位为us
int64_t now_micro_seconds() {
struct timeval tv;
gettimeofday(&tv, NULL);
int64_t seconds = tv.tv_sec;
return seconds * kMicroSecondsPerSecond + tv.tv_usec;
}
static const int kMicroSecondsPerSecond = 1000 * 1000;
};
int main() {
//std::unordered_map<int, bool> request_allow;
std::map<int, bool> request_allow;
// 限流50r/s,bucket为100r
BucketLimit bucket_limit(50, 100);
// for循环速度很快,这个for循环执行肯定是<1s
for(int i = 0; i < 1000; ++i) {
if(bucket_limit.allow()) {
request_allow[i] = true;
} else {
request_allow[i] = false;
sleep(0.01);
}
}
for(auto ite : request_allow) {
cout << "i = " << ite.first << " allow = " << ite.second << endl;
}
return 0;
}
限流参考书籍:
1.《亿级流量网站架构核心技术 跟开涛学搭建高可用高并发系统》第4章:限流详解
2.《极客时间-OpenResty从入门到实战》42丨如何应对突发流量:漏桶和令牌桶的概念
3.《网易云-Golang从入门到精通》https://github.com/NIGHTFIGHTING/koala/tree/master/ppt/14.%20%E9%99%90%E6%B5%81%E4%B8%AD
4.令牌桶go源码分析:
https://zhuanlan.zhihu.com/p/90206074
5.《极客时间-左耳听风》弹力设计篇之“限流设计”
6.令牌桶:https://zhuanlan.zhihu.com/p/89820414,https://www.cyhone.com/articles/usage-of-golang-rate/,https://github.com/chenyahui/AnnotatedCode/blob/master/go/x/time/rate/rate.go