Go语言中的速率限流策略全面详解

 更新时间:2023年11月29日 11:43:52   作者:低配全栈  
这篇文章主要为大家介绍了Go语言中的速率限流策略全面详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

前一篇文章中我们提到,为了防止缓存穿透,我们可以在应用里面的缓存层的上一层添加了singleflight。但是,我们也提到,即使使用了singleflight,我们一样还是会存在问题:

使用singleflight本身并不会直接导致OOM的发生,但是需要考虑到极端情况下导致内存使用增加,如果有大量唯一的请求快速连续到来,并且它们的处理时间相对较长,则这些请求可能会在内存中积累,从而增加内存使用.

什么,OpenAI又“雪崩”了?

为了解决这种问题,今天在这里介绍一下GO语言中限流策略(Rating Limit)的使用。

1. 什么是速率限流

在 Go 语言中,Rate Limit(速率限制)是一种控制资源利用率的重要机制,尤其适用于控制对外部资源的访问速率,例如 API 请求或数据库操作。Go 标准库中的golang.org/x/time/rate包提供了实现速率限制的功能。

核心概念

  •  Limiter(限制器): rate.Limiter 结构体是实现速率限制的主要组件。它使用令牌桶算法来控制事件发生的频率。

  • 令牌桶算法: 这是一种通过固定速率向桶中添加令牌来控制资源访问速率的算法。如果桶中有足够的令牌,请求就可以立即处理;如果没有,则请求需要等待或被拒绝。

2. 基本使用

首先看一个具体的例子:

import (
  "context"
  "fmt"
  "log"
  "time"
  "golang.org/x/time/rate"
)
func main() {
  // 创建一个新的限制器,每秒产生5个令牌,最大桶容量为5
  limiter := rate.NewLimiter(5, 5)
  // 模拟连续请求
  for i := 0; i < 10; i++ {
    i := i
    go func() {
      // 等待下一个令牌
      err := limiter.Wait(context.Background())
      if err != nil {
        log.Fatal(err)
      }
      // 令牌已获取,执行API请求
      fmt.Println("Sending API request", i, "at", time.Now().Format(time.RFC3339))
      // 这里可以添加执行实际 API 请求的代码
    }()
  }
  time.Sleep(10 * time.Second)
}

运行结果如下:

我们可以看到,因为rate.Limit的限制,大约每1秒被限制发送5次请求。

细节说明

  • 创建限制器: rate.NewLimiter(5, 5)&nbsp;创建了一个每秒生成 5 个令牌,最大桶容量为 5 的限制器。

  • 循环请求: 通过一个循环来模拟连续的 API 请求。

  • 等待令牌: 使用 limiter.Wait(context.Background()) 在每次请求之前等待令牌。这个调用会阻塞,直到获取到令牌为止。

  • 执行请求: 一旦获取到令牌,就打印一条消息表示发送了一个 API 请求。在实际应用中,这里可以替换为实际的 API 调用代码。

3. 动态调整限速器速率

在 Go 语言中,rate.Limiter 提供了动态调整速率的功能。通过这种方式i允许你在运行时根据需要改变速率限制,这在很多实际应用中非常有用,比如基于当前服务器负载或外部服务的可用性来调整请求速率。

rate.Limiter 提供了 SetLimit 和 SetBurst 两个方法来动态调整限制器的速率和桶大小:

  • SetLimit(rate.Limit): 这个方法用来设置每秒可以生成的令牌数。rate.Limit 是一个基于浮点数的类型,用来表示每秒允许的事件数。

  • SetBurst(int): 这个方法用来设置限制器的桶大小。桶大小决定了在任何给定时间内限制器可以允许的最大事件数。

package main
import (
  "context"
  "fmt"
  "time"
  "golang.org/x/time/rate"
)
func main() {
  // 初始速率为每秒2个请求
  limiter := rate.NewLimiter(2, 2)
  // 模拟动态调整速率
  go func() {
    for {
      time.Sleep(5 * time.Second)
      // 每5秒动态调整速率和桶大小
      newRate := rate.Limit(float64(time.Now().Second()) / 10)
      limiter.SetLimit(newRate)
      limiter.SetBurst(int(newRate))
      fmt.Println("Rate updated to:", newRate)
    }
  }()
  // 模拟请求
  for i := 0; ; i++ {
    err := limiter.Wait(context.Background())
    if err != nil {
      fmt.Println("Error:", err)
      continue
    }
    fmt.Println("Request", i, "at", time.Now().Format(time.RFC3339))
  }
}

通过动态调整 rate.Limiter 的速率和桶大小,你可以灵活地控制应用中的速率限制,使其更加适应变化的环境和需求。上述例子中,每5s会更新速率,每次更新速率之后,请求数量可以实现动态调整:

运行结果:

4. 应用场景

rate.Limiter 在 Go 语言中的应用场景广泛,主要用于控制资源的使用频率,以防止过载、滥用或达到限制。以下是一些常见的应用场景:

1. API 请求限制

当与外部服务(如 REST API)交互时,通常会有每秒或每分钟的请求限制。使用 rate.Limiter 可以确保你的应用不会超过这些限制,从而避免触发服务端的速率限制错误或被暂时禁止访问。

2. 数据库访问控制

在高并发环境下,过多的数据库查询可能会导致性能下降或服务不可用。通过限制数据库操作的频率,可以减轻数据库的负载,提高应用的稳定性和响应速度。

3. 限制用户操作

在某些应用中,可能需要限制用户执行特定操作的频率,例如发送消息、提交表单或请求验证码。这有助于防止滥用和自动化攻击,同时保持系统资源的合理使用。

总结

rate.Limiter 的使用场景体现了其灵活性和实用性。无论是保护外部服务不被过载、控制资源访问、还是提高应用的整体稳定性,它都是一个非常有效的工具。在设计系统时,考虑到这些场景,合理地应用速率限制,可以显著提升系统的健壮性和用户体验。

以上就是Go语言中的速率限流策略全面详解的详细内容,更多关于Go语言速率限流的资料请关注脚本之家其它相关文章!

相关文章

  • Golang中堆排序的实现

    Golang中堆排序的实现

    堆是一棵基于数组实现的特殊的完全二叉树,本文主要介绍了Golang中堆排序的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Golang Mutex错过会后悔的重要知识点分享

    Golang Mutex错过会后悔的重要知识点分享

    互斥锁 Mutex 是并发控制的一个基本手段,是为了避免并发竞争建立的并发控制机制,本文主要为大家整理了一些Mutex的相关知识点,希望对大家有所帮助
    2023-07-07
  • Go channel结构体源码和读写和关闭过程详解

    Go channel结构体源码和读写和关闭过程详解

    这篇文章主要介绍了Go channel结构体源码和读写和关闭过程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • Golang交叉编译之跨平台编译使用详解

    Golang交叉编译之跨平台编译使用详解

    这篇文章主要为大家介绍了Golang交叉编译之跨平台编译使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • 如何go语言比较两个对象是否深度相同

    如何go语言比较两个对象是否深度相同

    这篇文章主要介绍了如何go语言比较两个对象是否深度相同,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • 使用go连接clickhouse方式

    使用go连接clickhouse方式

    这篇文章主要介绍了使用go连接clickhouse方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • 使用go语言实现cors中间件

    使用go语言实现cors中间件

    CORS是一种浏览器安全机制,用于控制在Web应用程序中不同源(Origin)之间的资源共享,本文将给大家介绍如何使用go语言实现cors中间件,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2023-09-09
  • 利用rpm打包上线部署golang代码的方法教程

    利用rpm打包上线部署golang代码的方法教程

    RPM是RPM Package Manager(RPM软件包管理器)的缩写,这篇文章主要给大家介绍了关于利用rpm打包上线部署golang代码的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-01-01
  • go语言入门环境搭建及GoLand安装教程详解

    go语言入门环境搭建及GoLand安装教程详解

    这篇文章主要介绍了go语言入门环境搭建及GoLand安装教程详解,需要的朋友可以参考下
    2020-12-12
  • Go语言中的方法、接口和嵌入类型详解

    Go语言中的方法、接口和嵌入类型详解

    这篇文章主要介绍了Go语言中的方法、接口和嵌入类型详解,本文分别对它们做了详细讲解,需要的朋友可以参考下
    2014-10-10

最新评论