限流算法,基于go的gRPC 实现的
目录
一、单机限流
1、令牌桶算法
3、固定窗口限流算法
4、滑动窗口
二、集群限流
1、分布式固定窗口 (基于redis)
2、分布式滑动窗口
一、单机限流
1、令牌桶算法
令牌桶算法是当流量进入系统前需要获取令牌,没有令牌那么就要进行限流
这个算法是怎么实现的呢
-
定义一个后台协程按照一定的频率去产生token
-
后台协程产生的token 放到固定大小容器里面
-
有流量进入系统尝试拿到token,没有token 就需要限流了

type TokenBucketLimiter struct {token chan struct{}stop chan struct{}
}
func NewTokenBucket(capactity int, timeInternal time.Duration) *TokenBucketLimiter {te := make(chan struct{}, capactity)stop := make(chan struct{})ticker := time.NewTicker(timeInternal)go func() {defer ticker.Stop()for {select {case <-ticker.C:select {case te <- struct{}{}:default:
}case <-stop:return}}}()return &TokenBucketLimiter{token: te,stop: stop,}
}
func (t *TokenBucketLimiter) BuildServerInterceptor() grpc.UnaryServerInterceptor {return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {select {case <-ctx.Done():err = ctx.Err()returncase <-t.token:return handler(ctx, req)case <-t.stop:err = errors.New("缺乏保护")return}}
}
func (t *TokenBucketLimiter) Stop() {close(t.stop)
}
3、固定窗口限流算法
什么是固定窗口限流算法
固定窗口限流算法(Fixed Window Rate Limiting Algorithm)是一种最简单的限流算法,其原理是在固定时间窗口(单位时间)内限制请求的数量。该算法将时间分成固定的窗口,并在每个窗口内限制请求的数量。具体来说,算法将请求按照时间顺序放入时间窗口中,并计算该时间窗口内的请求数量,如果请求数量超出了限制,则拒绝该请求。
优点:实现简单
缺点:对于瞬时流量没发处理,也就是临界问题,比如下图在20t前后,在16t以及26t有大量流量进来,在这10t中,已经超过了流量限制,没法限流
实现如下

type fixWindow1 struct {lastVistTime int64vistCount int64interval int64maxCount int64
}
func NewfixWindow1(macCount int64) *fixWindow1 {t := &fixWindow1{maxCount: macCount,}return t
}
func (f *fixWindow1) FixWindow1() grpc.UnaryServerInterceptor {return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {current := time.Now().UnixNano()lasttime := atomic.LoadInt64(&f.lastVistTime)if lasttime+f.interval > current {if atomic.CompareAndSwapInt64(&f.lastVistTime, lasttime, current) {atomic.StoreInt64(&f.lastVistTime, current)atomic.StoreInt64(&f.maxCount, 0)}}count := atomic.AddInt64(&f.vistCount, 1)if count > f.maxCount {return gen.GetByIDResp{}, errors.New("触发限流")}return handler(ctx, req)}
}
4、滑动窗口
什么是滑动窗口算法:
滑动窗口限流算法是一种常用的限流算法,用于控制系统对外提供服务的速率,防止系统被过多的请求压垮。它将单位时间周期分为n个小周期,分别记录每个小周期内接口的访问次数,并且根据时间滑动删除过期的小周期。它可以解决固定窗口临界值的问题。

type slideWindow struct {
timeWindow *list.Listinterval int64maxCnt intlock sync.Mutex
}
func NewSlideWindow(interval time.Duration, maxCnt int) *slideWindow {t := &slideWindow{timeWindow: list.New(),interval: interval.Nanoseconds(),maxCnt: maxCnt,}return t
}
func (s *slideWindow) SlideWinowlimit() grpc.UnaryServerInterceptor {return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {s.lock.Lock()now := time.Now().UnixNano()// 快路径if s.timeWindow.Len() < s.maxCnt {resp, err = handler(ctx, req)s.timeWindow.PushBack(now)s.lock.Unlock()return}front := s.timeWindow.Front()for front != nil && front.Value.(int64)+s.interval < now {s.timeWindow.Remove(front)front = s.timeWindow.Front()}if s.timeWindow.Len() >= s.maxCnt {s.lock.Unlock()return &gen.GetByIdReq{}, errors.New("触发限流")}s.lock.Unlock()resp, err = handler(ctx, req)s.timeWindow.PushBack(now)return}
}
二、集群限流
下面是分布式限流,为啥是分布式限流,单机限流只能对单台服务器进行限流,没发对集权进行限流,需要用分布式限流来进行集权限流
1、分布式固定窗口 (基于redis)
type redisFix struct {
serName stringinterVal intlimitCnt intredis redis.Cmdable
}
//go:embed lua/fixwindow.lua
var lua_redis_fix string
func NewRedisFix(serName string, interval int, limitCnt int, redis redis.Cmdable) *redisFix {t := &redisFix{serName: serName,interVal: interval,limitCnt: limitCnt,redis: redis,}return t
}
func (r *redisFix) RedisFix() grpc.UnaryServerInterceptor {return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {res, err := r.limit(ctx)if err != nil {return &gen.GetByIDResp{}, err}if res {return &gen.GetByIdReq{}, errors.New("触发限流")}return handler(ctx, req)}
}
func (r *redisFix) limit(ctx context.Context) (res bool, err error) {keys := []string{r.serName}res, err = r.redis.Eval(ctx, lua_redis_fix, keys, r.interVal, r.limitCnt).Bool()return
}
lua
local key = KEYS[1]
local limitCnt = tonumber(ARGV[2])
local val = redis.call('get',key)
if val==false thenif limitCnt<1 thenreturn "true"elseredis.call('set',key,1,'PX',ARGV[1])return "false"end
elseif tonumber(val)<limitCnt thenredis.call('incr',key)return "false"
elsereturn "true"
end
2、分布式滑动窗口
//go:embed lua/slidewindow.lua
var slideWindLua string
type redisSlib struct {serverName stringinterVal time.DurationmaxCnt int64redis redis.Cmdable
}
func NewRedisSlib(interval time.Duration, maxCnt int64, serverName string, clientCmd redis.Cmdable) *redisSlib {t := &redisSlib{serverName: serverName,interVal: interval,maxCnt: maxCnt,redis: clientCmd,}return t
}
func (r *redisSlib) RedisSlibLimt() grpc.UnaryServerInterceptor {return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {limt, err := r.limt(ctx)if err != nil {return nil, err}if limt {return nil, errors.New("限流")}return handler(ctx, req)}
}
func (r *redisSlib) limt(ctx context.Context) (bool, error) {now := time.Now().UnixMilli()return r.redis.Eval(ctx, slideWindLua, []string{r.serverName}, r.interVal.Milliseconds(), r.maxCnt, now).Bool()
}
lua
local key = KEYS[1]
local window = tonumber(ARGV[1])
local maxCnt = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
--- 窗口的最小边界
local min = now-window
redis.call('ZREMRANGEBYSCORE',key,'-inf',min)
local cnt = redis.call('ZCOUNT',key,'-inf','+inf')
if cnt>=maxCnt thenreturn "true"
elseredis.call('ZADD',key,now,now)redis.call('PEXPIRE',key,window)return "false"
end
相关文章:
限流算法,基于go的gRPC 实现的
目录 一、单机限流 1、令牌桶算法 3、固定窗口限流算法 4、滑动窗口 二、集群限流 1、分布式固定窗口 (基于redis) 2、分布式滑动窗口 一、单机限流 1、令牌桶算法 令牌桶算法是当流量进入系统前需要获取令牌,没有令牌那么就要进行限…...
Shell中HTTP变量和文本处理
在Shell中,HTTP变量和文本处理是常见的任务之一。Shell是一个命令行解释器,可以用来自动化执行各种系统任务。在Shell中,我们可以使用各种命令和工具来处理HTTP变量和文本。 首先,让我们来看看如何在Shell中处理HTTP变量。HTTP变…...
java学习part39map
159-集合框架-Map不同实现类的对比与HashMap中元素的特点_哔哩哔哩_bilibili 1.Map 2.Entry 个人理解是c的pair,代表一个键值对。Map就是entry的叠加 3.常用方法 4.TreeMap 5.Properties...
使用sqoop操作HDFS与MySQL之间的数据互传
一,数据从HDFS中导出至MySQL中 1)开启Hadoop、mysql进程 start-all.sh/etc/init.d/mysqld start/etc/init.d/mysqld status 2)将学生数据stu_data.csv传到HDFS的/local_student目录下 在hdfs中创建目录 hdfs dfs -mkdir /local_student 上…...
Kafka使用指南
Kafka简介架构设计Kafka的架构设计关键概念Kafka的架构设计关键机制 Partition介绍Partition工作机制 应用场景ACK机制介绍ACK机制原理ACK机制对性能的影响ACK控制粒度Kafka分区数对集群性能影响调整分区优化集群性能拓展Kafka数据全局有序 Kafka简介 Kafka是由Apache软件基金…...
HarmonyOS4.0从零开始的开发教程03初识ArkTS开发语言(中)
HarmonyOS(二)初识ArkTS开发语言(中)之TypeScript入门 浅析ArkTS的起源和演进 1 引言 Mozilla创造了JS,Microsoft创建了TS,Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力,到具备类…...
西工大计算机学院计算机系统基础实验一(函数编写1~10)
还是那句话,千万不要慌,千万不要着急,耐下性子慢慢来,一步一个脚印,把基础打的牢牢的,一样不比那些人差。回到实验本身,自从按照西工大计算机学院计算机系统基础实验一(…...
VMware 虚拟机 电脑重启后 NAT 模式连不上网络问题修复
问题描述: 昨天 VMware 安装centos7虚拟机,网络模式配置的是NAT模式,配置好后,当时能连上外网,今天电脑重启后,发现连不上外网了 检查下各个配置,都没变动,突然就连不上了 网上查了…...
【桑基图】绘制桑基图
绘制桑基图 一、绘制桑基图(1)方法一:去在线网站直接绘制(2)方法二:写html之后在vscode上运行 二、遇到的问题(1)当导入一些excel的时候,无法绘制出桑基图 一、绘制桑基图…...
ACM32F403/F433 12 位多通道,支持 MPU 存储保护功能,应用于工业控制,智能家居等产品中
ACM32F403/F433 芯片的内核基于 ARMv8-M 架构,支持 Cortex-M33 和 Cortex-M4F 指令集。芯片内核 支持一整套DSP指令用于数字信号处理,支持单精度FPU处理浮点数据,同时还支持Memory Protection Unit (MPU)用于提升应用的…...
7. 从零用Rust编写正反向代理, HTTP及TCP内网穿透原理及运行篇
wmproxy wmproxy是由Rust编写,已实现http/https代理,socks5代理, 反向代理,静态文件服务器,内网穿透,配置热更新等, 后续将实现websocket代理等,同时会将实现过程分享出来ÿ…...
UE4.27-UE5.1设置打包Android环境
打包Android配置文件 1. 配置打包Android的SDK需求文件位于下面文件中: 2. 指定了对应的SDK环境变量名字以及NDK需求等: UE4.27-UE5.1--脚本自动配置 安装前提 1. 务必关闭虚幻编辑器和Epic Games Launcher,以确保NDK组件的安装或引擎环境…...
MySQL授权密码
mysql> crate databases school charcter set utf8; Query OK, 1 row affected, 1 warning (0.00 sec) 2.在school数据库中创建Student和Score表 mysql> use school Database changed mysql> create table student-> -> (id int(10) primary key auto_incremen…...
0X05
打开题目 点击完登录和注册都没有什么反应,所以先扫一下看看 在出现admin.php后就截止了,访问看看,进入后台。。 尝试一下弱口令 admin/12345 或者是demo/demo 设计中-自定义->右上角导出主题 找到一个导出的点,下载了一个1.zip压缩包…...
Doris优化总结
1 查看QueryProfile 利用查询执行的统计结果,可以更好的帮助我们了解Doris的执行情况,并有针对性的进行相应Debug与调优工作。 FE将查询计划拆分成为Fragment下发到BE进行任务执行。BE在执行Fragment时记录了运行状态时的统计值,并将Fragment执行的统计信息输出到日志之中。…...
案例059:基于微信小程序的在线投稿系统
文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…...
利用STM32内置Bootloader实现USB DFU固件升级
本文将介绍如何利用STM32内置的Bootloader来实现USB DFU(Device Firmware Upgrade)固件升级功能。首先,我们会介绍USB DFU的原理和工作流程。然后,我们将详细讲解如何配置STM32芯片以支持USB DFU,并提供相应的代码示例…...
Centos7如何安装MySQL
目录 一、卸载mysql 二、安装mysql 注:本文主要是看了这位大佬安装MySQL,才想着写一篇记录一下。 一、卸载mysql 安装mysql之前一定要将之前安装的mysql相关文件删除干净,防止出现错误。 (1)关闭mysql 开启了mysql就…...
VR远程带看,助力线下门店线上化转型“自救”
VR远程带看,因自身高效的沉浸式在线沟通功能,逐渐走进了大众的视野。身临其境的线上漫游体验以及实时同屏互联的新型交互模式,提升了商家同用户之间的沟通效率,进一步实现了远程线上一对一、一对多的同屏带看,用户足不…...
算法通关村第十七关-白银挑战贪心算法高频题目
大家好我是苏麟 , 今天说说贪心算法的高频题目 . 大纲 区间问题判断区间是否重叠合并区间插入区间 区间问题 判断区间是否重叠 描述 : 给定一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间intervalsl[i] [start, end] ,请你…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...
