我知道Puma相对于其他Rails Web服务器的好处是它如何处理慢速客户端。当 Puma 服务器接收并下载(可能很慢的)请求时,它仍然可以接收和下载其他请求,这些请求可能会下载得更快,并在慢速请求完成接收之前传递给工作线程进行处理。
但是我找不到任何关于这有什么限制(如果有的话)的信息。
彪马可以同时下载任意数量的请求吗?如果 1000 个慢速请求同时命中它,那么假设它不是一个慢速请求,第 1001 个请求会首先到达 Puma 工人吗?
我想我通常感兴趣的是多个慢速请求对其他请求的影响,包括彼此 - 因为我正在开发一个可能涉及大量"慢速请求"(通过 3G 从手机上传图像)的应用程序。
@nate-berkopec 的这篇精彩文章原则上有助于解释 Puma 如何帮助处理慢速客户端:"在集群模式下,Puma 可以处理慢速请求(这要归功于一个单独的主进程,其职责是下载请求并传递它们)......"任何人能提供更多的光芒都将非常受欢迎。
有许多注意事项,例如 IO 轮询系统、内存和并发问题。
IO 轮询系统
编辑(2020 年 9 月 9 日):到目前为止,Puma 服务器正在nio4r
上运行,不应再受到select
系统调用的限制(其中文件描述符值限制为 1023)。
据我所知,彪马使用select
系统调用(与碘或乘客不同,它们也可以保护您免受慢速客户端的侵害,但使用kqueue
或epoll
)。
select
系统调用在大多数系统上受到限制(通常最多 1024 个客户端/maxfd
个)。我认为这将创建一个限制。
但是,我知道 Puma 正在努力用既便携又有效的东西(例如利用nio4r
gem)取代select
系统调用。
我不知道这是否已经实现,但它会打破这个限制并可能提高性能。
记忆
慢速客户端在缓慢地用其标头数据填充缓冲区或缓慢下载已发送的缓冲数据(将缓冲区保留在内存中直到下载完成)时仍会消耗内存。
内存限制将始终增加客户端处理速度慢的限制。
可以提升一些限制,例如使用X-Sendfile发送静态文件(支持碘,以及当Puma或乘客在nginx下运行时)...但这不是你可以解决的问题。
并发
Puma在Ruby的GIL(全局指令锁)中处理慢速客户端。这意味着当 Puma 处理慢速客户端时,没有其他线程/指令可以执行。
这通常不是问题,但足够多的慢客户端会增加上下文切换和系统调用的成本。这可能会(可能)大大减慢服务器的速度。
乘客和碘都在 GIL 之外执行慢速客户端缓冲,允许这些系统调用真正并发(当多个 CPU 内核可用时)。
这将缓解问题,但不能完全解决问题。
结论和注意事项
最大的问题通常是 IO 轮询系统。对此的解决方案在彪马的路线图上(也许已经实施,我不确定)。
其他问题(内存限制和并发限制)相对不那么重要,但如果不使用语言扩展(碘服务器是用 C 编写的,乘客是用 C++ 编写的),这些问题就无法缓解。
由于Puma(目前)不需要任何语言扩展(除了C和Java中的集成HTTP解析器),这些问题仍然存在。
我应该指出,我是碘HTTP/Websocket服务器的作者,所以我有点偏见。