高并发系统设计 -- 服务限流算法

news/2024/9/19 8:14:52/

常见的限流算法

漏桶算法

img

漏桶法的关键点在于漏桶始终按照固定的速率运行,但是它并不能很好的处理有大量突发请求的场景,毕竟在某些场景下我们可能需要提高系统的处理效率,而不是一味的按照固定速率处理请求。

关于漏桶的实现,uber团队有一个开源的github.com/uber-go/ratelimit库。 这个库的使用方法比较简单,Take() 方法会返回漏桶下一次滴水的时间。

package mainimport ("fmt""time""go.uber.org/ratelimit"
)func main() {r1 := ratelimit.New(10) // (10表示1s/10,即每100ms(0.1s)运行一次;同理,1表示1s/1,即每秒运行一次)prev := time.Now()for i := 0; i < 10; i++ {now := r1.Take()fmt.Println(i, now.Sub(prev))prev = now}
}

令牌桶算法

令牌桶(Token bucket)其实和漏桶的原理类似,令牌桶按固定的速率往桶里放入令牌,并且只要能从桶里取出令牌就能通过令牌桶支持突发流量的快速处理

img

对于从桶里取不到令牌的场景,我们可以选择等待也可以直接拒绝并返回。

对于令牌桶的Go语言实现,大家可以参照github.com/juju/ratelimit库。这个库支持多种令牌桶模式,并且使用起来也比较简单。

创建令牌桶的方法:

// 创建指定填充速率和容量大小的令牌桶
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

虽说是令牌桶,但是我们没有必要真的去生成令牌放到桶里,我们只需要每次来取令牌的时候计算一下,当前是否有足够的令牌就可以了,具体的计算方式可以总结为下面的公式:

当前令牌数 = 上一次剩余的令牌数 + (本次取令牌的时刻-上一次取令牌的时刻)/放置令牌的时间间隔 * 每次放置的令牌数

我们推荐使用令牌桶算法。

gin中使用限流中间件

import ("github.com/gin-gonic/gin""github.com/juju/ratelimit""net/http""time"
)func RateLimit() gin.HandlerFunc {// 每100ms填充一个令牌,令牌桶容量为10000bucket := ratelimit.NewBucket(time.Microsecond*100, int64(10000))return func(c *gin.Context) {// 如果获取不到令牌就中断本次请求返回if bucket.TakeAvailable(1) < 1 {c.JSON(http.StatusOK, gin.H{"msg": "rate limit...",})c.Abort()return}}
}

我们可以看到这个中间件里面使用了c.Abort这一个代码,所以接下来我们来讲解一下c.Abort

c.Next和c.Abort

Next():在当前中间件中调用c.Next()时会中断当前中间件中后续的逻辑转而执行后续的中间件和handlers,等它们全部执行完之后再回来执行当前中间件的后续代码。

结论

  • c.Next()只针对当前的中间件,并不影响其他中间件。如果在中间件函数的非结尾调用Next()方法当前中间件剩余代码会被暂停执行,会先去执行后续中间件及handlers,等这些handlers全部执行完以后程序控制权会回到当前中间件继续执行剩余代码;
  • 如果想中断剩余中间件以及handlers应该使用Abort方法,但需要注意当前中间件的剩余代码会继续执行。
  • 如果想提前中止当前中间件的执行应该使用return退出而不是Next()方法;

http://www.ppmy.cn/news/8712.html

相关文章

计算机网络体系结构

目录常见的计算机网络体系结构计算机网络体系结构分层的必要性计算机网络体系结构分层思想举例计算机网络体系结构中的专用术语常见的计算机网络体系结构 TCP/IP体系结构相当于将OSI体系结构的物理层和数据链路层合并为网络接口层。并去掉了会话层和表示层。 由于TCP/IP在网络…

应用上K8S:Gradle打包

需求 对于spring boot项目我们一般使用Maven或Gradle进行编译打包&#xff0c;也可以借助docker plugin进行镜像打包并push到远程仓库。因此在经过《Docker随时随地玩转变量》一文&#xff0c;我们已经确定了Dockerfile&#xff0c;那么应用上K8S第二步&#xff1a;gradle打包…

D2. RGB Substring (hard version)(尺取)

Problem - 1196D2 - Codeforces 通用领域 医学 计算机 金融经济 你有一个包含n个字符的字符串s&#xff0c;每个字符是R&#xff0c; G或B。 你还得到一个整数k。你的任务是改变初始字符串s中的最小字符数&#xff0c;这样在改变之后&#xff0c;将会有一个长度为k的字符串…

gateway基本配置

目录 1、gateway简介 2、gateway核心概念 3、路由 4、断言 5、过滤器 5.1、过滤器介绍 5.2、内置局部过滤器与使用 5.3、内置全局过滤器 5.4、自定义全局过滤器 5.4.1、黑名单校验 5.4.2、模拟登录校验 6、一个简单的gateway配置实例 1、gateway简介 路由转发 执行…

【android Framework 探究】android 13 aosp 全记录 - 烧录

相关文章&#xff1a;【android Framework 探究】android 13 aosp编译全记录 写在开始 书接上文&#xff0c;编译完后&#xff0c;在二手平台挑挑拣拣最终下手piexl 5&#xff0c;这就开始迫不及待的烧录。 一&#xff0c;解锁bootloader 如果之前已经解锁可以跳过这步 adb r…

SpringBoot整合ShardingJdbc实现数据库水平分表实战

(1)添加Maven依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

表白墙 -- 前后端代码详解

表白墙 -- 前后端代码详解一、前端二、后端实现2.1 需求2.2 创建项目及初始化2.3 实现提交数据 (存档)2.3.1 实现 doPost2.3.2 构造请求 (修改 html 文件)2.3.3 验证2.4 实现获取数据 (读档)2.4.1 实现 doGet2.4.2 构造请求 (修改 html 文件)2.4.3 验证三、JDBC 版本 (MySQL)3.…

Java个人家乡博客源码

概述 个人博客相册家乡主题&#xff0c;用户注册后可以发布关于家乡的特色文章介绍&#xff0c;可以发布照片&#xff0c;相册管理&#xff0c;留言&#xff0c;评论&#xff0c;回复&#xff0c;收藏&#xff0c;关注 演示视频 https://www.bilibili.com/video/BV1iy4y1x7w6…

Python数据分析案例16——水质检测(支持向量机)

本次带来图片分类的案例&#xff0c;水质检测。 数据展示 五种类别的水质&#xff0c;图片形式储存的&#xff1a; 前面1是代表水质的类别标签&#xff0c;后面是样本个数。 图片特征构建 import numpy as np import pandas as pd import matplotlib.pyplot as plt import o…

Python代码实现学生管理系统

Python代码实现学生管理系统 需求说明 实现一个命令行版本的学生管理系统 功能: 新增学生 显示学生 查找学生 删除学生 存档到文件 创建入口函数 使用一个全局列表 students 表示所有学生信息. 使用 menu 函数和用户交互. 这是一个自定义函数. 使用 insert , show ,…

56. 数据增广 / 图像增广

1. CES上的真实故事 2. 数据增强 增加一个已有数据集&#xff0c;使得有更多的多样性 在语言里加入各种不同的背景噪音改变图片的颜色和形状 例如&#xff0c;我们可以以不同的方式裁剪图像&#xff0c;使感兴趣的对象出现在不同的位置&#xff0c;减少模型对于对象出现位置…

Python全栈开发(一)——环境搭建和入门

今天是2023年的第一天&#xff0c;接下来的一个月里&#xff0c;我将持续更新关于python全栈开发的相关知识&#xff0c;前面一段时间都是基础语法。主要分成四大块&#xff1a;基础、面向对象、MYSQL数据库、Django框架。话不多说&#xff0c;进入到今天的主题。 1.文档和工具…

【CSP】邻域均值

邻域均值 邻域均值 题意比较好理解&#xff0c;就是算一些数字。如果采用暴力方法的话&#xff0c;就是用一个边长为 2∗r12*r12∗r1 的正方形框框住大矩阵&#xff0c;然后遍历这个框&#xff0c;求出其平均值&#xff0c;然后移动正方形框&#xff0c;直到大矩阵内所有像…

MySql底层索引原理

前言 我们都知道MySql索引效率很高&#xff01;那其中的原理是什么呢&#xff1f;先跑出个问题来&#xff1a;二叉树、红黑树&#xff08;二叉平衡树&#xff09;、BTree&#xff08;平衡多叉树&#xff09;、Btree这几种类型中哪一种是mysql索引所选择的呢&#xff1f; 这个…

更新和删除数据

目录1、更新数据2、根据其他表更新数据3、 删除数据4、根据其他表删除数据对于不加WHERE条件的UPDATE和DELETE要格外谨慎&#xff01; 1、更新数据 1.1 更新全部数据&#xff1a;使用UPDATE关键字。语法如下&#xff1a; UPDATE 表名 SET 字段名新的值; 比如&#xff0c;更新学…

寒假每日一题W1D3——上课睡觉

题目描述 有 N 堆石子&#xff0c;每堆的石子数量分别为 a1,a2,…,aN。 你可以对石子堆进行合并操作&#xff0c;将两个相邻的石子堆合并为一个石子堆&#xff0c;例如&#xff0c;如果 a[1,2,3,4,5]&#xff0c;合并第 2,3 堆石子&#xff0c;则石子堆集合变为 a[1,5,4,5]。…

【攻防世界】Web warmup

知识点讲解 这一题主要是利用了include的特性 如果include的文件名中含有“/”&#xff0c;那么它会识别其为一个带目录的文件&#xff0c;只有最后一个“/”后的字符串对应的文件会被包含&#xff0c;而前面的字符串都只是在指定目录 意思是&#xff0c;如果我们的payload是这…

Qt第五十五章:Qt Design Studio设计登录页并打包到python运行

目录 一、Qt Design Studio 二、导出所有文件到QRC&#xff08;不要改动默认的QRC文件名称&#xff09; 三、QRC转换成py 1.删除Constants.qml中的 2.将App.qml和Screen01.qml中的 3.转换 4、将QRC文件和转换后的py文件&#xff0c;复制到python项目中使用。 一、Qt Des…

转换通达信分钟数据,包括5分钟和1分钟数据

目录 1 前言 2 操作演示 3 代码 4 软件下载 5 stockpy整体功能介绍 1 前言 真正的市场高手不但要熟练掌握日线&#xff0c;对分钟线也要进行深入研究。缠中说禅在他的博客中讲到&#xff0c;年、季、月、周、日、60分钟、30分钟、5分钟、1分钟研究道理是相同的。粒度越细&…

20230102单独编译Toybrick的TB-RK3588X开发板的Android12的内核

20230102单独编译Toybrick的TB-RK3588X开发板的Android12的内核 2023/1/2 17:40 《RK3588_Android12_SDK_Developer_Guide_CN.pdf》 原厂的开发板rk3588-evb1-lp4-v10单独编译内核的方式&#xff1a; cd kernel-5.10 export PATH../prebuilts/clang/host/linux-x86/clang-r4161…