go 建议:x/时间/速率:添加滑动窗口、固定窗口和泄漏桶速率限制器

jgwigjjp  于 4个月前  发布在  Go
关注(0)|答案(2)|浏览(58)

您的功能请求是否与问题相关?请描述。

当与实现速率限制器的外部API进行交互时,重要的是有一个匹配的速率限制器,以便请求不会无意中触发该速率限制。

描述您希望实现的解决方案

实现以下速率限制算法之一:

  • 滑动窗口
  • 固定窗口
  • 漏桶
  • (其他?)
    描述您考虑过的替代方案

这些算法中的一些存在于外部仓库中

但理想情况下,这些算法应该有一个共同的接口和位置。

附加上下文

我在 #43003 中请求创建一个共同的接口,但我本末倒置了。
与任何请求一样,初始目标是确定哪些(如果有的话)值得实现,以及以何种形式实现。

bprjcwpo

bprjcwpo1#

在限流器中,可能需要或不需要很多不同的功能。功能伴随着权衡,如依赖关系或内存使用等。x/time/rate 限流器并非万能良药。人们可能想要的功能有:

  • 公平性(或任意排队行为)
  • 指标集成
  • 不同的突发行为(获取错误或截断到突发大小可能会非常痛苦,"债务"概念可能是好的)

我认为,如果:
(A) 它提出了统一的接口。
(B) 解释了为什么这个接口应该集中而不是仅仅是另一个库。
那么这个提案将会更有分量。
我建议你从(A)开始。

cdmah0mi

cdmah0mi2#

作为我为43003做的x/time/rate审查的一部分,我移动了几个东西来了解它,并创建了一个可以作为起点的接口。回顾一下,我相信我最初的建议是好的,但可以更好。我也看到一些总体上可以改进的东西,但会走向相反的方向规范。
因此,我有两个选择作为起点。第一个

type Limiter interface {
	AllowN(now time.Time, n int) bool
	ReserveN(now time.Time, n int) Reservation
	WaitN(ctx context.Context, n int) error
}

type Reservation interface {
	CancelAt(now time.Time)
	DelayFrom(now time.Time) time.Duration
	OK() bool
}

实际上是当前实现的精简版本,真正的区别在于它从我的原始混乱中删除了什么,即它删除了助手。第二个是对Reservation工作方式的更激进的改变,但我认为这清理了接口。我建议这只是因为它是一个x包,而创建一个Limiter接口将是一个向后不兼容的更改,无论如何都需要将当前的Limiter重命名为TokenBucketLimiter

type Limiter interface {
	Allow(time.Time, int) bool
	Reserve(time.Time, int) Reservation
}

type Reservation interface {
	Cancel(context.Context)
	Ready() <-chan bool
	ExpectedDelay(time.Time) time.Duration
	Delay(time.Time) time.Duration
	OK() bool
}

Allow 可以认为是多余的,但我相信能够在安全的方式内检查限制器内部的能力超过了接口复杂性的增加。
从小到大,其他更改如下

  • 大多数方法的名称从它们的N形式缩短,以提高接口的可读性。
  • Canceltime.Time 更改为 context.Context ,以允许更广泛的能力取消预订。
  • 创建 Ready ,它返回一个在预订准备好时输出true的通道(如果被取消/更改,可能会输出false)。
  • 这允许在不用担心外部定时器如何受到影响的情况下更新预订。
  • ExpectedDelay 返回假设没有取消的情况下,预订将在何时准备好的时间。
  • Delay 返回相同的时间,但是它锁定预订在其当前时间。

相关问题