你应该使用 Nginx + UWSGI 已翻译 100%

renwofei423 投递于 2013/07/05 08:53 (共 7 段, 翻译完成于 07-09)
阅读 19106
收藏 133
5
加载中

经过大量的实验(在 disqus.comgetsentry.com上),我可以确切的说:uwsgi应该成为Python世界的标准。 把它和nginx结合,在基于 Python的Web应用程序上你能获得在线程(或非线程)之上更好的性能体验。

更新:忽略古老的说法“你给任何度量是慢”,我在这里说的请求是指后端节点,他们处理输入事件(从20KB到1MB大小的请求),在网络跳过数跳经过各种授权和配额策略,并最形成一些队列操作。卸载尽可能多的工作负载。(本段翻译有问题,请参考原文,译者注)

Garfielt
Garfielt
翻译于 2013/07/08 18:43
2

服务策略

目前已经有相当数量的方法可以用来运行Python应用程序。我不打算使用mod_wsgi,最重要的,我并不想说明事件模型如何工作。我不相信在Python的世界它们依旧使用,所以这篇文章的主题也不是关于传统的线程(或多进程)的Python应用程序。

相反,我将专注于两个最流行且我最熟悉的解决方案:gunicorn和uwsgi。

Garfielt
Garfielt
翻译于 2013/07/08 17:00
2

Gunicorn(Python UNIX平台的wsgi服务器)

回顾过去,Python的Web服务器的解决方案基本上只有mod_wsgi。其中最流行的(或理解为时尚)的方法是最近Gunicorn。

实际上,我仍然建议使用gunicorn,这样可以极大的减少不便:它可以漂亮的嵌入Django而且设置简单。

它也有10%的配置选项和uwsgi一致(这对某些人来说是件好事),除此之外,比较看来,它提供了与uwsgi(或任何其他Python Web服务器)几乎相同的基本特性。

Garfielt
Garfielt
翻译于 2013/07/08 17:15
3

uwsgi

在我看来这是唯一的选择,从Gunicorn到uwsgi。将有更高性能的,有更多极易明白的配置选项,通过协议可以与nginx交互也增加了优势。
它的配置也是相当简单,找到一篇文章相关文章就可以了,后来更多。
我开始使用uwsgi来跑一些应用,使用–processes=10和–threads=10来测试服务器的多CPU,目的有两个:

  • 支持情况
  • 测试降低内存使用量的可能性
  • 测试线程安全的支持情况
(对于这些测试是否值得,DISQUS是 单线程运行的,我想保持尽可能的精简,把每个节点的能力发挥到极致)
Garfielt
Garfielt
翻译于 2013/07/08 17:27
2

不断趋向成功的迭代

我们使API平均响应时间降到40ms以内,我非常自豪。这里我说的API相应时间是指:从请求击中了Python服务器到服务器返回响应到代理所花费的时间。

不幸的是,当我们始获得越来越大的流量并出现访问尖峰后响应时间出现问题了,波动的响应时间不再符合我们开始的设想,尽管服务节点上我们仍然有大约30%的内存和60%的资源空余。

在不少调整后,我们停用了大量uwsgi进程的方法,让nginx的负载均衡它们(之前是让uwsgi本身负载平衡)。

这意味着什么呢,是不是做uwsgi过程= 10,我们运行10个单独的uwsgi实例代替–processes=10

其结果是一个美丽的,一致的20ms的平均响应时间。

API Times

API响应时间

Garfielt
Garfielt
翻译于 2013/07/08 18:18
2

将他们组合在一起

我喜欢着手去做而非空谈,这里我给大家一些我们在线服务器的实际设置

nginx

配置的第一块是Nginx的,我们需要实际计算并添加uwsgi的进程 后端数量,所以事情有点复杂。

我们首先建立在我们的网页配置列表:

# recipes/web.rb

hosts = (0..(node[:getsentry][:web][:processes] - 1)).to_a.map do |x|
  port = 9000 + x
  "127.0.0.1:#{port}"
end

template "#{node['nginx']['dir']}/sites-available/getsentry.com" do
  source "nginx/getsentry.erb"
  owner "root"
  group "root"
  variables(
    :hosts => hosts
  )
  mode 0644
  notifies :reload, "service[nginx]"
end
Nginx的配置很简单:
# templates/getsentry.erb

upstream internal {
<% @hosts.each do |host| %>
  server <%= host %>;
<% end %>
}

server {
  location / {
    uwsgi_pass         internal;

    uwsgi_param   Host                 $host;
    uwsgi_param   X-Real-IP            $remote_addr;
    uwsgi_param   X-Forwarded-For      $proxy_add_x_forwarded_for;
    uwsgi_param   X-Forwarded-Proto    $http_x_forwarded_proto;

    include uwsgi_params;
  }
}

现在,我们已经设置了uwsgi的主机数量并分配了权重值,从9000端口开始,它们都是被uwsgi配置使用的套接字地址。

uwsgi

另一方面,我们使用supervisor来控制uwsg进程,这也非常简单:

# recipes/web.rb

command = "/srv/www/getsentry.com/env/bin/uwsgi -s 127.0.0.1:90%(process_num)02d --need-app --disable-logging --wsgi-file getsentry/wsgi.py --processes 1 --threads #{node['getsentry']['web']['threads']}"

supervisor_service "web" do
  directory "/srv/www/getsentry.com/current/"
  command command
  user "dcramer"
  stdout_logfile "syslog"
  stderr_logfile "syslog"
  startsecs 10
  stopsignal "QUIT"
  stopasgroup true
  killasgroup true
  process_name '%(program_name)s %(process_num)02d'
  numprocs node['getsentry']['web']['processes']
end
Garfielt
Garfielt
翻译于 2013/07/08 18:31
2

位置的选择

除非有人想出了一个非常有说服力的论据:为什么应该有另一种方式(或某种该情形下不能工作的情况),我希望能听到这种模式因为Python的世界变得更标准。最起码,我希望看到关于如何提高uwsgi内进程管理的一些辩论的火花

如果你要精简这个帖子,留下这句话:uwsgi线程(或非线程)服务是Python的Web应用程序唯一选择

(我匆匆写了这篇文章来说明今天的一些研究结果,所以难免简单,错别字请谅解)

Garfielt
Garfielt
翻译于 2013/07/08 18:37
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(15)

caol
caol
使用gunicorn觉得比uwsgi配置起来更加方便和简单
周星星
周星星
此文应尽快删除,免得误导新人
拿日蓝
拿日蓝

引用来自“BaitaoJi”的评论

垃圾

不是吧
BaitaoSi
BaitaoSi
垃圾
随我方向
随我方向
示例代码都是Ruby的呀, 感觉很飘逸的语言~~~
阿鹅分
阿鹅分
Server:Tengine/1.4.6
壮哉我大东北
壮哉我大东北
凭什么?扯淡
FeiFan
FeiFan
不是翻译的问题, 英文原文写的就比较跳跃.. 有些地方是puppet的配置文件, 用的ruby的语法.
意思好像是: 用Nginx在一个port上面负载均衡到10个进程, 比用gunicorn+gevent, 起10个worker来的效果好. 前者是部署tornado程序的常见方法. 后者是部署django常用的方法.
宏哥
宏哥
Approved
倪倪
乱糟糟的翻译
返回顶部
顶部