go的限流
背景
服务请求下游,oom,排查下来发现是一个下游组件qps陡增导致
但是司内网络框架比较挫,竟然不负责框架内存问题(有内存管理模块,但逻辑又是无限制使用内存)
每个请求一个r、w buffer,请求无限制,内存不够直接就oom,然后就被linux给迁移掉了
所以才有了加限流的必要性(粉饰太平)
所以站在更高维度去考虑这个问题,就变成了一个网络框架是否要去管理内存?
作用
限制请求速率,保护服务,以免服务过载
常用的限流方法
固定窗口、滑动窗口、漏桶、令牌桶
令牌桶:
一个固定大小的桶,系统会以恒定速率向桶中放 Token,桶满则暂时不放
如果桶中有剩余 Token 就可以一直取,如果没有剩余 Token,则需要等到桶中被放置 Token/直接返回失败
本次学习令牌
golang.org/x/time/rate
代码实现
// A Limiter controls how frequently events are allowed to happen.
// Limiter 用来限制发生事件的频率
//
// It implements a "token bucket" of size b, initially full and refilled
// at rate r tokens per second.
// 初始的时候满的,然后以每秒r tokens的速率来填充,bucket大小为b
//
// Informally, in any large enough time interval, the Limiter limits the
// rate to r tokens per second, with a maximum burst size of b events.
//
// As a special case, if r == Inf (the infinite rate), b is ignored.
// See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.
// r还能设置为 Inf?
//
// The zero value is a valid Limiter, but it will reject all events.
// Use NewLimiter to create non-zero Limiters.
// 还能有拒绝全部的零值Limiter?妙啊
//
// Limiter has three main methods, Allow, Reserve, and Wait.
// Most callers should use Wait.
// 三个方法:Allow, Reserve, Wait,每个方法都会消耗一个token
//
// Each of the three methods consumes a single token.
// They differ in their behavior when no token is available.
// If no token is available, Allow returns false.
// Allow:非阻塞
//
// If no token is available, Reserve returns a reservation for a future token
// and the amount of time the caller must wait before using it.
// Reserve 还能预定? 牛哇,还能返回如果一定要使用的话,要等多久
//
// If no token is available, Wait blocks until one can be obtained
// or its associated context.Context is canceled.
// Wait:阻塞
//
// The methods AllowN, ReserveN, and WaitN consume n tokens.
// AllowN、ReserveN、WaitN:消费n个token
type Limiter struct {mu sync.Mutex// 每秒的事件数,即事件速率limit Limit// 单次调用(Allow, Reserve, Wait)中消费token的最大数// 更高的 Burst 的值,将会一次允许更多的事件发生(at once)burst inttokens float64// last is the last time the limiter's tokens field was updated// limiter的tokens字段的前一次被更新的事件last time.Time// lastEvent is the latest time of a rate-limited event (past or future)// 速率受限事件(past or future)的前一次时间lastEvent time.Time
}// A zero Limit allows no events.
type Limit float64
看了结构体就知道如何设计一个很粗糙的限流器了
没有用复杂的结构,就是一个简单的原子计数
使用
// NewLimiter returns a new Limiter that allows events up to rate r and permits
// bursts of at most b tokens.
// 速率r,一次b个突发
func NewLimiter(r Limit, b int) *Limiter {return &Limiter{limit: r,burst: b,}
}
NewLimiter的参数除了用Limit传,还能传间隔
func Every(interval time.Duration) Limit {if interval <= 0 {return Inf}return 1 / Limit(interval.Seconds())
}
Allow、AllowN、Reserve、ReserveN、Wait、WaitN
里面用的都是 reserveN
// Allow reports whether an event may happen now.
func (lim *Limiter) Allow() bool {return lim.AllowN(time.Now(), 1)
}// AllowN reports whether n events may happen at time t.
// Use this method if you intend to drop / skip events that exceed the rate limit.
// Otherwise use Reserve or Wait.
func (lim *Limiter) AllowN(t time.Time, n int) bool {return lim.reserveN(t, n, 0).ok
}// Reserve is shorthand for ReserveN(time.Now(), 1).
func (lim *Limiter) Reserve() *Reservation {return lim.ReserveN(time.Now(), 1)
}// ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.
// The Limiter takes this Reservation into account when allowing future events.
// The returned Reservation’s OK() method returns false if n exceeds the Limiter's burst size.
// Usage example:
//
// r := lim.ReserveN(time.Now(), 1)
// if !r.OK() {
// // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
// return
// }
// time.Sleep(r.Delay())
// Act()
//
// Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.
// If you need to respect a deadline or cancel the delay, use Wait instead.
// To drop or skip events exceeding rate limit, use Allow instead.
func (lim *Limiter) ReserveN(t time.Time, n int) *Reservation {r := lim.reserveN(t, n, InfDuration)return &r
}// Wait is shorthand for WaitN(ctx, 1).
func (lim *Limiter) Wait(ctx context.Context) (err error) {return lim.WaitN(ctx, 1)
}// WaitN blocks until lim permits n events to happen.
// It returns an error if n exceeds the Limiter's burst size, the Context is
// canceled, or the expected wait time exceeds the Context's Deadline.
// The burst limit is ignored if the rate limit is Inf.
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {// The test code calls lim.wait with a fake timer generator.// This is the real timer generator.newTimer := func(d time.Duration) (<-chan time.Time, func() bool, func()) {timer := time.NewTimer(d)return timer.C, timer.Stop, func() {}}return lim.wait(ctx, n, time.Now(), newTimer)
}// wait is the internal implementation of WaitN.
func (lim *Limiter) wait(ctx context.Context, n int, t time.Time, newTimer func(d time.Duration) (<-chan time.Time, func() bool, func())) error {lim.mu.Lock()burst := lim.burstlimit := lim.limitlim.mu.Unlock()// 在限流的情况下,一次请求索要超过 burst 的令牌if n > burst && limit != Inf {return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, burst)}// Check if ctx is already cancelled// 用这种方式检查ctx是否结束select {case <-ctx.Done():return ctx.Err()default:// 这里有 default,所以不会卡住}// Determine wait limitwaitLimit := InfDuration// 它竟然还照顾了ctx的Deadline,牛哇牛哇if deadline, ok := ctx.Deadline(); ok {// t是当前时间,deadline-t就是等待时长waitLimit = deadline.Sub(t)}// Reserver := lim.reserveN(t, n, waitLimit)if !r.ok {return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)}// Wait if necessary// DelayFrom returns the duration for which the reservation holder must wait// before taking the reserved action. Zero duration means act immediately.// InfDuration means the limiter cannot grant the tokens requested in this// Reservation within the maximum wait time.// 0时长意味着立即执行,不用等limiter// InfDuration时长意味着在此次最大的等待时间里,无法授权这么多的tokendelay := r.DelayFrom(t)if delay == 0 {return nil}// newTimer 中创建了一个定时器,这里用完要停止,不然系统中的定时器越来越多// ch:delay定时器// stop:定时器取消函数// advance:仅用于测试,设置钩子,牛哇牛哇ch, stop, advance := newTimer(delay)defer stop()advance() // only has an effect when testing// 等待谁先来select {case <-ch:// We can proceed.return nilcase <-ctx.Done():// Context was canceled before we could proceed. Cancel the// reservation, which may permit other events to proceed sooner.r.Cancel()return ctx.Err()}
}
源码学习
在一个快变现的现状下,lim.reserveN都没有心思学,悲哀
lim.reserveN
问题
它是单实例还是分布式的?
在单个实例中对资源访问或操作进行限速,属于单实例限流
分布式限流通常涉及到跨进程或跨机器的状态共享与同步,通常需要额外的基础设施支持,比如分布式缓存(例如 Redis)或数据库,来保持限流状态的一致性
golang.org/x/time/rate 包并不为这些提供内置支持
如果需要在分布式环境中实现限流,需要考虑使用一个中心化的存储解决方案来同步不同节点之间的限流状态
或者采用其他的分布式限流策略。这可能涉及到一些复杂性
因为需要管理共享状态和处理分布式系统中可能出现的各种问题
例如网络分区、延迟波动、以及同步状态时的竞态条件等
相关文章:
go的限流
背景 服务请求下游,oom,排查下来发现是一个下游组件qps陡增导致 但是司内网络框架比较挫,竟然不负责框架内存问题(有内存管理模块,但逻辑又是无限制使用内存) 每个请求一个r、w buffer,请求无限…...

补充--广义表学习
第一章 逻辑结构 (1)A(),A是一个空表,长度为0,深度为1。 (2)B(d,e),B的元素全是原子,d和e,长度为2,深度为1。 (3)C(b,(c,…...
【笔记】KaiOS SPN显示逻辑
更新流程code 1、gonk/dom/system/gonk/radio/RadioInterfaceLayer.jsm handleNetworkStateChanged -> requestNetworkInfo() -> handleRilResponse的getOperator -> handleOperator handleNetworkStateChanged:网络状态变化请求网络信息 this.requestNetworkInfo…...

Visual Basic6.0零基础教学(4)—编码基础,数据类型与变量
编码基础,数据类型与变量 文章目录 编码基础,数据类型与变量前言一、VB中的编程基础二、VB的基本字符集和词汇集1、字符集2、词汇集 VB中的数据类型VB中的变量与常量一.变量和常量的命名规则二.变量声明1.用Dim语句显式声明变量三. 常量 运算符和表达式一. 运算符 1. 算术运算符…...

VPCFormer:一个基于transformer的多视角指静脉识别模型和一个新基准
文章目录 VPCFormer:一个基于transformer的多视角指静脉识别模型和一个新基准总结摘要介绍相关工作单视角指静脉识别多视角指静脉识别Transformer 数据库基本信息 方法总体结构静脉掩膜生成VPC编码器视角内相关性的提取视角间相关关系提取输出融合IFFN近邻感知模块(NPM) patch嵌…...
Android 图形渲染和显示系统关系
SurfaceFlinger:作为 Android 系统中的一个系统服务,SurfaceFlinger 负责管理整个屏幕的渲染和合成工作。它管理和合成多个 Surface,并与硬件加速器以及 Hardware Composer (HWC) 进行交互,最终将图像数据发送给显示硬件进行显示。…...
3.C++:类与对象(下)
一、再谈构造函数 1.1构造函数体赋值 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;}private:int _year;int _month;i…...

iOS开发之SwiftUI
iOS开发之SwiftUI 在iOS开发中SwiftUI与Objective-C和Swift不同,它采用了声明式语法,相对而言SwiftUI声明式语法简化了界面开发过程,减少了代码量。 由于SwiftUI是Apple推出的界面开发框架,从iOS13开始引入,Apple使用…...

2024-简单点-pandas
pandas pandas to numpy 尽量不用.values提取数据 numexpr 和 bottleneck加速 布尔操作 describe 自定义describe .pipe df.apply 行或者列级别函数级别应用...

面试笔记——Redis(双写一致、持久化)
双写一致 双写一致性: 当修改了数据库中的数据,也要更新缓存的数据,使缓存和数据库中的数据保持一致。 相关问题:使用Redis作为缓存,mysql的数据如何与Redis进行同步?——双写一致性问题 回答时࿰…...

【漏洞复现】科立讯通信指挥调度平台editemedia.php sql注入漏洞
漏洞描述 在20240318之前的福建科立讯通信指挥调度平台中发现了一个漏洞。该漏洞被归类为关键级别,影响文件/api/client/editemedia.php的未知部分。通过操纵参数number/enterprise_uuid可导致SQL注入。攻击可能会远程发起。 免责声明 技术文章仅供参考,任何个人和组织使…...

css的active事件在手机端不生效的解决方法
需求:需求就是实现点击图中的 “抽奖” 按钮,实现一个按钮Q弹的放大缩小动画 上面是实现的效果,pc端,点击触发 :active 问题:但是这种方式在模拟器上可以,真机H5一调试就没生效了,下面是简单…...

00. 认识 Java 语言与安装教程
认识 Java Java 在 20 多年发展过程中,与时俱进,为了适应时代的需要,经历过两次重大的版本升级,一个是 Java 5,它提供了泛型等重要的功能。另一个是提供了 Lambda 表达式等重要的功能的 Java 8。 一些重要的 Java 的…...
数据结构-栈-004
1链栈 1.1栈结点结构体定义 /*定义一个数据结构*/ typedef struct student {char name[32];char sex;int age; }DATA_TYPE;/*定义一个栈结点*/ typedef struct stack_node {DATA_TYPE data;//数据域struct stack_node *pnext;//指针域 }STACK_NODE;1.2栈顶结点结构体定义 /*…...
(第76天)XTTS 升级:11GR2 到 19C
参考文档: 11G - Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 1389592.1)V4 使用跨平台增量备份减少可传输表空间的停机时间 (Doc ID 2940565.1)前言 XTTS(Cross Platform Transportable Tablespaces,跨平台迁移表空间)是…...

修改网站源码,给电子商城的商品添加图片时商品id为0的原因
修改网站源码,给电子商城的商品添加图片时商品id为0的原因。花了几个小时查找原因。后来,由于PictureControl.class.php是复制CourseControl.class.php而来,于是对比了这两个文件,在CourseControl.class.php找到了不一样的关键几条…...
ffmpeg开发异步AI推理Filter
ffmpeg开发异步AI推理Filter 1.环境搭建、推理服务及客户端SDK2.编译原版ffmpeg3.测试原版ffmpeg的filter功能4.准备异步推理filter5.修改点6.重新编译ffmpeg7.测试异步推理filter本文旨在阐述如何开发一个FFmpeg Filter,该模块利用gRPC异步通信机制调用远程视频处理服务。这一…...
python与excel第七节 拆分工作簿
一个工作簿中多个工作表拆分为多个工作簿 假设一个excle工作簿中有多个工作表,现在需要将每个工作表拆分为单独的工作簿。 例子: import xlwings as xw# 设置生成文件的路径path D:\\TEST\\dataIn# 源文件的路径workbook_name D:\\TEST\\dataIn\\产…...

JS08-DOM节点完整版
DOM节点 查找节点 父节点 <div class="father"><div class="son">儿子</div></div><script>let son = document.querySelector(.son)console.log(son.parentNode);son.parentNode.style.display = none</script>通过…...

【python】python3基础
文章目录 一、安装pycharm 二、输入输出输出 print()文件输出:格式化输出: 输入input注释 三、编码规范四、变量保留字变量 五、数据类型数字类型整数浮点数复数 字符串类型布尔类型序列结构序列属性列表list ,有序多维列表列表推导式 元组tu…...
qt使用笔记二:main.cpp详解
Qt中main.cpp文件详解 main.cpp是Qt应用程序的入口文件,包含程序的启动逻辑。下面我将详细解析其结构和功能。 基本结构 一个典型的Qt main.cpp 文件结构如下: #include <QApplication> // 或者 QGuiApplication/QCoreApplication #include &…...
随访系统安装的记录
安装PG17.5 安装https://www.cnblogs.com/nulixuexipython/p/18040243 1、遇到navicat链接不了PG https://blog.csdn.net/sarsscofy/article/details/84985933 2、查看有无安装mysqlhttps://blog.51cto.com/u_16175430/7261412 3、 方案一:oracle不开日志 data…...
MySQL 迁移至 Docker ,删除本地 mysql
macOS 的删除有大量的配置文件和相关数据文件要删除,如果 update mysql 那么数据更杂。 停止 MYSQL 使用 brew 安装,则 brew services stop mysql 停止 mysql 。 如果没有使用 brew 安装,则 sudo /usr/local/mysql/support-files/mysq…...

Docker容器部署elasticsearch8.*与Kibana8.*版本使用filebeat采集日志
第 1 步:使用 Docker Compose 部署 Elasticsearch 和 Kibana 首先,我们需要创建一个 docker-compose.yml 文件来定义和运行 Elasticsearch 和 Kibana 服务。这种方式可以轻松管理两个容器的配置和网络。 创建 docker-compose.yml 文件 在一个新的文件夹…...
将HTML内容转换为Canvas图像,主流方法有效防止文本复制
HTML to Canvas 使用说明 项目概述 此项目实现了将HTML内容转换为Canvas图像的功能,可有效防止文本被复制。适用于需要保护内容的场景,如试题系统、付费内容等。 主要功能 防止复制: 将文本内容转换为Canvas图像,使用户无法选择和复制Mat…...
测试(面经 八股)
目录 前言 一,软件测试(定义) 1,定义 2,目的 3,价值 4,实践 二,软件测试(目的) 1,找 bug 2,验证达标 3,质量评价…...
使用 Unstructured 开源库快速入门指南
引言 本文将介绍如何使用 Unstructured 开源库(GitHub,PyPI)和 Python,在本地开发环境中将 PDF 文件拆分为标准的 Unstructured 文档元素和元数据。这些元素和元数据可用于 RAG(检索增强生成)应用、AI 代理…...
ps蒙版介绍
一、蒙版的类型 Photoshop中有多种蒙版类型,每种适用于不同的场景: 图层蒙版(Layer Mask) 作用:控制图层的可见性,黑色隐藏、白色显示、灰色半透明。特点:可随时编辑,适合精细调整。…...
预训练语言模型T5-11B的简要介绍
文章目录 模型基本信息架构特点性能表现应用场景 T5-11B 是谷歌提出的一种基于 Transformer 架构的预训练语言模型,属于 T5(Text-To-Text Transfer Transformer)模型系列,来自论文 Colin Raffel, Noam Shazeer, Adam Roberts, Kat…...

Java应用10(客户端与服务器通信)
Java客户端与服务器通信 Java提供了多种方式来实现客户端与服务器之间的通信,下面我将介绍几种常见的方法: 1. 基于Socket的基本通信 服务器端代码 import java.io.*; import java.net.*;public class SimpleServer {public static void main(String…...