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

go-zero 是如何实现计数器限流的?

原文链接: 如何实现计数器限流?

上一篇文章 go-zero 是如何做路由管理的? 介绍了路由管理,这篇文章来说说限流,主要介绍计数器限流算法,具体的代码实现,我们还是来分析微服务框架 go-zero 的源码。

在微服务架构中,一个服务可能需要频繁地与其他服务交互,而过多的请求可能导致性能下降或系统崩溃。为了确保系统的稳定性和高可用性,限流算法应运而生。

限流算法允许在给定时间段内,对服务的请求流量进行控制和调整,以防止资源耗尽和服务过载。

计数器限流算法主要有两种实现方式,分别是:

  1. 固定窗口计数器
  2. 滑动窗口计数器

下面分别来介绍。

固定窗口计数器

算法概念如下:

  • 将时间划分为多个窗口;
  • 在每个窗口内每有一次请求就将计数器加一;
  • 如果计数器超过了限制数量,则本窗口内所有的请求都被丢弃当时间到达下一个窗口时,计数器重置。

固定窗口计数器是最为简单的算法,但这个算法有时会让通过请求量允许为限制的两倍。

考虑如下情况:限制 1 秒内最多通过 5 个请求,在第一个窗口的最后半秒内通过了 5 个请求,第二个窗口的前半秒内又通过了 5 个请求。这样看来就是在 1 秒内通过了 10 个请求。

滑动窗口计数器

算法概念如下:

  • 将时间划分为多个区间;
  • 在每个区间内每有一次请求就将计数器加一维持一个时间窗口,占据多个区间;
  • 每经过一个区间的时间,则抛弃最老的一个区间,并纳入最新的一个区间;
  • 如果当前窗口内区间的请求计数总和超过了限制数量,则本窗口内所有的请求都被丢弃。

滑动窗口计数器是通过将窗口再细分,并且按照时间滑动,这种算法避免了固定窗口计数器带来的双倍突发请求,但时间区间的精度越高,算法所需的空间容量就越大。

go-zero 实现

go-zero 实现的是固定窗口的方式,计算一段时间内对同一个资源的访问次数,如果超过指定的 limit,则拒绝访问。当然如果在一段时间内访问不同的资源,每一个资源访问量都不超过 limit,此种情况是不会拒绝的。

而在一个分布式系统中,存在多个微服务提供服务。所以当瞬间的流量同时访问同一个资源,如何让计数器在分布式系统中正常计数?

这里要解决的一个主要问题就是计算的原子性,保证多个计算都能得到正确结果。

通过以下两个方面来解决:

  • 使用 redis 的 incrby 做资源访问计数
  • 采用 lua script 做整个窗口计算,保证计算的原子性

接下来先看一下 lua script 的源码:

// core/limit/periodlimit.goconst periodScript = `local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCRBY", KEYS[1], 1)
if current == 1 thenredis.call("expire", KEYS[1], window)
end
if current < limit thenreturn 1
elseif current == limit thenreturn 2
elsereturn 0
end`

主要就是使用 INCRBY 命令来实现,第一次请求需要给 key 加上一个过期时间,到达过期时间之后,key 过期被清楚,重新计数。

限流器初始化:

type (// PeriodOption defines the method to customize a PeriodLimit.PeriodOption func(l *PeriodLimit)// A PeriodLimit is used to limit requests during a period of time.PeriodLimit struct {period     int  // 窗口大小,单位 squota      int  // 请求上限limitStore *redis.RediskeyPrefix  string   // key 前缀align      bool}
)// NewPeriodLimit returns a PeriodLimit with given parameters.
func NewPeriodLimit(period, quota int, limitStore *redis.Redis, keyPrefix string,opts ...PeriodOption) *PeriodLimit {limiter := &PeriodLimit{period:     period,quota:      quota,limitStore: limitStore,keyPrefix:  keyPrefix,}for _, opt := range opts {opt(limiter)}return limiter
}

调用限流:

// key 就是需要被限制的资源标识
func (h *PeriodLimit) Take(key string) (int, error) {return h.TakeCtx(context.Background(), key)
}// TakeCtx requests a permit with context, it returns the permit state.
func (h *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error) {resp, err := h.limitStore.EvalCtx(ctx, periodScript, []string{h.keyPrefix + key}, []string{strconv.Itoa(h.quota),strconv.Itoa(h.calcExpireSeconds()),})if err != nil {return Unknown, err}code, ok := resp.(int64)if !ok {return Unknown, ErrUnknownCode}switch code {case internalOverQuota: // 超过上限return OverQuota, nilcase internalAllowed:   // 未超过,允许访问return Allowed, nilcase internalHitQuota:  // 正好达到限流上限return HitQuota, nildefault:return Unknown, ErrUnknownCode}
}

上文已经介绍了,固定时间窗口会有临界突发问题,并不是那么严谨,下篇文章我们来介绍令牌桶限流。

以上就是本文的全部内容,如果觉得还不错的话欢迎点赞转发关注,感谢支持。


参考文章:

  • https://juejin.cn/post/6895928148521648141
  • https://juejin.cn/post/7051406419823689765
  • https://www.infoq.cn/article/Qg2tX8fyw5Vt-f3HH673

推荐阅读:

  • go-zero 是如何做路由管理的?

相关文章:

go-zero 是如何实现计数器限流的?

原文链接&#xff1a; 如何实现计数器限流&#xff1f; 上一篇文章 go-zero 是如何做路由管理的&#xff1f; 介绍了路由管理&#xff0c;这篇文章来说说限流&#xff0c;主要介绍计数器限流算法&#xff0c;具体的代码实现&#xff0c;我们还是来分析微服务框架 go-zero 的源…...

【考研复习】24王道数据结构课后习题代码|第3章栈与队列

文章目录 3.1 栈3.2 队列3.3 栈和队列的应用 3.1 栈 int symmetry(linklist L,int n){char s[n/2];lnode *pL->next;int i;for(i0;i<n/2;i){s[i]p->data;pp->next;}i--;if(n%21) pp->next;while(p&&s[i]p->data){i--;pp->next;}if(i-1) return 1;…...

java中excel文件下载

1、System.getProperty(user.dir) 获取的是启动项目的容器位置 2、 Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING); StandardCopyOption.REPLACE_EXISTING 来忽略文件已经存在的异常&#xff0c;如果存在就去覆盖掉它Sta…...

29 | 广州美食店铺数据分析

广州美食店铺数据分析 一、数据分析项目MVP加/价值主张宣言 随着经济的快速发展以及新媒体的兴起,美食攻略、美食探店等一系列东西进入大众的眼球,而人们也会在各大平台中查找美食推荐,因此本项目做的美食店铺数据分析也是带有可行性的。首先通过对广东省的各市美食店铺数量…...

fastApi基础

1、fastApi简介 官方文档&#xff1a;https://fastapi.tiangolo.com/ 源码&#xff1a; https://github.com/tiangolo/fastapi 2、环境准备 安装python 安装pycharm 安装fastAPI 安装 uvicorn 查看已经安装的第三方库&#xff1a;pip list 查看pip 配置信息&#xff1a;pip co…...

Mysql整理二 - 常见查询语句面试题(附原表)

表结构&#xff0c;创建原表的代码在最后 -- cid课程id; tid老师id; sid学生id; select * from t_mysql_course; select * from t_mysql_score; select * from t_mysql_student; select * from t_mysql_teacher; 1. 查询" 01 “课程比” 02 "课程成绩高的学生的信息…...

Python - 读取pdf、word、excel、ppt、csv、txt文件提取所有文本

前言 本文对使用python读取pdf、word、excel、ppt、csv、txt等常用文件&#xff0c;并提取所有文本的方法进行分享和使用总结。 可以读取不同文件的库和方法当然不止下面分享的这些&#xff0c;本文的代码主要目标都是&#xff1a;方便提取文件中所有文本的实现方式。 这些库的…...

Codeforces Round 892 (Div. 2) C. Another Permutation Problem 纯数学方法 思维题

Codeforces Round 892 (Div. 2) C. Another Permutation Problem 源码&#xff1a; #include <iostream> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <stack> #include &l…...

持续输出:自媒体持续输出文字内容、视音频创作(视频课程、书籍章节)

以下是自媒体持续输出文字内容、视音频创作的最佳方法&#xff1a; 灵感来源&#xff1a;寻找灵感来源是自媒体创作的重要一环。可以从日常生活、网络热点、行业动态等方面寻找创作灵感。 确定主题&#xff1a;在确定主题的时候&#xff0c;需要根据读者和观众的需求&#xff…...

篇十七:备忘录模式:恢复对象状态

篇十七&#xff1a;"备忘录模式&#xff1a;恢复对象状态" 开始本篇文章之前先推荐一个好用的学习工具&#xff0c;AIRIght&#xff0c;借助于AI助手工具&#xff0c;学习事半功倍。欢迎访问&#xff1a;http://airight.fun/。 另外有2本不错的关于设计模式的资料&…...

初识mysql数据库之图形化界面

目录 一、好用的数据库图形化界面软件 1. Navicat 2. SQLyog 3. MYSQL Workbench 二、MYSQL Workbench基本使用 1. 安装 2. 远端连接 3. 执行sql语句 一、好用的数据库图形化界面软件 在以前的文章中&#xff0c;一共介绍了两种使用数据库的方式&#xff0c;分别为在l…...

APP外包开发的H5开发框架

跨平台移动应用开发框架允许开发者使用一套代码在多个操作系统上构建应用程序&#xff0c;从而节省时间和资源。以下是一些常见的跨平台移动应用开发框架以及它们的特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0…...

高性能跨平台网络通信框架 HP-Socket v5.9.3

项目主页 : http://www.oschina.net/p/hp-socket开发文档 : https://www.docin.com/p-4478351216.html下载地址 : https://github.com/ldcsaa/HP-SocketQQ Group: 44636872, 663903943 v5.9.3 更新 一、主要更新 问题修复&#xff1a;通过 POST/PUT 等带有请求内容的 HTTP 方…...

Vue3.2+TS在v-for的时候,循环处理时间,将其变成xx-xx-xx xx:xx:xx格式,最后教给大家自己封装一个时间hooks,直接复用

Vue3.2TS在v-for的时候&#xff0c;循环处理时间&#xff0c;将其变成xx-xx-xx xx:xx:xx格式 最后教给大家自己封装一个时间hooks&#xff0c;直接复用 1.没有封装&#xff0c;直接使用 <template><div><ul><li v-for"item,index in arr" :k…...

05 mysql innodb page

前言 最近看到了 何登成 大佬的 "深入MySQL源码 -- Step By Step" 的 pdf 呵呵 似乎是找到了一些 方向 之前对于 mysql 方面的东西, 更多的仅仅是简单的使用[业务中的各种增删改查], 以及一些面试题的背诵 这里会参照 MySQL Internals Manual 来大致的看一下 i…...

记录一次electron打包提示文件找不到的解决方法

没有配置files选项 files的作用是配置打包到应用程序的构建资源 就是说如果你想使用项目那个目录下的文件 就得通过files配置一下不然就会报错 json文件或者yml文件会报的错 格式是这样的 "files": ["dist-electron", "dist"],electron打包配…...

《大型网站技术架构》第二篇 架构-高可用

高可用在公司中的重要性 对公司而言&#xff0c;可用性关系网站的生死存亡。对个人而言&#xff0c;可用性关系到自己的绩效升迁。 工程师对架构做了许多优化、对代码做了很多重构&#xff0c;对性能、扩展性、伸缩性做了很多改善&#xff0c;但别人未必能直观地感受到&#…...

VS Code 使用cnpm下载包失败

一、 问题如下&#xff1a; 网上找到的解决方法是要在powershell中执行&#xff1a; Set-ExecutionPolicy RemoteSigned进行更改策略。 首先我们解释下这个Set-ExecutionPolicy RemoteSigned&#xff0c;Set-ExecutionPolicy 是一个 PowerShell 命令&#xff0c;用于控制脚本…...

【图像分类】CNN + Transformer 结合系列.4

介绍两篇利用Transformer做图像分类的论文&#xff1a;CoAtNet&#xff08;NeurIPS2021&#xff09;&#xff0c;ConvMixer&#xff08;ICLR2022&#xff09;。CoAtNet结合CNN和Transformer的优点进行改进&#xff0c;ConvMixer则patch的角度来说明划分patch有助于分类。 CoAtN…...

分享一下利用Vue表单处理实现复杂表单布局

在开发Web应用程序中&#xff0c;表单是非常常见的一种元素。而在某些情况下&#xff0c;我们需要实现一些更为复杂的表单布局&#xff0c;以满足业务需求。使用Vue.js作为前端框架&#xff0c;我们可以很方便地处理复杂表单布局&#xff0c;并且实现数据的双向绑定。 下面来将…...

Neo4j 5.x 安装后登录不上?别慌,这可能是默认密码策略在“搞鬼”

Neo4j 5.x 登录问题全解析&#xff1a;从密码策略到实战解决方案 刚接触Neo4j 5.x的开发者们&#xff0c;是否遇到过这样的场景&#xff1a;按照老教程满怀期待地输入默认用户名密码&#xff0c;却发现无论如何都登录不上Web控制台&#xff1f;这不是你的操作问题&#xff0c;…...

别再手动解算了!用STM32的DMP库5分钟搞定MPU6050姿态角(附完整代码)

STM32与MPU6050&#xff1a;5分钟实现高精度姿态解算的DMP实战指南 1. 为什么选择DMP方案进行姿态解算&#xff1f; 在嵌入式开发中&#xff0c;姿态解算一直是个让人头疼的问题。传统方法需要开发者深入理解复杂的数学算法&#xff0c;从原始传感器数据中提取欧拉角&#xf…...

Qwen3-ASR-1.7B效果展示:TED演讲级长音频端到端转写完整性验证

Qwen3-ASR-1.7B效果展示&#xff1a;TED演讲级长音频端到端转写完整性验证 1. 开篇引言&#xff1a;为什么需要高质量的语音识别&#xff1f; 在日常工作和学习中&#xff0c;我们经常遇到需要将音频内容转换为文字的场景。无论是会议记录、视频字幕制作&#xff0c;还是学习…...

如何快速实现MyBatis分页查询:PageHelper终极指南

如何快速实现MyBatis分页查询&#xff1a;PageHelper终极指南 【免费下载链接】Mybatis-PageHelper Mybatis通用分页插件 项目地址: https://gitcode.com/gh_mirrors/my/Mybatis-PageHelper 前言&#xff1a;在MyBatis项目中实现分页功能是每个开发者都会遇到的挑战&…...

Gemma-3-12B-IT精彩案例分享:从初学者提问到完整函数实现的全过程

Gemma-3-12B-IT精彩案例分享&#xff1a;从初学者提问到完整函数实现的全过程 1. 引言&#xff1a;为什么这个案例值得一看&#xff1f; 如果你正在寻找一个能真正帮你写代码、解答疑惑的AI助手&#xff0c;那么今天分享的这个案例可能会让你眼前一亮。我们不是要讲空洞的理论…...

编程语言三巨头:汇编、C++与PHP大比拼

好的&#xff0c;我们来分析一下 PHP、C 和汇编语言之间的主要区别。它们处于不同的抽象层次&#xff0c;服务于不同的目的。抽象层级与目的汇编语言&#xff1a; 这是最低级的编程语言之一&#xff0c;几乎是机器指令&#xff08;二进制代码&#xff09;的人类可读形式&#x…...

Codex Computer Use 教 AI 看屏幕,HAR 流教 AI 发指令——谁才是真正的打工替身?

不用看API文档&#xff0c;不用申请密钥。 不需要AI“看屏幕”碰运气——录一段HAR&#xff0c;AI精确搞定一切。 写完往 Openclaw 一丢&#xff0c;你负责吃小龙虾&#xff0c;它负责把消息发到群里。2026年4月&#xff0c;AI界的地震级更新接踵而至。OpenAI 刚刚发布了Codex的…...

【王炸组合】Hermes Agent 官方 UI 发布:本地白嫖 Google Gemma 4,零成本打造最强微信 AI 助手

前言如果说 2025 年是 AI 大模型的爆发年&#xff0c;那么 2026 年 4 月就是“个人 AI 智能体”的普及元年。随着 Gemma 4&#xff08;Google 4月2日刚刚发布&#xff0c;31B 性能直逼 GPT-4o&#xff09;的开源&#xff0c;以及 Hermes Agent 终于告别了繁琐的命令行、发布了正…...

算法实战:巧用连通块思想求解闭合区域面积

1. 连通块算法&#xff1a;从抽象概念到实际问题 第一次接触连通块算法时&#xff0c;我完全被这个抽象的概念搞懵了。直到有一天在玩扫雷游戏&#xff0c;突然意识到&#xff1a;那些被数字包围的空白区域&#xff0c;不就是典型的连通块吗&#xff1f;这个顿悟让我彻底理解了…...

7个实用技巧!AWS Amplify-js前端错误监控最佳实践:实时报警与精准分析

7个实用技巧&#xff01;AWS Amplify-js前端错误监控最佳实践&#xff1a;实时报警与精准分析 【免费下载链接】amplify-js A declarative JavaScript library for application development using cloud services. 项目地址: https://gitcode.com/gh_mirrors/am/amplify-js …...