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

限流算法,基于go的gRPC 实现的

目录

一、单机限流

1、令牌桶算法

3、固定窗口限流算法

4、滑动窗口

二、集群限流

1、分布式固定窗口 (基于redis)

2、分布式滑动窗口


一、单机限流

1、令牌桶算法

令牌桶算法是当流量进入系统前需要获取令牌,没有令牌那么就要进行限流

这个算法是怎么实现的呢

  1. 定义一个后台协程按照一定的频率去产生token

  2. 后台协程产生的token 放到固定大小容器里面

  3. 有流量进入系统尝试拿到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、分布式固定窗口 &#xff08;基于redis&#xff09; 2、分布式滑动窗口 一、单机限流 1、令牌桶算法 令牌桶算法是当流量进入系统前需要获取令牌&#xff0c;没有令牌那么就要进行限…...

Shell中HTTP变量和文本处理

在Shell中&#xff0c;HTTP变量和文本处理是常见的任务之一。Shell是一个命令行解释器&#xff0c;可以用来自动化执行各种系统任务。在Shell中&#xff0c;我们可以使用各种命令和工具来处理HTTP变量和文本。 首先&#xff0c;让我们来看看如何在Shell中处理HTTP变量。HTTP变…...

java学习part39map

159-集合框架-Map不同实现类的对比与HashMap中元素的特点_哔哩哔哩_bilibili 1.Map 2.Entry 个人理解是c的pair&#xff0c;代表一个键值对。Map就是entry的叠加 3.常用方法 4.TreeMap 5.Properties...

使用sqoop操作HDFS与MySQL之间的数据互传

一&#xff0c;数据从HDFS中导出至MySQL中 1&#xff09;开启Hadoop、mysql进程 start-all.sh/etc/init.d/mysqld start/etc/init.d/mysqld status 2&#xff09;将学生数据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&#xff08;二&#xff09;初识ArkTS开发语言&#xff08;中&#xff09;之TypeScript入门 浅析ArkTS的起源和演进 1 引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类…...

西工大计算机学院计算机系统基础实验一(函数编写1~10)

还是那句话&#xff0c;千万不要慌&#xff0c;千万不要着急&#xff0c;耐下性子慢慢来&#xff0c;一步一个脚印&#xff0c;把基础打的牢牢的&#xff0c;一样不比那些人差。回到实验本身&#xff0c;自从​​​​​​按照西工大计算机学院计算机系统基础实验一&#xff08;…...

VMware 虚拟机 电脑重启后 NAT 模式连不上网络问题修复

问题描述&#xff1a; 昨天 VMware 安装centos7虚拟机&#xff0c;网络模式配置的是NAT模式&#xff0c;配置好后&#xff0c;当时能连上外网&#xff0c;今天电脑重启后&#xff0c;发现连不上外网了 检查下各个配置&#xff0c;都没变动&#xff0c;突然就连不上了 网上查了…...

【桑基图】绘制桑基图

绘制桑基图 一、绘制桑基图&#xff08;1&#xff09;方法一&#xff1a;去在线网站直接绘制&#xff08;2&#xff09;方法二&#xff1a;写html之后在vscode上运行 二、遇到的问题&#xff08;1&#xff09;当导入一些excel的时候&#xff0c;无法绘制出桑基图 一、绘制桑基图…...

ACM32F403/F433 12 位多通道,支持 MPU 存储保护功能,应用于工业控制,智能家居等产品中

ACM32F403/F433 芯片的内核基于 ARMv8-M 架构&#xff0c;支持 Cortex-M33 和 Cortex-M4F 指令集。芯片内核 支持一整套DSP指令用于数字信号处理&#xff0c;支持单精度FPU处理浮点数据&#xff0c;同时还支持Memory Protection Unit &#xff08;MPU&#xff09;用于提升应用的…...

7. 从零用Rust编写正反向代理, HTTP及TCP内网穿透原理及运行篇

wmproxy wmproxy是由Rust编写&#xff0c;已实现http/https代理&#xff0c;socks5代理&#xff0c; 反向代理&#xff0c;静态文件服务器&#xff0c;内网穿透&#xff0c;配置热更新等&#xff0c; 后续将实现websocket代理等&#xff0c;同时会将实现过程分享出来&#xff…...

UE4.27-UE5.1设置打包Android环境

打包Android配置文件 1. 配置打包Android的SDK需求文件位于下面文件中&#xff1a; 2. 指定了对应的SDK环境变量名字以及NDK需求等&#xff1a; UE4.27-UE5.1--脚本自动配置 安装前提 1. 务必关闭虚幻编辑器和Epic Games Launcher&#xff0c;以确保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

打开题目 点击完登录和注册都没有什么反应&#xff0c;所以先扫一下看看 在出现admin.php后就截止了&#xff0c;访问看看,进入后台。。 尝试一下弱口令 admin/12345 或者是demo/demo 设计中-自定义->右上角导出主题 找到一个导出的点&#xff0c;下载了一个1.zip压缩包…...

Doris优化总结

1 查看QueryProfile 利用查询执行的统计结果,可以更好的帮助我们了解Doris的执行情况,并有针对性的进行相应Debug与调优工作。 FE将查询计划拆分成为Fragment下发到BE进行任务执行。BE在执行Fragment时记录了运行状态时的统计值,并将Fragment执行的统计信息输出到日志之中。…...

案例059:基于微信小程序的在线投稿系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…...

利用STM32内置Bootloader实现USB DFU固件升级

本文将介绍如何利用STM32内置的Bootloader来实现USB DFU&#xff08;Device Firmware Upgrade&#xff09;固件升级功能。首先&#xff0c;我们会介绍USB DFU的原理和工作流程。然后&#xff0c;我们将详细讲解如何配置STM32芯片以支持USB DFU&#xff0c;并提供相应的代码示例…...

Centos7如何安装MySQL

目录 一、卸载mysql 二、安装mysql 注&#xff1a;本文主要是看了这位大佬安装MySQL&#xff0c;才想着写一篇记录一下。 一、卸载mysql 安装mysql之前一定要将之前安装的mysql相关文件删除干净&#xff0c;防止出现错误。 &#xff08;1&#xff09;关闭mysql 开启了mysql就…...

VR远程带看,助力线下门店线上化转型“自救”

VR远程带看&#xff0c;因自身高效的沉浸式在线沟通功能&#xff0c;逐渐走进了大众的视野。身临其境的线上漫游体验以及实时同屏互联的新型交互模式&#xff0c;提升了商家同用户之间的沟通效率&#xff0c;进一步实现了远程线上一对一、一对多的同屏带看&#xff0c;用户足不…...

算法通关村第十七关-白银挑战贪心算法高频题目

大家好我是苏麟 , 今天说说贪心算法的高频题目 . 大纲 区间问题判断区间是否重叠合并区间插入区间 区间问题 判断区间是否重叠 描述 : 给定一个会议时间安排的数组 intervals &#xff0c;每个会议时间都会包括开始和结束的时间intervalsl[i] [start, end] &#xff0c;请你…...

网易技术岗校招通关秘籍:从需求画像到Offer收割(实战篇)

1. 网易技术岗校招需求画像解析 第一次参加大厂校招的同学&#xff0c;往往会被各种岗位JD绕晕。去年我带过一个浙大的学弟&#xff0c;他同时投了网易的Java和后端开发岗&#xff0c;结果发现笔试题目完全不同。后来才知道&#xff0c;网易不同业务线对"后端开发"的…...

英雄联盟Akari助手:5大核心功能解决游戏中的常见痛点

英雄联盟Akari助手&#xff1a;5大核心功能解决游戏中的常见痛点 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power &#x1f680;. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在为英雄联盟游戏中的繁琐操…...

sqlite-utils与Datasette集成:构建数据驱动的Web应用终极指南

sqlite-utils与Datasette集成&#xff1a;构建数据驱动的Web应用终极指南 【免费下载链接】sqlite-utils Python CLI utility and library for manipulating SQLite databases 项目地址: https://gitcode.com/gh_mirrors/sq/sqlite-utils sqlite-utils是一款强大的Pytho…...

目标检测 - 从FPN到PAN:双向路径聚合如何提升特征融合效率

1. 目标检测中的特征金字塔&#xff1a;从FPN到PAN的进化之路 在目标检测任务中&#xff0c;处理多尺度目标一直是个棘手的问题。想象一下&#xff0c;你要在一张图片中同时识别出近处的行人、远处的车辆和更远处的交通标志&#xff0c;这些目标的尺寸差异可能达到数十倍。传统…...

STM32F4当USB主机,驱动CH340串口模块的保姆级调试笔记(附源码)

STM32F4作为USB主机驱动CH340模块的深度实践指南 在嵌入式开发中&#xff0c;USB主机功能扩展串口资源是常见需求。当标准CDC类设备无法满足特殊场景时&#xff0c;驱动像CH340这样的厂商自定义设备就成了一项必备技能。本文将带您深入探索STM32F4系列微控制器作为USB主机与CH3…...

终极指南:5分钟快速解密网易云音乐NCM文件,实现音乐自由

终极指南&#xff1a;5分钟快速解密网易云音乐NCM文件&#xff0c;实现音乐自由 【免费下载链接】ncmdump ncmdump - 网易云音乐NCM转换 项目地址: https://gitcode.com/gh_mirrors/ncmdu/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#…...

现代化WPF可视化设计引擎:从XAML代码到拖拽式开发的效率革命

现代化WPF可视化设计引擎&#xff1a;从XAML代码到拖拽式开发的效率革命 【免费下载链接】WpfDesigner The WPF Designer from SharpDevelop 项目地址: https://gitcode.com/gh_mirrors/wp/WpfDesigner 在WPF应用程序开发中&#xff0c;手动编写XAML代码进行界面布局是每…...

终极分屏神器Nucleus Co-Op:一台电脑实现4人同时开黑完整指南

终极分屏神器Nucleus Co-Op&#xff1a;一台电脑实现4人同时开黑完整指南 【免费下载链接】nucleuscoop Starts multiple instances of a game for split-screen multiplayer gaming! 项目地址: https://gitcode.com/gh_mirrors/nu/nucleuscoop 你是否曾因朋友聚会时电脑…...

【大模型服务治理实战指南】:奇点智能大会首发的7大避坑法则与3套可落地架构模板

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;大模型服务治理&#xff1a;奇点智能大会 在2024年奇点智能大会上&#xff0c;大模型服务治理成为核心议题。随着LLM推理服务规模化部署&#xff0c;企业面临模型版本混乱、流量调度失衡、资源隔离缺失…...

OpenClaw Mattermost插件:为团队协作平台注入AI智能的轻量集成方案

1. 项目概述&#xff1a;为团队协作平台注入AI灵魂如果你所在的技术团队正在使用 Mattermost 这类自托管、注重数据隐私的团队协作工具&#xff0c;同时又希望引入一个能处理工单、回答疑问、甚至自动执行任务的智能助手&#xff0c;那么你很可能已经厌倦了那些需要复杂 API 调…...