当前位置: 首页 > news >正文

GO--基于令牌桶和漏桶的限流策略

至于为什么要限流,字面意思已经很清楚了,就是为了减轻服务器的压力

下面我们将介绍两个限流策略----漏桶和令牌桶。

漏桶

原理介绍

漏桶,顾名思义就是一个漏斗,漏斗嘴的大小是固定的,所以不管漏斗现容量多大,都不会影响漏斗出水的速度。类比到我们的web服务中,我们可以为web服务准备一个固定速率的请求处理器(漏桶),对我们的请求,如果此时桶内请求量超过了桶的最大容量,那么就执行特定的抛弃策略(直接丢弃或者阻塞请求)。与此同时,对我们的请求 ,进行固定速率的处理。这样就会形成一种限流的效果。

 使用

基于这个原理,有很多个人或者组织都自己开发了相应的算法实现,我们今天介绍的是github.com/uber-go/ratelimiticon-default.png?t=O83Ahttps://github.com/uber-go/ratelimit

 这个算法比较简单,库的使用也比较清晰,有需要的可以去看一看源代码,下面我将介绍

 如何在项目中使用这个库,下面我将以gin框架为例:

导包

go.uber.org/ratelimit

编写中间件

package ratelimit// 基于gin 框架 编写限流中间件 并 使用
// 限流中间件:漏桶 和 令牌桶import ("time""github.com/gin-gonic/gin"loutong "go.uber.org/ratelimit" // 漏桶中间件(具名导入)
)// 漏桶策略限流器
func RateLimitMiddleware(rate int) func(c *gin.Context) {// 使用闭包写中间件,可以在使用中间件的时候,传入指定参数( rate 是请求数,每秒处理请求数 )// 创建(漏桶)限流器,指定处理速率(不限制速率:NewUnlimited())rl := loutong.New(rate)// 返回一个函数return func(c *gin.Context) {// 获得当前的时间now := time.Now()// 尝试从漏桶中获得一个请求去处理rl.Take()// 获得处理请求花费的时间cost := time.Since(now)if cost > 0 {// 如果有等待,那么花费时间大于0c.Abort()       // 丢弃请求// 对待等待的请求进行处理:阻塞 或者 丢弃}c.Next()}
}
/*
使用Take()方法的作用:
如果当前请求的流入速度太快,超过了设定的每秒请求数(RPS)的标准,那么这个 “Take” 操作就需要阻塞(暂停、等待),
不让过多的请求一下子涌入后续的处理流程,直到请求流入的速度符合设定好的每秒请求数这个要求,
以此来实现精准的限流控制,保证系统按照既定的请求处理速率稳定运行。
Take()方法返回一个time值,反映的是 请求等待的时间 
*/

测试

package mainimport ("component/ratelimit""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.Use(ratelimit.RateLimitMiddleware(5))r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})r.NoRoute(func(c *gin.Context){c.JSON(404, gin.H{"msg": "404,您的也页面好像找不到了~",})})r.Run("127.0.0.1:8080")
}
  1. 优点

    • 流量整形效果好
      • 漏桶算法能够平滑突发流量。例如,在网络服务中,当有大量用户在短时间内发起请求(如某热门商品限时抢购活动导致大量用户同时访问电商网站),这些请求会先进入 “漏桶” 缓存起来,然后以固定的速率流出进行处理。这就使得后端服务接收到的请求是平稳的,避免了后端服务因突发的高流量而崩溃。
    • 易于理解和实现
      • 其原理简单直观,类似于生活中的漏斗。从编程角度看,实现一个基本的漏桶算法不需要复杂的代码结构。比如,可以用一个简单的队列来模拟 “漏桶”,记录请求的到达时间,按照固定的时间间隔从队列头部取出请求进行处理。
    • 对资源的消耗可预测
      • 因为处理请求的速率是固定的,所以系统在单位时间内消耗的资源(如 CPU、内存等)是可以预估的。例如,一个按照每秒 10 个请求速率处理的服务,只要提前评估每个请求处理所需的资源量,就可以大致计算出系统在一段时间内需要的资源总量。
  2. 缺点

    • 可能导致响应延迟增加
      • 当请求流量突发且超过桶的容量时,新的请求可能会被阻塞或丢弃。对于被阻塞的请求,会导致用户等待时间变长。例如,在一个在线支付系统中,如果因为流量限制而导致支付请求被阻塞,用户可能会等待很长时间才能完成支付,这会影响用户体验。
    • 不能充分利用系统资源
      • 由于漏桶算法是按照固定速率处理请求,即使系统有足够的资源来处理更多的请求,也不会加快处理速度。比如,在深夜时段,服务器资源利用率很低,但是因为漏桶算法限制了请求处理速率,使得服务器不能更快地处理请求,从而导致资源闲置。

令牌桶

原理介绍

令牌桶的原理其实和漏桶差不多,漏桶相当于在单位时间(比如1秒内处理多少个请求)。那么令牌桶就是表现的间接了点。他是通过指定每秒的令牌数,从而指定每秒处理请求的个数(每个请求在被处理的时候都会拿取一个令牌)

使用

同样,这个算法也有很多人去实现,我们这里以下面这个为例:

github.com/juju/ratelimiticon-default.png?t=O83Ahttps://github.com/juju/ratelimit这个库支持多种令牌桶模式,并且使用起来也比较简单。

导包

github.com/juju/ratelimit

编写中间件

package ratelimit// 基于gin 框架 编写限流中间件 并 使用
// 限流中间件:漏桶 和 令牌桶import ("net/http""time""github.com/gin-gonic/gin"lingpai "github.com/juju/ratelimit"
)// 令牌桶中间件
// 限流中间件: 每 fillInterval 的时间,可最多处理 1 个请求(相当于对处理请求的 打点器)
// 特点: 如果一段时间内不请求,token会存储,直到桶的最大容量cap,应对突发多个请求
func RateLimitMiddleware(fillInterval time.Duration, cap int64) func(c *gin.Context) {// 创建令牌桶 : 参数: 1. 填充时间(单位时间) 2. 容量bucket := lingpai.NewBucket(fillInterval, cap)return func(c *gin.Context) {// 判断是否限流(如果取不到 token 就限流)if bucket.TakeAvailable(1) <= 0 {c.String(http.StatusOK, "你点击的太快了,请慢点点击~")// 终止执行c.Abort()return}// 取到令牌继续执行c.Next()}
}

创建令牌桶的方法:

// 创建指定填充速率和容量大小的令牌桶
func NewBucket(fillInterval time.Duration, capacity int64) *Bucket
// 创建指定填充速率、容量大小和每次填充的令牌数的令牌桶
func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket
// 创建填充速度为指定速率和容量大小的令牌桶
// NewBucketWithRate(0.1, 200) 表示每秒填充20个令牌
func NewBucketWithRate(rate float64, capacity int64) *Bucket

取出令牌的方法如下:

// 取token(非阻塞)
func (tb *Bucket) Take(count int64) time.Duration
func (tb *Bucket) TakeAvailable(count int64) int64// 最多等maxWait时间取token
func (tb *Bucket) TakeMaxDuration(count int64, maxWait time.Duration) (time.Duration, bool)// 取token(阻塞)
func (tb *Bucket) Wait(count int64)
func (tb *Bucket) WaitMaxDuration(count int64, maxWait time.Duration) bool

测试

package mainimport ("component/ratelimit""time""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.Use(ratelimit.RateLimitMiddleware(1*time.Second, 10))r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})r.NoRoute(func(c *gin.Context){c.JSON(404, gin.H{"msg": "404,您的也页面好像找不到了~",})})r.Run("127.0.0.1:8080")
}
  1. 优点

    • 支持突发流量处理
      • 令牌桶算法允许流量在一定范围内突发。因为令牌是以固定速率生成并积累在桶中的,所以在短时间内,如果桶中有足够的令牌,就可以允许高于平均速率的突发流量通过。例如,一个令牌桶每秒产生 10 个令牌,桶的容量为 100 个令牌。在某一时刻,桶内积累了 90 个令牌,此时如果有 50 个请求同时到达,只要令牌足够,这 50 个请求就可以立即通过,这对于应对突发的高流量情况(如限时抢购活动)非常有效。
    • 有效利用系统资源
      • 相比于漏桶算法,令牌桶算法能够更好地利用系统资源。当系统资源充足且有足够的令牌时,请求可以快速通过,不会像漏桶算法那样限制请求只能以固定的较低速率通过。例如,在服务器负载较低的时段,大量请求可以利用积累的令牌快速处理,充分发挥系统的处理能力。
    • 流量控制灵活
      • 可以通过调整令牌生成速率和桶的容量来灵活地控制流量。比如,对于不同重要性的服务或者不同的用户级别,可以设置不同的令牌桶参数。对于高级别的用户或者重要的服务接口,可以设置较大的令牌生成速率和桶容量,以保证其流量优先通过。
    • 平均速率限制准确
      • 虽然允许突发流量,但令牌桶算法依然能够保证在较长的时间范围内,请求通过的平均速率不会超过令牌生成的速率。这就使得系统可以在允许一定程度的灵活性的同时,维持一个稳定的整体流量水平。
  2. 缺点

    • 实现相对复杂
      • 与漏桶算法相比,令牌桶算法的实现较为复杂。它需要维护令牌的生成、存储和消耗的逻辑。在代码层面,需要考虑如何准确地按照固定速率生成令牌,如何有效地存储令牌(可能涉及到数据结构的选择,如队列、计数器等),以及如何正确地在请求到达时消耗令牌。
    • 参数调整难度较大
      • 令牌桶算法的性能高度依赖于令牌生成速率和桶容量这两个参数的设置。如果参数设置不合理,可能会导致流量控制效果不佳。例如,若令牌生成速率设置过高,可能无法有效地限制流量,导致系统过载;若桶容量设置过小,可能无法充分利用系统允许的突发流量特性,频繁地拒绝请求。而且在实际的复杂系统中,要准确地确定这两个参数的合适值需要进行大量的测试和性能评估。

相关文章:

GO--基于令牌桶和漏桶的限流策略

至于为什么要限流&#xff0c;字面意思已经很清楚了&#xff0c;就是为了减轻服务器的压力 下面我们将介绍两个限流策略----漏桶和令牌桶。 漏桶 原理介绍 漏桶&#xff0c;顾名思义就是一个漏斗&#xff0c;漏斗嘴的大小是固定的&#xff0c;所以不管漏斗现容量多大&#…...

MongoDB性能监控工具

mongostat mongostat是MongoDB自带的监控工具&#xff0c;其可以提供数据库节点或者整个集群当前的状态视图。该功能的设计非常类似于Linux系统中的vmstat命令&#xff0c;可以呈现出实时的状态变化。不同的是&#xff0c;mongostat所监视的对象是数据库进程。mongostat常用于…...

Axure设计之模拟地图人员移动轨迹

在产品原型设计时&#xff0c;为了更好的表达和呈现预期的效果&#xff0c;让客户或开发看一眼就能理解要实现的功能&#xff0c;往往需要在产品设计时尽量去接近现实&#xff0c;这就需要我们在使用Axure制作原型时应具有高度细节和逼真度的原型设计。原型设计不仅包含了产品的…...

Android环境搭建

Android环境搭建 第一步&#xff1a;安装 Homebrew 执行以下命令来安装 Homebrew&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"检测是否安装成功&#xff1a; brew --version第二步&#xff1a;安装 No…...

前端工程化面试题(一)

如何使用 Docker 部署前端项目&#xff1f; 使用 Docker 部署前端项目通常涉及以下几个步骤&#xff1a; 创建项目&#xff1a;首先&#xff0c;需要在本地创建并配置好前端项目。 准备 Docker 文件&#xff1a; .dockerignore&#xff1a;这个文件用于排除不需要上传到 Dock…...

模型案例:| 手机识别模型!

导读 2023年以ChatGPT为代表的大语言模型横空出世&#xff0c;它的出现标志着自然语言处理领域取得了重大突破。它在文本生成、对话系统和语言理解等方面展现出了强大的能力&#xff0c;为人工智能技术的发展开辟了新的可能性。同时&#xff0c;人工智能技术正在进入各种应用领…...

期权懂|个股期权交割操作流程是什么样的?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 个股期权交割操作流程是什么样的&#xff1f; 一、行权申报&#xff1a; 期权买方在行权日通过其经纪商提交行权指令&#xff0c;表明其决定行使期权权利。 二、行权匹配&#xf…...

【openGauss】openGauss execute执行update语句,获取更新的行数

【openGauss】openGauss execute执行update语句&#xff0c;获取更新的行数 在openGauss中&#xff0c;可以使用execute语句执行update语句&#xff0c;并通过GET DIAGNOSTICS语句获取更新的行数。下面是一个示例&#xff1a; DO $$ DECLAREupdated_rows INTEGER; BEGINEXECUT…...

P8780 [蓝桥杯 2022 省 B] 刷题统计

题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 &#x1d44e;道题目&#xff0c;周六和周日每天做 &#x1d44f; 道题目。请你帮小明计算&#xff0c;按照计划他将在第几天实现做题数大于等于 &#x1d45b; 题? 输入格式 输入一行包含三…...

切比雪夫不等式:方差约束下的概率估计

切比雪夫不等式&#xff1a;方差约束下的概率估计 背景 在概率分析中&#xff0c;切比雪夫不等式是一个常用的工具&#xff0c;它通过引入随机变量的 方差信息&#xff0c;给出了偏离均值的概率界限。这一不等式是对 马尔科夫不等式 的自然扩展&#xff0c;结合了更丰富的分布…...

使用CancellationTokenSource来控制长时间sql查询中断

前端 <!-- 透明的覆盖层&#xff0c;显示在页面上方&#xff0c;包含进度条 --><Grid Visibility"{Binding IsLoading}" Background"Transparent" HorizontalAlignment"Stretch" VerticalAlignment"Stretch" ZIndex"1&…...

小红薯最新x-s 算法补环境教程12-06更新(下)

在上一篇文章中已经讲了如何去定位x-s生成的位置&#xff0c;本篇文章就直接开始撸代码吧 如果没看过的话可以看&#xff1a;小红薯最新x-s算法分析12-06&#xff08;x-s 56&#xff09;&#xff08;上&#xff09;-CSDN博客 1、获取加密块代码 首先来到参数生成的位置&…...

wazuh-modules-sca

wazuh中安全配置评估模块主线程执行wm_sca_main最后在wm_sca_start中循环执行&#xff0c;不会返回 // Module main function. It wont return #ifdef WIN32 DWORD WINAPI wm_sca_main(void *arg) {wm_sca_t *data (wm_sca_t *)arg; #else void * wm_sca_main(wm_sca_t * dat…...

Uniapp的App环境下使用Map获取缩放比例

概述 目前我试过的就是你用vue后缀是拿不到比例的你可以用nvue当然uniapp的uvue应该是更加可以的我使用的是高德所以你得在高德的后台声请原生的Android的key才可以如果是vue3的开发模式的话不用使用this来获取当前对象使用scale对象来接受和改变缩放比例会比较友好然后直接走…...

微信小程序配置less并使用

1.在VScode中下载Less插件 2.在微信小程序中依次点击如下按钮 选择 从已解压的扩展文件夹安装… 3.选中刚在vscode中下载安装的插件文件 如果没有修改过插件的安装目录&#xff0c;一般是在c盘下C:\用户\用户名.vscode\extensions\mrcrowl.easy-less-2.0.2 我的路径是&#xf…...

“全面支持公路数字化转型升级四大任务”视频孪生解决方案

数字经济的加速布局&#xff0c;对交通领域数字化转型、智能化升级提出明确要求。2024年上半年&#xff0c;为深入贯彻落实中共中央、国务院关于加快建设交通强国、数字中国等决策部署&#xff0c;推进公路水路交通基础设施数字转型、智能升级、融合创新&#xff0c;加快发展新…...

顶顶通电话机器人开发接口对接大语言模型之实时流TTS对接介绍

大语言模型一般都是流式返回文字&#xff0c;如果等全部文字返回了一次性去TTS&#xff0c;那么延迟会非常严重&#xff0c;常用的方法就是通过标点符号断句&#xff0c;返回了一句话就提交给TTS。随着流TTS的出现&#xff0c;就可以直接把大模型返回的文字灌给流TTS&#xff0…...

P3379 【模板】最近公共祖先(LCA)

【模板】最近公共祖先&#xff08;LCA&#xff09; https://www.luogu.com.cn/problem/P3379 题目描述 如题&#xff0c;给定一棵有根多叉树&#xff0c;请求出指定两个点直接最近的公共祖先。 输入格式 第一行包含三个正整数 N , M , S N,M,S N,M,S&#xff0c;分别表示…...

2030. gitLab A仓同步到B仓

文章目录 1 A 仓库备份 到 B 仓库2 B 仓库修改main分支的权限 1 A 仓库备份 到 B 仓库 #!/bin/bash# 定义变量 REPO_DIR"/home/xhome/opt/git_sync/zz_xx_xx" # 替换为你的本地库A的实际路径 REMOTE_ORIGIN"http://192.168.1.66:8181/zzkj_software/zz_xx_xx.…...

网易博客旧文-----如何在WINDOWS下载安卓(android)源代码并和eclipse做关联

如何在WINDOWS下载安卓&#xff08;android&#xff09;源代码并和eclipse做关联 2013-02-05 17:27:16| 分类&#xff1a; 安卓开发 | 标签&#xff1a; |举报 |字号大中小 订阅 编写安卓程序时&#xff0c;有时想看看安卓某些类的实现&#xff0c;但默认情况下环境是不带的。…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...