本文是Kevin Goldberg的文章“ Python WSGI服务器的性能分析:第2部分”的译文。
引言
在
WSGI的作者
看来 ,在本系列的
第一部分中 ,您遇到了
WSGI和六种最受欢迎的服务器。 在这一部分中,将向您显示分析这些服务器性能的结果。 为此,创建了一个特殊的测试沙箱。
参赛者
由于时间限制,研究仅限于六台WSGI服务器。 该项目的所有启动说明
都托管在GitHub上 。 也许随着时间的推移,该项目将会扩展,并将介绍其他WSGI服务器的性能分析。 但是现在,我们将讨论六台服务器:
- Bjoern称自己为“超快速WSGI服务器”,并称其为“最快,最小和最轻的WSGI服务器”。 我们创建了一个使用大多数默认库设置的小型应用程序 。
- CherryPy是一个非常流行且稳定的框架和WSGI服务器。 这个小脚本用于通过CherryPy为我们的示例应用程序提供服务。
- Gunicorn的灵感来自Ruby的Unicorn服务器(因此得名)。 他谦虚地声称它“简单实施,易于使用且相当快”。 与Bjoern和CherryPy不同, Gunicorn是独立服务器。 我们使用此命令创建了它。 参数“ WORKER_COUNT”设置为可用处理器核心数量的两倍加一个。 这是根据Gunicorn文档中的建议完成的。
- Meinheld是一种高性能WSGI兼容的Web服务器,该服务器声称是轻量级的。 根据服务器站点上显示的示例,我们创建了应用程序 。
- mod_wsgi由与mod_python相同的创建者创建。 与mod_python一样,它仅适用于Apache。 但是,它确实包含一个名为“ mod_wsgi express”的工具,该工具可以创建最小的Apache实例。 我们使用此命令配置并使用了mod_wsgi express 。 为了匹配Gunicorn ,我们调整了mod_wsgi来创建工人数量是处理器核心的两倍。
- uWSGI是功能齐全的应用程序服务器。 通常, uWSGI与代理服务器配对(例如:Nginx)。 但是,为了更好地评估每个服务器的性能,我们尝试仅使用裸服务器,并为每个可用处理器核心创建了两个工作服务器。
基准测试
为了使测试尽可能客观,创建了一个
Docker容器以将被测试服务器与系统其余部分隔离。 另外,使用Docker容器可确保每次启动都从头开始。
伺服器:
- 隔离在Docker容器中。
- 分配了2个处理器内核。
- 容器的RAM限制为512 MB。
测试:
- 现代HTTP基准测试工具wrk进行了测试。
- 对服务器进行了随机测试,同时连接的数量从100增加到10,000。
- wrk仅限于Docker未使用的两个CPU内核。
- 每次测试持续30秒,并重复4次。
指标:
- 持久性请求,错误和延迟的平均数量由wrk提供。
- 监视内置在Docker中,显示了CPU和RAM的使用水平。
- 丢弃最高和最低读数,并对其余值取平均值。
- 出于好奇,我们将完整脚本发送到GitHub 。
结果
所有初始性能指标
都包含在项目存储库中 ,并且还提供了一个
CSV摘要
文件 。 此外,为了可视化,在
Google文档环境中创建了图形。
RPS与同时连接数
该图显示了并发请求的平均数量; 数字越高越好。


- Bjoern:明显的赢家。
- CherryPy:尽管他是用纯Python编写的,但他还是表现最好的人。
- Meinheld:鉴于容器资源稀缺,因此性能出色。
- mod_wsgi:不是最快的,但是性能是一致且足够的。
- Gunicorn:在较低的负载下表现良好,但存在大量连接问题。
- uWSGI:沮丧,结果不佳。
获奖者:比约恩比约恩
根据不断提出的要求,
Bjoern无疑是赢家。 但是,考虑到这个数字比竞争对手高得多,我们有些怀疑。 我们不确定
Bjoern真的会如此惊人。 最初,我们按字母顺序测试服务器,然后认为
Bjoern获得了不公平的优势。 但是,即使按照随机服务器顺序启动服务器并重新测试之后,结果仍然相同。
uWSGI
我们对
uWSGI的测试结果感到失望。 我们希望他能带头。 在测试期间,我们注意到
uWSGI日志在屏幕上打印,并且最初我们通过服务器所做的额外工作来解释性能不足的问题。 但是,即使添加了“
--disable-logging ”选项之后,
uWSGI仍然是最慢的服务器。
如
uWSGI手册中所述,它通常与代理服务器(例如Nginx)连接。 但是,我们不确定这能否解释这么大的差异。
延误
延迟是请求与其响应之间经过的时间。 数字越小越好。

- CherryPy:很好地处理了负载。
- Bjoern:通常较低的延迟,但在较少的并发连接下效果更好。
- 独角兽:良好且稳定。
- mod_wsgi:即使同时进行大量连接,也具有平均性能。
- Meinheld:总体而言,可接受的性能。
- uWSGI:uWSGI再次排在最后。
获奖者:CherryPyRAM使用
此指标显示内存需求和每个服务器的“亮度”。 数字越小越好。

- Bjoern:非常轻。 它仅使用9 MB的RAM来处理10,000个并发请求。
- Meinheld:与Bjoern相同。
- Gunicorn:熟练地应对高负载,而内存消耗却很少。
- CherryPy:最初需要少量的RAM,但随着负载的增加,其使用量迅速增加。
- mod_wsgi:在较低级别上,它是最密集的内存之一,但仍保持一致。
- uWSGI:显然,我们正在测试的版本在内存消耗方面存在问题。
优胜者:Bjoern和Meinheld错误数
服务器崩溃,被中断或请求超时时,将发生错误。 越低越好。

对于每个服务器,我们计算了请求总数与错误总数之比:
- CherryPy:即使有大量连接,错误率也约为0。
- Bjoern:发生错误,但是已被处理的请求数所抵消。
- mod_wsgi:可以正常工作,可接受的错误率为6%。
- Gunicorn:错误率为9%。
- uWSGI:由于它处理的请求数量很少,因此错误率仅为34%。
- Meinheld:在更高的负载下会下降,在最苛刻的测试中会抛出10,000多个错误。
获奖者:CherryPyCPU使用率
如果服务器运行良好,则高CPU使用率不是好是坏。 但是,这提供了有关服务器的一些有趣信息。 由于使用了两个CPU内核,因此最大可能的使用率为200%。

- Bjoern:单线程服务器,其始终使用100%CPU证明了这一点。
- CherryPy:多线程,但停留在150%。 这可能是由于Python GIL所致。
- Gunicorn:使用多个进程,并在较低级别上充分利用CPU资源。
- Meinheld:使用诸如Bjoern之类的CPU资源的单线程服务器。
- mod_wsgi:多线程服务器,在所有测量中均使用所有CPU内核
- uWSGI:CPU使用率非常低。 CPU消耗不超过50%。 这是uWSGI配置不正确的证据。
WINNER:不,因为这更多地是对行为的观察而不是对性能的比较。结论
总结一下! 您可以从每个服务器的结果中得出一些一般性想法:
- Bjoern:证明自己是“超快速,超轻量级WSGI服务器”。
- CherryPy:高性能,低内存消耗和低错误率。 对于纯Python来说还不错。
- Gunicorn:一个适合中等负载的好服务器。
- Meinheld:效果很好,所需资源最少。 但是,要承受更高的负载。
- mod_wsgi:与Apache集成并且运行良好。
- uWSGI:非常失望。 我们错误地配置了uWSGI ,或者我们安装的版本存在基本错误。