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 jwt无感刷新与SSO单点登录限制解除方法详解

    GoLang jwt无感刷新与SSO单点登录限制解除方法详解

    这篇文章主要介绍了GoLang jwt无感刷新与SSO单点登录限制解除方法,JWT是一个签名的JSON对象,通常用作Oauth2的Bearer token,JWT包括三个用.分割的部分。本文将利用JWT进行认证和加密,感兴趣的可以了解一下
    2023-03-03
  • 盘点总结2023年Go并发库有哪些变化

    盘点总结2023年Go并发库有哪些变化

    这篇文章主要为大家介绍了2023年Go并发库的变化盘点总结,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • golang设置http response响应头与填坑记录

    golang设置http response响应头与填坑记录

    这篇文章主要给大家介绍了关于golang设置http response响应头与填坑记录的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08
  • 详解Golang time包中的结构体time.Ticker

    详解Golang time包中的结构体time.Ticker

    在日常开发过程中,会频繁遇到对时间进行操作的场景,使用 Golang 中的 time 包可以很方便地实现对时间的相关操作,接下来的几篇文章会详细讲解 time 包,本文讲解一下 time 包中的结构体 time.Ticker,需要的朋友可以参考下
    2023-08-08
  • GoLang channel关闭状态相关操作详解

    GoLang channel关闭状态相关操作详解

    Channel 和 goroutine 的结合是 Go 并发编程的大杀器。而 Channel 的实际应用也经常让人眼前一亮,通过与 select,cancel,timer 等结合,它能实现各种各样的功能。接下来,我们就要介绍GoLang channel关闭状态相关操作
    2022-10-10
  • 一文详解go mod依赖管理详情

    一文详解go mod依赖管理详情

    这篇文章主要介绍了一文详解go mod依赖管理详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-07-07
  • 详解Golang如何实现支持随机删除元素的堆

    详解Golang如何实现支持随机删除元素的堆

    堆是一种非常常用的数据结构,它能够支持在O(1)的时间复杂度获取到最大值(或最小值)。本文主要介绍了如何实现支持O(log(n))随机删除元素的堆,需要的可以参考一下
    2022-09-09
  • Go语言实现二进制与十进制互转的示例代码

    Go语言实现二进制与十进制互转的示例代码

    这篇文章主要和大家详细介绍了Go语言中实现二进制与十进制互相转换的示例代码,文中的代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-05-05
  • golang 如何获取pem格式RSA公私钥长度

    golang 如何获取pem格式RSA公私钥长度

    这篇文章主要介绍了golang 如何获取pem格式RSA公私钥长度操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go排序算法通用qsort函数使用示例

    Go排序算法通用qsort函数使用示例

    这篇文章主要为大家介绍了Go排序算法通用qsort函数使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11

最新评论