歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 你應該使用Nginx + UWSGI

你應該使用Nginx + UWSGI

日期:2017/2/27 15:58:46   编辑:Linux教程
經過大量的實驗(在 disqus.com和 getsentry.com上),我可以確切的說:uwsgi應該成為Python世界的標准。 把它和nginx結合,在基於 Python的Web應用程序上你能獲得在線程(或非線程)之上更好的性能體驗。

更新:忽略古老的說法“你給任何度量是慢”,我在這裡說的請求是指後端節點,他們處理輸入事件(從20KB到1MB大小的請求),在網絡跳過數跳經過各種授權和配額策略,並最形成一些隊列操作。卸載盡可能多的工作負載。

服務策略
目前已經有相當數量的方法可以用來運行Python應用程序。我不打算使用mod_wsgi,最重要的,我並不想說明事件模型如何工作。我不相信在Python的世界它們依舊使用,所以這篇文章的主題也不是關於傳統的線程(或多進程)的Python應用程序。
相反,我將專注於兩個最流行且我最熟悉的解決方案:gunicorn和uwsgi。

Gunicorn(Python UNIX平台的wsgi服務器)
回顧過去,Python的Web服務器的解決方案基本上只有mod_wsgi。其中最流行的(或理解為時尚)的方法是最近Gunicorn。
實際上,我仍然建議使用gunicorn,這樣可以極大的減少不便:它可以漂亮的嵌入Django而且設置簡單。
它也有10%的配置選項和uwsgi一致(這對某些人來說是件好事),除此之外,比較看來,它提供了與uwsgi(或任何其他Python Web服務器)幾乎相同的基本特性。

uwsgi
在我看來這是唯一的選擇,從Gunicorn到uwsgi。將有更高性能的,有更多極易明白的配置選項,通過協議可以與nginx交互也增加了優勢。
它的配置也是相當簡單,找到一篇文章相關文章就可以了,後來更多。
我開始使用uwsgi來跑一些應用,使用–processes=10和–threads=10來測試服務器的多CPU,目的有兩個:
  • 支持情況
  • 測試降低內存使用量的可能性
  • 測試線程安全的支持情況
(對於這些測試是否值得,DISQUS是 單線程運行的,我想保持盡可能的精簡,把每個節點的能力發揮到極致)

不斷趨向成功的迭代
我們使API平均響應時間降到40ms以內,我非常自豪。這裡我說的API相應時間是指:從請求擊中了Python服務器到服務器返回響應到代理所花費的時間。
不幸的是,當我們始獲得越來越大的流量並出現訪問尖峰後響應時間出現問題了,波動的響應時間不再符合我們開始的設想,盡管服務節點上我們仍然有大約30%的內存和60%的資源空余。
在不少調整後,我們停用了大量uwsgi進程的方法,讓nginx的負載均衡它們(之前是讓uwsgi本身負載平衡)。
這意味著什麼呢,是不是做uwsgi過程= 10,我們運行10個單獨的uwsgi實例代替–processes=10。
其結果是一個美麗的,一致的20ms的平均響應時間。 API響應時間
將他們組合在一起
我喜歡著手去做而非空談,這裡我給大家一些我們在線服務器的實際設置。

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

位置的選擇
除非有人想出了一個非常有說服力的論據:為什麼應該有另一種方式(或某種該情形下不能工作的情況),我希望能聽到這種模式因為Python的世界變得更標准。最起碼,我希望看到關於如何提高uwsgi內進程管理的一些辯論的火花。
如果你要精簡這個帖子,留下這句話:uwsgi線程(或非線程)服務是Python的Web應用的程序唯一選擇。
轉自:http://www.oschina.net/translate/serving-python-web-applications
Copyright © Linux教程網 All Rights Reserved