Go 分布式出站http速率限制器
我有一个微服务体系结构应用程序,它有多个服务轮询一个外部API。外部API的速率限制为每分钟600个请求。我如何使我的所有实例都低于共享的600费率限制 谷歌只为我带来了3种解决方案,其中最有希望的是:Go 分布式出站http速率限制器,go,distributed,rate-limiting,Go,Distributed,Rate Limiting,我有一个微服务体系结构应用程序,它有多个服务轮询一个外部API。外部API的速率限制为每分钟600个请求。我如何使我的所有实例都低于共享的600费率限制 谷歌只为我带来了3种解决方案,其中最有希望的是: 这是三个中最有希望的一个,但我确实不知道如何设置它 它似乎只有在达到限制时才会拒绝(我的应用程序需要等待,直到它能够发出请求),并且速率中的每个函数。NewLimiter函数似乎是一个不同的导入/依赖项,我无法确定它是哪一个 有一个“软”的极限,很明显,可以让我超过这个极限。有些端点我并不介意
- 这是三个中最有希望的一个,但我确实不知道如何设置它
- 它似乎只有在达到限制时才会拒绝(我的应用程序需要等待,直到它能够发出请求),并且
速率中的
每个
函数似乎是一个不同的导入/依赖项,我无法确定它是哪一个函数。NewLimiter
- 有一个“软”的极限,很明显,可以让我超过这个极限。有些端点我并不介意我在几秒钟内无法访问它们,但是其他端点请求应该尽可能多地工作
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
}
}
}()
var信号量=make(chan结构{},5)
var rate=make(chan结构{},10)
func init(){
//漏桶
go func(){
股票代码:=时间.NewTicker(100*时间.毫秒)
延迟停止
适用于range ticker.C{
_,确定:=如果您想要一个全局速率限制器,您需要一个地方来维护分布式状态,例如zookeeper。通常,我们不想支付开销。或者,您可以设置一个转发代理(),在其中执行速率限制。我无法与您找到的库联系,但速率限制非常简单。您需要某种共享事务存储。每个存储桶(或速率限制)然后是一个简单的整数和一个时间值。整数是特定时间内存储桶中的滴数。每次必须应用速率限制时,减去自上次更新以来泄漏的滴数,然后添加一个,然后检查滴数是否在存储桶的容量内
我们正在使用Redis进行此类操作。要在Redis中实现此事务性,需要一个脚本(请参阅和)。例如,在SQL数据库中,一个SELECT for UPDATE
后跟一个UPDATE
语句将实现相同的功能。这是我们的Redis脚本:
——replicate\u命令允许我们使用TIME命令。我们依赖于精确的
--(且合理一致)时间戳。多个客户端可能具有
--不可接受的时钟漂移。
redis.replicate_命令()
本地速率=tonumber(ARGV[1])——每秒泄漏多少滴
本地上限=桶数(ARGV[2])——桶中可容纳多少滴
现在本地,uz=unpack(redis.call('TIME'))
--一个bucket由一个带有两个键的散列表示,n和t。n是
--在时间t(自纪元起的秒数)时落在铲斗中。
本地xs=redis.call('HMGET',键[1],'n','t')
本地n=tonumber(xs[1])
本地t=tonumber(xs[2])
如果类型(n)~=“数字”或类型(t)~=“数字”,则
--桶还不存在(n和t为假),或者有人搞错了
--我们的散列值。无论哪种方式,都假设桶是空的。
n、 现在t=0
结束
--清除从t开始泄漏的液滴
n=n-(现在-t)*费率
如果n<0,则
n=0
结束
--如果合适,加一滴
如果n
每秒10滴的呼叫示例,容量为10滴:
EVALSHA <SHA_IN_HEX> 1 rate-limit:my-bucket 10 10
EVALSHA 1费率限制:我的桶10
脚本返回存储桶中的丢弃数。如果该数字等于容量,则您可以短时间睡眠并重试,也可以根据需要完全拒绝请求
请注意,脚本从不返回大于容量的值,因此在您的情况下,恢复时间不超过十分之一秒。这可能不是您所需要的,因为您正在尝试匹配第三方速率限制器。也就是说,您可能可以让存储桶溢出,从而在突发请求后获得更长的恢复时间.如果超过600,会发生什么?大概你会得到429响应或类似的响应?如果你只是以合理的方式处理429呢?我们使用的是一个漏桶速率限制器。我不确定它是否符合你的用例,但在我们的团队中,我们发现它非常适合流式用例(我们在websocket上限制速率)。不确定它在您的使用案例中是否会同样好。免责声明:我编写了该库,但Oracle的生产软件正在使用它cloud@Flimzy我可能会发现错误,但有些服务更为关键,并且与用户请求有关,不能让用户等到限制最终重置。@jwells131313听起来不错。你能给我一些提示吗有关详细信息?github上的代码似乎只是客户端代码,不知道它如何与其他正在运行的实例共享速率限制。但您已经要求用户等待计时器重置。自己限制速率与在429上重试之间唯一的逻辑区别是网络请求的数量。当然,这一点很重要,但是,如果您希望通常处于限制之下,处理429可能会容易得多。使用带速率限制器的前向代理正是我想要的。在我的解决方案中,我现在使用基于Goproxy的Cuttle。
EVALSHA <SHA_IN_HEX> 1 rate-limit:my-bucket 10 10