当前位置: 首页 > 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;但默认情况下环境是不带的。…...

MATLAB中axes函数用法

目录 语法 说明 示例 在图窗中定位多个坐标区 将坐标区设置为当前坐标区 在选项卡上创建坐标区 axes函数的功能是创建笛卡尔坐标区。 语法 axes axes(Name,Value) axes(parent,Name,Value) ax axes(___) axes(cax) 说明 axes 在当前图窗中创建默认的笛卡尔坐标区&…...

构建 Java Web 应用程序:实现简单的增删查改(Mysql)

简介 本教程将指导您如何使用Java Servlet和JSP技术构建一个简单的Web应用程序。该应用程序将包括用户注册、登录、注销&#xff08;删除用户信息&#xff09;、修改密码以及根据性别查询用户信息等功能。我们将使用MySQL数据库来存储用户数据。 环境准备 Java Development …...

3d行政区划-中国地图

前言 技术调研&#xff1a;做底代码平台的3d行政区组件 写的demo 效果图&#xff1a; 实现的功能项 地标、打点、飞线、three.js 3d 中国地图的一些基础配置补充 geo中国地图文件获取 其他项:包 "dependencies": {"d3": "^7.9.0","d3-…...

适合存储时序数据的数据库和存储系统

时序数据的存储通常要求高效地处理大量按时间排序的数据&#xff0c;同时支持快速查询、实时分析和高并发写入。以下是一些适合存储时序数据的数据库和存储系统&#xff1a; 1. InfluxDB 概述&#xff1a;InfluxDB 是一个开源的时序数据库&#xff0c;专门为处理时序数据而设…...

dolphinscheduler集群服务一键安装启动实现流程剖析

1.dolphinscheduler的安装部署 dolphinscheduler服务的安装部署都是非常简单的&#xff0c;因为就服务本身而言依赖的服务并不多。 mysql / postgresql。由于需要进行元数据及业务数据的持久化存储所以需要依赖于数据库服务&#xff0c;数据库服务支持mysql、postgresql等&am…...

深入了解Linux —— 学会使用vim编辑器

前言 学习了Linux中的基本指令也理解了权限这一概念&#xff0c;但是我们怎么在Linux下写代码呢&#xff1f; 本篇就来深入学习Linux下的vim编辑器&#xff1b;学会在Linux下写代码。 软件包管理器 1. 软件包&#xff1f; 在Linux下安装软件&#xff0c;通常是下载程序的源码…...

C05S01-Web基础和HTTP协议

一、Web基础 1. Web相关概念 1.1 URL URL&#xff08;Uniform Resource Locator&#xff0c;统一资源定位符&#xff09;&#xff0c;是一种用于在互联网上标识和定位资源的标准化地址&#xff0c;提供了一种访问互联网上特定资源的方法。URL的基本格式如下所示&#xff1a;…...

MIT工具课第六课任务 Git基础练习题

如果您之前从来没有用过 Git&#xff0c;推荐您阅读 Pro Git 的前几章&#xff0c;或者完成像 Learn Git Branching 这样的教程。重点关注 Git 命令和数据模型相关内容&#xff1b; 相关内容整理链接&#xff1a;Linux Git新手入门 git常用命令 Git全面指南&#xff1a;基础概念…...

计算机网络安全

从广义来说&#xff0c;凡是涉及到网络上信息的机密性、报文完整性、端点鉴别等技术和理论都是网络安全的研究领域。 机密性指仅有发送方和接收方能理解传输报文的内容&#xff0c;而其他未授权用户不能解密&#xff08;理解&#xff09;该报文报文完整性指报文在传输过程中不…...

Delphi 实现键盘模拟、锁定键盘,锁定鼠标等操作

Delphi 模拟按键的方法 SendMessageA 说明: 调用一个窗口的窗口函数&#xff0c;将一条消息发给那个窗口。除非消息处理完毕&#xff0c;否则该函数不会返回SendMessage所包含4个参数: 1. hwnd 32位的窗口句柄窗口可以是任何类型的屏幕对象&#xff0c;因为Win32能够维护大多数…...