Golang | 令牌桶限流算法

  • 限流算法的目的是控制对后端接口的访问频率,防止因过度访问导致系统崩溃。
  • 网站登录接口是限流的典型例子,爬虫或恶意用户可能疯狂调用登录接口,导致数据库压力过大。
  • 通过限制接口的QPS(每秒查询率),可以保护后端数据库不受冲击。
  • 令牌桶算法是一种经典的限流算法,将请求想象成令牌,桶以一定速度放入令牌。
  • 桶的容量决定瞬间最多能满足的请求数,生产速度代表平均供应速度。
  • 谷歌官方提供了基于令牌桶算法的实现,位于guava库的x包下。
  • 使用rate.newLimit方法创建限流器,指定时间间隔和桶容量。
  • 限流器接受三种取令牌方式:wait、allow和reserve。
  • wait方式会等待桶内令牌足够为止;allow方式立即返回是否允许取走令牌;reserve方式会计算等待时间。

go 复制代码
package tests

import (
	"sync/atomic"
	"time"
	"golang.org/x/time/rate"
)

// TotalQuery 记录请求总数
var TotalQuery int32

// Handler 模拟接口
func Handler() {
	atomic.AddInt32(&TotalQuery, 1)
	time.Sleep(50 * time.Millisecond)
}

func CallHandler() {
	// 每隔100ms生成一个令牌,最大QPS限制为10
	limiter := rate.NewLimiter(rate.Every(100*time.Millisecond), 10)
	for {
		// 方式一:WaitN()
		//ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
		//defer cancel()
		//limiter.WaitN(ctx, 1) // 阻塞,直到桶中有N个令牌。N=1时等价于Wait(ctx)
		//Handler()

		// 方式二:AllowN()
		// 不等,当前桶中是否至少还有N个令牌,如果有则返回true。N=1时等价于Allow(time.Time)
		//if limiter.AllowN(time.Now(), 1) {
		//	Handler()
		//}

		// 方式三:ReserveN()
		// reserve.Delay()告诉你还需要等多久才会有充足的令牌,等待相应时间,再执行
		reserve := limiter.ReserveN(time.Now(), 1)
		time.Sleep(reserve.Delay())
		Handler()
	}
}
  • 令牌桶(Token Bucket)算法是一种常用的限流算法,常用于网络流量控制和高并发服务的请求限速。它本质上是一个允许突发请求但控制平均速率的机制,兼具了平滑输出和灵活突发的优点。
  • 令牌桶算法通过一个"桶"来存储"令牌",系统按照固定速率向桶中添加令牌,处理请求时必须"取走"一个令牌,如果桶里没有令牌了,请求就被拒绝或延迟处理。
  • 每次处理请求时:
    • 令牌补充:根据当前时间与上次补充时间的差值,计算应添加的令牌数量:tokens += (now - last_refill_time) * r
    • 令牌溢出处理:如果 tokens > b,令牌数取为桶最大容量。
    • 判断请求是否能通过:
      • 如果 tokens >= 1,扣除一个令牌,允许请求通过。
      • 否则,拒绝请求或阻塞等待。
相关推荐
IvanCodes2 小时前
Python 数据处理(十三):JSON、CSV 与数据序列化
开发语言·python
aramae4 小时前
MySQL复合查询(8)
java·c语言·开发语言·后端·算法
qq_2518364576 小时前
springboot vue3 开发实现 拼豆管理系统
java·开发语言·ai编程
郑州光合科技余经理7 小时前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程
知识分享小能手8 小时前
C++ 学习教程,从入门到精通,C++ 入门知识 — 完整知识点(1)
开发语言·c++·学习
+VX:Fegn08958 小时前
计算机毕业设计|基于springboot + vue旅游管理系统(源码+数据库+文档)
java·开发语言·vue.js·spring boot·课程设计
阿里嘎多学长9 小时前
2026-09-20 GitHub 热点项目精选
开发语言·程序员·github·代码托管
weixin_3077791310 小时前
C++代码实现MATLAB中的ode23tb函数功能
开发语言·c++·算法·matlab
2601_9669496511 小时前
为什么量化回测中 for 循环比 DataFrame 慢三个数量级?从向量化原理讲起
开发语言·python·pandas·股票数据·quantdash
边境悍匪12 小时前
蜗牛学苑 Java 智能体学习 Day45|Knife4j+SpringBoot3、书城项目整合 MyBatis 思维导图复盘
java·开发语言·vue.js·学习·spring