Nginx + UWSGIの使い方

巴扎黑
巴扎黑オリジナル
2017-04-05 14:56:181484ブラウズ

(disqus.com と getsentry.com で) 多くの実験を行った結果、私は間違いなく言えます: uwsgi は Python の世界の標準になるはずです。 nginx と組み合わせると、Python ベースの Web アプリケーションのスレッド (または非スレッド) でのパフォーマンス エクスペリエンスが向上します。

更新: 「与えられたメトリックはどれも遅い」という古くからの言い伝えを無視してください。ここでのリクエストとはバックエンド ノードを指します。バックエンド ノードは受信イベント (サイズが 20 KB から 1 MB の範囲のリクエスト) を処理し、ネットワーク内のさまざまなホップを飛び越えます。ポリシーであり、ほとんどは何らかのキュー操作を形成します。可能な限り多くのワークロードをオフロードします。 (この段落の翻訳に問題があります。原文と訳者注を参照してください)

サービス戦略

Python アプリケーションを実行する方法はすでに多数あります。 mod_wsgi を使用するつもりはありません。そして最も重要なのは、イベント モデルがどのように機能するかを説明しようとしているわけではありません。これらが Python の世界ではまだ使用されているとは思えないため、この記事のトピックは従来のスレッド (またはマルチプロセス) Python アプリケーションに関するものではありません。

代わりに、私が最もよく知っている 2 つの最も人気のあるソリューション、gunicorn と uwsgi に焦点を当てます。

Gunicorn (Python UNIX プラットフォーム用の wsgi サーバー)

過去を振り返ると、Python の Web サーバーのソリューションは基本的に mod_wsgi でした。最近最も人気のある (または流行していると考えられている) 方法の 1 つは Gunicorn です。

実際、私は今でも gunicorn を使用することをお勧めします。これにより、不便さが大幅に軽減されます。Gunicorn は Django を美しく埋め込み、セットアップが簡単です。

また、uwsgi と同じ構成オプションが 10% ありますが (これは一部の人にとっては良いことです)、それ以外は、比較すると、uwsgi (または他の Python Web サーバー) とほぼ同じ基本機能を提供します。

うすぎ

私の意見では、Gunicorn から uwsgi まで、これが唯一の選択肢です。パフォーマンスが向上し、理解しやすい構成オプションが増え、プロトコルを通じて nginx と対話できる機能も利点を追加します。
その構成も非常にシンプルです。関連する記事を見つけるだけです。詳細については後ほど説明します。
私はいくつかのアプリケーションを実行するために uwsgi を使い始め、次の 2 つの目的で –processes=10 と –threads=10 を使用してサーバーのマルチ CPU をテストしました:

  • サポート状況


  • メモリ使用量を削減できる可能性をテストしています


  • スレッドの安全性サポートをテストします

(これらのテストに価値があるかどうかについては、DISQUS はシングルスレッドで実行されます。できるだけ合理化して各ノードの機能を最大化したいと考えています)

成功に向けて継続的に反復します

API の平均応答時間を 40 ミリ秒未満に短縮できたことを非常に誇りに思っています。ここで話している API 応答時間とは、リクエストが Python サーバーに到達してから、サーバーがプロキシに応答を返すまでにかかる時間を指します。

残念ながら、サービス ノードにはまだ約 30% のメモリがあり、アクセスのスパイクが発生し始めると、応答時間の変動が当初の予想と一致しなくなり始めました。 % のリソースが利用可能です。

多くの調整を行った後、多数の uwsgi プロセスを非アクティブ化し、nginx に負荷分散を行わせました (以前は uwsgi 自体に負荷分散を行わせていました)。

これは、uwsgiprocesses=10 を実行する代わりに、--processes=10 の代わりに 10 個の個別の uwsgi インスタンスを実行することを意味します。

その結果、美しく安定した 20 ミリ秒の平均応答時間が得られます。

API 応答時間

一緒に並べてください

私は何かについて話すよりも、実際に何かをするのが好きなので、ここではオンライン サーバーの実際のセットアップをいくつか紹介します。

nginx

構成の最初の部分は Nginx であり、実際に uwsgi プロセス バックエンドの数を計算して追加する必要があるため、少し複雑になります。

まず、Web ページで構成リストを作成します:

# 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 構成で使用されるソケット アドレスです。

うすぎ

一方、スーパーバイザーを使用して 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[&#39;getsentry&#39;][&#39;web&#39;][&#39;threads&#39;]}"

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 &#39;%(program_name)s %(process_num)02d&#39;
  numprocs node[&#39;getsentry&#39;][&#39;web&#39;][&#39;processes&#39;]
end

場所の選択

なぜ別の方法があるのか​​ (またはこの場合は機能しないのか) 誰かが非常に説得力のある議論を思いつかない限り、Python の世界がより標準になるにつれて、私はこのパターンについて聞きたいと思っています。少なくとも、uwsgi 内でプロセス管理を改善する方法についての議論が火花を散らすことを期待します。

以上がNginx + UWSGIの使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。