为什么Unicorn需要与Nginx一起部署?

145

我希望了解Nginx和Unicorn之间的区别。据我所知,Nginx是一个Web服务器,而Unicorn是一个Ruby HTTP服务器。

既然Nginx和Unicorn都可以处理HTTP请求,为什么需要在RoR应用程序中使用Nginx和Unicorn的组合呢?


4
好问题!我觉得这个问题的标题应该是“为什么我们需要使用nginx和unicorn结合使用”。答案对我很有帮助。 - servatj
1
@servatj 我添加了一个回答,更详细地解释了为什么Unicorn需要像Nginx这样的反向代理在它前面。你可能想要看一下 ;) - Agis
4个回答

96

Nginx是一个纯粹的Web服务器,用于提供静态内容和/或将请求重定向到另一个套接字以处理请求。

Unicorn是一个Rack Web服务器,仅用于托管'Rack App',通常生成动态内容。Rack应用程序也可以提供静态内容,但不如大多数其他传统Web服务器高效。

大多数RoR设置使用传统Web服务器和Rack服务器的组合来应用它们的最佳功能。 Nginx通过代理平衡和提供静态内容非常快速地进行请求重定向。 Unicorn能够很好地处理HTTP头并平衡传入请求以供Ruby处理。


90

这个答案是对其他答案的补充,解释了为什么Unicorn需要在其前面部署nginx。

简言之,Unicorn通常与反向代理(如nginx)一起部署的原因是因为它的创建者有意设计成这样,以简单为代价进行折衷。

首先,没有什么阻止你在不使用反向代理的情况下部署Unicorn。但是,这不是一个很好的主意;让我们看看为什么。

Unicorn遵循Unix哲学,即“专注于做一件事且做到极致”,即提供快速、低延迟的客户端服务(我们稍后会看到这意味着什么)。Unicorn被设计用于快速、低延迟的客户端服务,也意味着它在处理慢速、高延迟的客户端方面并不擅长,这一点确实正确。这是Unicorn的弱点之一,反向代理就是应对这些慢客户端的手段(我们稍后会看到如何)。

幸运的是,这样的反向代理已经存在,叫做nginx

只处理快速客户端这一决策极大地简化了Unicorn的设计,使代码库更简单、更小,代价是在部署时增加一些复杂性(即需要额外部署nginx以外的Unicorn)。

另一个选择是以这样的方式设计Unicorn,以使其不需要反向代理。然而,这意味着它必须实现额外的功能来完成现在nginx所做的所有事情,从而导致更复杂的代码库和更多的工程努力。

相反,其创建者决定利用现有的经过实战测试且设计非常良好的软件,并避免浪费时间和精力在已经被其他软件解决的问题上。

但让我们变得技术化并回答你的问题:

为什么Unicorn需要与nginx一起部署?

以下是一些关键原因:

Unicorn使用阻塞式I/O处理客户端

依靠反向代理意味着Unicorn不必使用非阻塞式I/O。相反,它可以使用阻塞式I/O,这在程序员看来本质上更简单且易于跟踪。

此外,正如设计文档所述:

[使用阻塞式I/O] 允许在Ruby解释器内遵循更简单的代码路径,并减少系统调用。

然而,这也有一些后果:

核心要点1:Unicorn对于慢速客户端效率低下

(为了简化起见,我们假设设置了1个Unicorn工作进程)

由于使用了阻塞式I/O,一个Unicorn工作进程一次只能服务于一个客户端,因此一个慢速客户端(即连接缓慢的客户端)会使该工作进程忙碌更长时间(比快速客户端多花费的时间)。同时,其他客户端将等待,直到该工作进程再次空闲(即请求会排队等待)。

为了解决这个问题,在Unicorn前部署了一个反向代理,它会完全缓冲传入请求以及应用响应,然后分别将它们一次性地发送(也就是逐个提供)给Unicorn和客户端。在这方面,可以说反向代理"保护"Unicorn免受网络缓慢的影响。

幸运的是,Nginx是这种角色的绝佳候选人,因为它设计用于高效地处理数千个并发客户端。

重要的是,反向代理应该与Unicorn在同一个本地网络中(通常是在同一个物理机器上通过Unix域套接字与Unicorn通信),以便将网络延迟降至最低。

因此,这样的代理实际上扮演着 Unicorn 最初设计要服务的 快速客户端 的角色,因为它将请求代理到 Unicorn 上 快速 并且尽可能地使工作进程保持繁忙状态,以确保相对于使用缓慢连接的客户端所需时间而言,最短的时间内完成请求。

关键点2: Unicorn 不支持 HTTP/1.1 keep-alive 特性

由于 Unicorn 使用阻塞 I/O,这也意味着它无法支持 HTTP/1.1 keep-alive 特性,因为缓慢客户端的持久连接将很快占用所有可用的 Unicorn 工作进程。

因此,为了利用 HTTP keep-alive,猜猜看:需要使用反向代理。

另一方面,nginx 可以使用仅使用少量线程处理数千个并发连接。因此,它没有像 Unicorn 这样的服务器那样具有并发限制(本质上是限制 worker 进程的数量),这意味着它可以很好地处理持久连接。更多关于它如何实现的信息可以在这里找到。

这就是为什么 nginx 接受来自客户端的 keep-alive 连接并通过通常的 Unix 套接字以普通连接的方式代理它们到 Unicorn 上的原因。

关键点3: Unicorn 不太擅长提供静态文件服务

同样,提供静态文件服务是 Unicorn 能够 完成的任务,但不是设计为高效完成的。

反向代理如nginx则更擅长此类任务(如sendfile(2)和缓存)。

更多信息

PHILOSOPHY文档中还有其他要点(见“通过反向代理提高性能”)。

另请参阅 nginx 的基本特性

通过利用现有软件(即 nginx)并遵循“做一件事情并把它做好”的 Unix 哲学,Unicorn 能够在维持为 Rack 应用程序提供高效服务的同时,遵循更简单的设计和实现。

要了解更多信息,请参考 Unicorn 的哲学设计文档,这些文档详细说明了 Unicorn 设计背后的选择以及为什么认为 nginx 是 Unicorn 的好反向代理。


但是为什么不直接使用Nginx呢?我想他问的不是“为什么unicorn需要nginx”,而是Unicorn提供了什么Nginx没有的功能呢? - omikes
4
如果是这样的话,我相信其他答案已经很好地回答了这个问题。我仍然认为我的答案对于任何试图理解Nginx和Unicorn组合的人提供了有用的信息。 - Agis
3
这真是一份宝藏,谢谢你! - Magne

60

1
Pratik,我的问题是Unicorn服务器可以同时提供静态和动态进程,那么为什么我们要使用只能处理静态内容的NGinx或Apache,再结合Passenger、Unicorn或mod_php呢? - loganathan
17
@loganathan,Apache和Nginx在提供静态内容方面比Ruby或任何应用服务器更快。它们也知道如何处理缓存,并且擅长允许同时下载文件,同时仍然接收流量并将其传递给应用服务器。 - Pratik
4
如果有大量的数据进出,nginx将会缓冲并逐步传递给客户端。如果没有nginx,其中一个进程将会被上传和下载占用。 - BraveNewCurrency
12
这并没有回答为什么需要使用nginx这个问题。它只是把它放在两张图片中而没有做任何评论。Nick的回答更好。 - gorn
1
我同意@gorn的观点。例如,这对我来说毫无意义。 - Joshua Grosso Reinstate CMs
显示剩余5条评论

14

Nginx可以用来为unicorn服务器提供服务,因为慢速客户端会使unicorn服务器崩溃。Nginx被用作一种代理,缓冲所有请求和响应以适应慢速客户端。

参见http://unicorn.bogomips.org/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接