Go | 限流器实现

可作为面试时的亮点写在简历上

一、限流算法

🚀 1.0 总结

  1. 计数器固定窗口算法实现简单,容易理解。和漏斗算法相比,新来的请求也能够被马上处理到。但是流量曲线可能不够平滑,有“突刺现象”,在窗口切换时可能会产生两倍于阈值流量的请求;

  2. 计数器滑动窗口算法作为计数器固定窗口算法的一种改进,有效解决了窗口切换时可能会产生两倍于阈值流量请求的问题,但计算机很难处理滑动的行为,只能通过轮询的方式模拟(redis的过期时间本质上也是轮询),会占用CPU资源/内存浪费;

  3. 漏斗算法能够对流量起到整流的作用,让随机不稳定的流量以固定的速率流出,但是不能解决流量突发的问题;

  4. 令牌桶算法作为漏斗算法的一种改进,除了能够起到平滑流量的作用,还允许一定程度的流量突发。但可能需要初始化;

以上四种限流算法都有自身的特点,具体使用时还是要结合自身的场景进行选取。
令牌桶算法一般用于保护自身的系统,对调用者进行限流,保护自身的系统不被突发的流量打垮。如果自身的系统实际的处理能力强于配置的流量限制时,可以允许一定程度的流量突发,使得实际的处理速率高于配置的速率,充分利用系统资源。
漏斗算法一般用于保护第三方的系统,比如自身的系统需要调用第三方的接口,为了保护第三方的系统不被自身的调用打垮,便可以通过漏斗算法进行限流,保证自身的流量平稳的打到第三方的接口上。

1.1 计数器

维护一个计数器,开始处理请求时计数器+1,请求处理完毕后计数器-1

优点:实现简单,Java中原子类Atomic即可实现,分布式场景采用Redis incr
缺点:不能应对突发流量

1.2 固定窗口

计数器+定时更新

缺点:固定窗口临界问题,假设接口每秒的限流为100,但在0.55s~1.05s的0.5s中涌入200个请求可能会导致限流为100/s的系统崩溃
在这里插入图片描述

1.3 滑动窗口

记录时间窗口中每个请求到来的时间,保证任意时间窗口中请求数量均不超过系统限制

缺点:无法解决短时间内集中流量的冲击

boolean limiter() {
   
	long now = currentTimeMillis(); // 获取当前时间
	long counter = getCounterInTimeWindow(now)	// 根据当前时间获取时间窗口内的计数
	if (counter < threshold) {
    		// 小于阈值
		addToTimeWindow(now);		// 记录当前时间
		return true;
	}
	return false;
}

1.4 Leaky Bucket 漏桶

使用队列保存全部request,新的request放入队列尾部,队列满时将其丢弃

优点

  1. 可以平滑处理突发流量
  2. 容易实现
  3. 队列/缓冲区大小恒定,内存使用率高

缺点

  1. 请求延迟
  2. 出现突发流量,队列被old request占满时,new request会被饿死

1.5 令牌桶

定速的往桶内放入令牌,令牌数量超过桶的限制,丢弃。请求来了先向桶内索要令牌,索要成功则通过被处理,反之拒绝

缺点:存在突刺问题,导致服务器空闲状态下,存在大量资源浪费
在这里插入图片描述

二、单机限流器

rate/limiter.go中限流器的实现

令牌桶只要桶中还有 Token,请求就还可以一直进行。当突发量激增到一定程度,则才会按照预定速率进行消费。

2.1 内部结构

  • 实现令牌桶的常规思路:单独维护一个Timer和BlockingQueue,从而实现每隔一段时间向队列中添加令牌、取出令牌;
  • Go中的实现:通过计数的方式表示桶中剩余的令牌,采用lazyload的思想,每次取token之前会先根据上次更新令牌数的时间差更新桶中Token数量;
type Limiter struct {
   
	mu     sync.Mutex
	limit  Limit	// 控制产生令牌的速度 float64的别名
	burst  int		// 令牌桶的最大容量
	tokens float64	// 令牌数量
	last time.Time	// 上次更新令牌桶的时间
	lastEvent time.Time	// 上次发生限速器事件的时间
}

2.2 构造方法

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值