【发布时间】:2019-11-11 15:23:30
【问题描述】:
我有一个微服务架构应用程序,其中包含多个轮询外部 API 的服务。外部 API 的速率限制器为每分钟 600 个请求。如何让我的所有实例一起保持在共享的 600 速率限制以下?
Google 只给我带来了 3 个解决方案,最有希望的是:
- myntra/golimit 三者中最有前途的,但我真的不知道如何设置它。
-
wallstreetcn/rate 似乎只有在达到限制时才会拒绝(我的应用程序需要等到它可以发出请求)并且
rate.NewLimiterfunc 中的Every函数似乎是一个不同的导入/依赖项,我无法想象它是什么 - manavo/go-rate-limiter 有一个“软”限制,显然,它可以让我超过限制。有些端点我不介意几秒钟内无法访问它们,但其他端点请求应该尽可能地工作。
目前我有一个业余的解决方案。下面的代码允许我设置每分钟的限制,它会在请求之间休眠以将请求分散到一分钟内。此客户端速率限制是针对每个实例的,因此我必须硬编码将 600 个请求除以实例数量。
var semaphore = make(chan struct{}, 5)
var rate = make(chan struct{}, 10)
func init(){
// leaky bucket
go func() {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for range ticker.C {
_, ok := <-rate
// if this isn't going to run indefinitely, signal
// this to return by closing the rate channel.
if !ok {
return
}
}
}()
在发出 http API 请求的函数内部。
rate <- struct{}{}
// check the concurrency semaphore
semaphore <- struct{}{}
defer func() {
<-semaphore
}()
如何让我的所有实例一起保持在共享的 600 速率限制以下?
偏好: - 基于一个键的速率限制计数器,因此可以设置多个计数器。 - 将请求分散到设置的持续时间,这样 600 个请求不会在前 30 秒内发送,而是在整分钟持续时间内发送。
【问题讨论】:
-
超过 600 会发生什么?大概您会收到 429 响应或类似的响应?如果您只是以合理的方式处理 429 会怎样?
-
我们正在使用此处提供的漏桶速率限制器:github.com/jwells131313/danaides。我不确定它是否符合您的用例,但在我们的团队中,我们发现它非常适合流式传输用例(我们限制了 websocket 的速率)。不确定它在您的用例中是否会一样好。免责声明:我编写了该库,但 Oracle 云中的生产软件正在使用它
-
@Flimzy 我可能会发现错误,但有些服务更重要,并且与用户请求相关联,不能让用户等到限制最终重置。
-
@jwells131313 听起来不错。你能给我更多的细节吗?你 github 上的代码似乎只是客户端,看不到它如何与其他正在运行的实例共享速率限制。
-
但是您已经要求您的用户等到计时器重置。限制自己的速率和重试 429 之间的唯一逻辑区别是网络请求的数量。当然,这可能很重要,但如果您希望通常低于限制,则处理 429 可能会容易得多。
标签: go distributed rate-limiting