- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
现在,我正在 AWS 的一个生产区域中测试一个极其简单的信号量。在部署时,延迟从 150 毫秒跃升至 300 毫秒。我假设会发生延迟,但如果它可以被删除那就太好了。这对我来说有点新,所以我正在试验。我已将信号量设置为允许 10000 个连接。这与 Redis 设置的最大连接数相同。下面的代码是最优的吗?如果没有,有人可以帮我优化它,如果我做错了什么等等。我想把它作为一个中间件,这样我就可以简单地在服务器上这样调用它 n.UseHandler(wrappers.DoorMan( wrappers.DefaultHeaders(myRouter), 10000))
.
package wrappers
import "net/http"
// DoorMan limit requests
func DoorMan(h http.Handler, n int) http.Handler {
sema := make(chan struct{}, n)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sema <- struct{}{}
defer func() { <-sema }()
h.ServeHTTP(w, r)
})
}
最佳答案
您概述的解决方案存在一些问题。但首先,让我们退后一步;这里面有两个问题,其中一个暗示:
听起来你想做的其实是第二种,防止太多的请求打到Redis。我将从解决第一个问题开始,然后对第二个问题发表一些评论。
如果您确实想“在门口”对入站连接进行速率限制,您通常永远不要通过在处理程序中等待来做到这一点。使用您提出的解决方案,该服务将继续接受请求,这些请求将在 sema <- struct{}{}
处排队。陈述。如果负载持续存在,它最终会通过用尽套接字、内存或其他一些资源来关闭您的服务。另请注意,如果您的请求率接近信号量的饱和度,您会看到由于 goroutine 在处理请求之前等待信号量而导致的延迟增加。
更好的方法是始终尽可能快地响应(尤其是在负载很重的情况下)。这可以通过发送 503 Service Unavailable
来完成。返回给客户端或智能负载平衡器,告诉它退出。
在你的情况下,它可能看起来像这样:
select {
case sema <- struct{}{}:
defer func() { <-sema }()
h.ServeHTTP(w, r)
default:
http.Error(w, "Overloaded", http.StatusServiceUnavailable)
}
如果速率限制的原因是避免后端服务重载,您通常想要做的是对该服务重载使用react,并通过请求链施加背压。
实际上,这可能意味着将与上述相同类型的信号量逻辑放在一个包装器中,以保护对后端的所有调用,并在信号量溢出时通过请求的调用链返回错误。
此外,如果后端发送类似 503
的状态代码(或等效),您通常应该以相同的方式向下传播该指示,或者诉诸其他一些回退行为来处理传入的请求。
您可能还想考虑将其与 circuit breaker 结合使用, 如果后端服务似乎没有响应或关闭,则停止尝试快速调用后端服务。
如上所述通过限制并发或排队连接的数量来限制速率通常是处理过载的好方法。当后端服务过载时,请求通常会花费更长的时间,这将减少每秒的有效请求数。但是,如果出于某种原因,您希望对每秒的请求数有一个固定的限制,您可以使用 rate.Limiter
来实现。而不是信号量。
在 channel 上发送和接收普通对象的成本应该是亚微秒。即使在高度拥塞的信道上,也不会出现接近 150 毫秒的额外延迟,只是为了与信道同步。因此,假设在处理程序中完成的工作在其他方面是相同的,无论您的延迟增加来自于它几乎肯定与等待某处的 goroutines 相关联(例如,在 I/O 上或访问被其他 goroutines 阻塞的同步区域) .
如果您收到传入请求的速度接近您设置的并发限制 10000 可以处理的速度,或者如果您收到请求高峰,您可能会看到 goroutine 导致的平均延迟增加在 channel 的等待队列中。
无论哪种方式,这都应该很容易衡量;例如,您可以在处理路径的某些点跟踪时间戳。我会在所有请求的样本(例如 0.1%)上执行此操作,以避免日志输出影响性能。
关于go - 有没有更好的方法限制 "door"的请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42957767/
据我所知,根本不为元素呈现 HTML,或添加 display:none,似乎具有完全相同的行为:两者都使元素消失并且不与 HTML 交互。 我正在尝试禁用和隐藏一个复选框。所以HTML的总量很小;我无
我刚刚读了Android Architecture Tutorial: Developing an App with a Background Service (using IPC) .基本上是 让服
我有两个查询具有相同的结果,现在我想知道哪个查询更优化? 在选择中: select t1.*, sum(t2.value) as total_votes from table1 t1 left joi
有人告诉我,对于 I/O 绑定(bind)的应用程序,非阻塞 I/O 会更好。对于 CPU 密集型应用程序,阻塞 I/O 会好得多。我找不到这种说法的原因。试过谷歌,但很少有文章只是触及这个话题而没有
我有一个算法可以在数字列表中寻找好的对。一个好的配对被认为是索引 i 小于 j 且 arr[i] 1: # Finding the mid of the array
我有一个算法可以在数字列表中寻找好的对。一个好的配对被认为是索引 i 小于 j 且 arr[i] 1: # Finding the mid of the array
我从 API 收到一个 json,我需要解析并修改一个属性值。问题是,我收到的 json 数据的嵌套结构不一致,我无法控制它。 这将禁止我指定在特定深度(如 parsedJson.children[0
我有 451 个城市的坐标。现在我想计算每个城市之间的距离,然后根据该距离对一些结果进行排序。现在我有两个选择: 我可以运行一个循环来计算每个可能的城市组合的距离并将它们存储到一个表中,这将产生大约
对于返回相同结果的不同查询,我有两个查询计划我想知道是否有人可以告诉我哪个“更好”,以及为什么。 SELECT * FROM bids order by (select ranking from us
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 7 年前。 Improve this qu
我有一个二维数组。我需要尽可能快地对其执行一些操作(函数每秒将被调用十几次,所以让它变得高效会很好)。 现在,假设我想获取元素 A[i][j],简单地使用 A[i][j] 在速度上有什么不同吗和 *(
在声明或使用字符串的代码中,我通常会看到开发人员这样声明它: string randomString = @"C:\Random\RandomFolder\ThisFile.xml"; 代替: str
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Why don't CSS resets use '*' to cover all elements? 我正
如果我有一个包含许多重复项的 python 列表,并且我想遍历每个项目,而不是重复项,最好使用一个集合(如 set(mylist),或者找到另一种方法来创建没有重复的列表?我想只是循环遍历列表并检查重
在阅读常量接口(interface)反模式时,我发现没有实例的最终常量类比常量接口(interface)更好。 请解释一下怎么做? public interface ConstIfc { publ
我正在查看我继承的一些旧代码,我真的不喜欢某些地方的风格。我真的不喜欢它的外观的一件事是: bool func() { bool ret = true; ret &= test1();
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 4 年前。 Improv
我经常发现自己试图使用 boost/QT 信号解耦对象。实现这一点的简单方法是针对我要通信的每个具体类型,创建一个新的信号和插槽签名并连接所有相关对象。这导致了访问者模式,理想情况下我想发出一个访问者
我正在 https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html 上阅读有关 lambda 的内容 在方法
public List getInts() { List xs = new ArrayList(); xs.add(1); // return Collections.unmo
我是一名优秀的程序员,十分优秀!