”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 控制传出速率限制

控制传出速率限制

发布于2024-07-30
浏览:981

让我们想象这样一个场景:有一个与第三方 API 交互的分布式应用程序。通常,第三方 API 具有速率限制控制机制,以避免其客户端突发请求并导致服务停机。在这样的场景下,调用者如何在分布式环境中控制向第三方API发出请求的速率?这篇文章讨论了解决这个问题的可能策略。

有多种算法可以控制请求速率,但这里我们将重点关注令牌桶算法,因为它相对容易理解和实现。该算法规定:一个桶最多可以容纳T令牌,当应用程序想要向第三方API发出请求时,它必须采取1桶中的令牌。如果桶是空的,则必须等到桶中至少有 1 令牌。此外,桶会以 R 令牌/​​毫秒的固定速率重新填充 1 令牌。

令牌桶算法很容易理解,但是如何在分布式环境中使用它来控制对第三方API的传出请求?

如果想要在分布式环境中控制传出速率限制,则需要当前速率限制的集中事实来源。有多种方法可以实现事实来源,我用可能的实现理想化了下图:

Controlling outgoing rate limit

上图中,我们有一个分布在多个pod中的应用程序,每个pod都可以向第三方API发出请求。在应用基础设施中,有一个TCP服务器通过令牌桶算法来控制速率限制。在向第三方 API 发出请求之前,pod 会向 TCP 服务器请求新的令牌,并且 pod 会等待 TCP 服务器的响应,直到至少有一个可用令牌。令牌可用后,Pod 向第三方 API 发出请求。

TCP 服务器实现可以在这个存储库 https://github.com/rafaquelhodev/rlimit/ 中找到,在下一节中我将简要讨论 golang 中的令牌桶实现。

令牌桶实现

下面,我将展示令牌桶实现背后的主要思想。请查看 https://github.com/rafaquelhodev/rlimit/ 存储库以了解详细的实现。

速率限制控制集中在TokenBucket结构体中:

type TokenBucket struct {
    id           string
    mu           sync.Mutex
    tokens       int64
    maxTokens    int64
    refillPeriod int64
    cron         chan bool
    subs         []chan bool
}

您可以注意到TokenBucket结构中有一个subs属性。基本上,这是特定令牌桶的订阅者数组:每次客户端请求令牌时,客户端都会添加到 subs 数组中,并且当新令牌添加到存储桶时会通知客户端。

启动桶时,我们需要提供桶可以支持的最大令牌数(maxTokens)以及令牌添加到桶中的时间量(refillPeriod):

func newTokenBucket(id string, maxTokens int64, refillPeriod int64) *TokenBucket {
    bucket := &TokenBucket{
        id:           id,
        tokens:       0,
        maxTokens:    maxTokens,
        refillPeriod: refillPeriod,
        cron:         make(chan bool),
        subs:         make([]chan bool, 0),
    }
    fmt.Printf("refill period  = %d\n", refillPeriod)
    bucket.startCron()
    return bucket
}

现在,您可能想知道“如何将令牌添加到存储桶?”。为此,当创建存储桶时,会启动一个 cron 作业,并在每个 refillPeriod 毫秒时,将一个新令牌添加到存储桶中:

func (tb *TokenBucket) startCron() {
    ticker := time.NewTicker(time.Duration(tb.refillPeriod) * time.Millisecond)

    go func() {
        for {
            select {
            case  0 {
                        sub := tb.subs[0]
                        tb.subs = tb.subs[1:]
                        sub 



最后,当客户端想要从桶中获取令牌时,必须调用 waitAvailable 函数:

func (tb *TokenBucket) waitAvailable() bool {
    tb.mu.Lock()

    if tb.tokens > 0 {
        fmt.Printf("[CONSUMING TOKEN] - id = %s\n", tb.id)
        tb.tokens -= 1
        tb.mu.Unlock()
        return true
    }

    fmt.Printf("[WAITING TOKEN] - id %s\n", tb.id)

    ch := tb.tokenSubscribe()

    tb.mu.Unlock()

    





灵感来自 https://github.com/Mohamed-khattab/Token-bucket-rate-limiter

版本声明 本文转载于:https://dev.to/rafaquelhodev/controlling-outgoing-rate-limit-3klg?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 为什么不使用CSS`content'属性显示图像?
    为什么不使用CSS`content'属性显示图像?
    在Firefox extemers属性为某些图像很大,&& && && &&华倍华倍[华氏华倍华氏度]很少见,却是某些浏览属性很少,尤其是特定于Firefox的某些浏览器未能在使用内容属性引用时未能显示图像的情况。这可以在提供的CSS类中看到:。googlepic { 内容:url(&#...
    编程 发布于2025-05-05
  • 在JavaScript中如何获取实际渲染的字体,当CSS字体属性未定义时?
    在JavaScript中如何获取实际渲染的字体,当CSS字体属性未定义时?
    Accessing Actual Rendered Font when Undefined in CSSWhen accessing the font properties of an element, the JavaScript object.style.fontFamily and objec...
    编程 发布于2025-05-05
  • 为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    在Microsoft Visual C 中,Microsoft consions用户strate strate strate strate strate strate strate strate strate strate strate strate strate strate strate st...
    编程 发布于2025-05-05
  • Java中如何使用观察者模式实现自定义事件?
    Java中如何使用观察者模式实现自定义事件?
    在Java 中创建自定义事件的自定义事件在许多编程场景中都是无关紧要的,使组件能够基于特定的触发器相互通信。本文旨在解决以下内容:问题语句我们如何在Java中实现自定义事件以促进基于特定事件的对象之间的交互,定义了管理订阅者的类界面。以下代码片段演示了如何使用观察者模式创建自定义事件: args)...
    编程 发布于2025-05-05
  • Java数组中元素位置查找技巧
    Java数组中元素位置查找技巧
    在Java数组中检索元素的位置 利用Java的反射API将数组转换为列表中,允许您使用indexof方法。 (primitives)(链接到Mishax的解决方案) 用于排序阵列的数组此方法此方法返回元素的索引,如果发现了元素的索引,或一个负值,指示应放置元素的插入点。
    编程 发布于2025-05-05
  • 如何在其容器中为DIV创建平滑的左右CSS动画?
    如何在其容器中为DIV创建平滑的左右CSS动画?
    通用CSS动画,用于左右运动 ,我们将探索创建一个通用的CSS动画,以向左和右移动DIV,从而到达其容器的边缘。该动画可以应用于具有绝对定位的任何div,无论其未知长度如何。问题:使用左直接导致瞬时消失 更加流畅的解决方案:混合转换和左 [并实现平稳的,线性的运动,我们介绍了线性的转换。这...
    编程 发布于2025-05-05
  • 在Oracle SQL中如何提取下划线前的子字符串?
    在Oracle SQL中如何提取下划线前的子字符串?
    [ 在oracle sql 解决方案: Explanation:SUBSTR function extracts a substring starting from the specified position (0) and continuing for a specified length.IN...
    编程 发布于2025-05-05
  • Python中何时用"try"而非"if"检测变量值?
    Python中何时用"try"而非"if"检测变量值?
    使用“ try“ vs.” if”来测试python 在python中的变量值,在某些情况下,您可能需要在处理之前检查变量是否具有值。在使用“如果”或“ try”构建体之间决定。“ if” constructs result = function() 如果结果: 对于结果: ...
    编程 发布于2025-05-05
  • 为什么尽管有效代码,为什么在PHP中捕获输入?
    为什么尽管有效代码,为什么在PHP中捕获输入?
    在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,输出...
    编程 发布于2025-05-05
  • 如何使用Depimal.parse()中的指数表示法中的数字?
    如何使用Depimal.parse()中的指数表示法中的数字?
    在尝试使用Decimal.parse(“ 1.2345e-02”中的指数符号表示法表示的字符串时,您可能会遇到错误。这是因为默认解析方法无法识别指数符号。 成功解析这样的字符串,您需要明确指定它代表浮点数。您可以使用numbersTyles.Float样式进行此操作,如下所示:[&& && && ...
    编程 发布于2025-05-05
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-05-05
  • 为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    查询模式实现缺失:解决“无法找到”错误在Silverlight应用程序中,尝试使用LINQ建立LINQ连接以错误而实现的数据库”,无法找到查询模式的实现。”当省略LINQ名称空间或查询类型缺少IEnumerable 实现时,通常会发生此错误。 解决问题来验证该类型的质量是至关重要的。在此特定实例中...
    编程 发布于2025-05-05
  • 如何有效地转换PHP中的时区?
    如何有效地转换PHP中的时区?
    在PHP 利用dateTime对象和functions DateTime对象及其相应的功能别名为时区转换提供方便的方法。例如: //定义用户的时区 date_default_timezone_set('欧洲/伦敦'); //创建DateTime对象 $ dateTime = ne...
    编程 发布于2025-05-05
  • 如何使用Python有效地以相反顺序读取大型文件?
    如何使用Python有效地以相反顺序读取大型文件?
    在python 反向行读取器生成器 == ord('\ n'): 缓冲区=缓冲区[:-1] 剩余_size- = buf_size lines = buffer.split('\ n'....
    编程 发布于2025-05-05
  • C++成员函数指针正确传递方法
    C++成员函数指针正确传递方法
    如何将成员函数置于c 的函数时,接受成员函数指针的函数时,必须同时提供对象的指针,并提供指针和指针到函数。需要具有一定签名的功能指针。要通过成员函数,您需要同时提供对象指针(此)和成员函数指针。这可以通过修改Menubutton :: SetButton()(如下所示:[&& && && &&华)...
    编程 发布于2025-05-05

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3