53

私はnginxとuwsgiでdjangoアプリを実行しています。これが私がuwsgiを実行する方法です:

sudo uwsgi -b 25000 --chdir=/www/python/apps/pyapp --module=wsgi:application --env DJANGO_SETTINGS_MODULE=settings --socket=/tmp/pyapp.socket --cheaper=8 --processes=16  --harakiri=10  --max-requests=5000  --vacuum --master --pidfile=/tmp/pyapp-master.pid --uid=220 --gid=499

&nginx構成:

server {
    listen 80;
    server_name test.com

    root /www/python/apps/pyapp/;

    access_log /var/log/nginx/test.com.access.log;
    error_log /var/log/nginx/test.com.error.log;

    # https://docs.djangoproject.com/en/dev/howto/static-files/#serving-static-files-in-production
    location /static/ {
        alias /www/python/apps/pyapp/static/;
        expires 30d;
    }

    location /media/ {
        alias /www/python/apps/pyapp/media/;
        expires 30d;
    }

    location / {
        uwsgi_pass unix:///tmp/pyapp.socket;
        include uwsgi_params;
        proxy_read_timeout 120;
    }

    # what to serve if upstream is not available or crashes
    #error_page 500 502 503 504 /media/50x.html;
}

ここに問題があります。サーバーで「ab」(ApacheBenchmark)を実行すると、次の結果が得られます。

nginxバージョン:nginxバージョン:nginx / 1.2.6

uwsgiバージョン:1.4.5

Server Software:        nginx/1.0.15
Server Hostname:        pycms.com
Server Port:            80

Document Path:          /api/nodes/mostviewed/8/?format=json
Document Length:        8696 bytes

Concurrency Level:      100
Time taken for tests:   41.232 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      8866000 bytes
HTML transferred:       8696000 bytes
Requests per second:    24.25 [#/sec] (mean)
Time per request:       4123.216 [ms] (mean)
Time per request:       41.232 [ms] (mean, across all concurrent requests)
Transfer rate:          209.99 [Kbytes/sec] received

500の同時実行レベルで実行中

oncurrency Level:      500
Time taken for tests:   2.175 seconds
Complete requests:      1000
Failed requests:        50
   (Connect: 0, Receive: 0, Length: 50, Exceptions: 0)
Write errors:           0
Non-2xx responses:      950
Total transferred:      629200 bytes
HTML transferred:       476300 bytes
Requests per second:    459.81 [#/sec] (mean)
Time per request:       1087.416 [ms] (mean)
Time per request:       2.175 [ms] (mean, across all concurrent requests)
Transfer rate:          282.53 [Kbytes/sec] received

ご覧のとおり...サーバー上のすべてのリクエストは、タイムアウトエラーまたは「クライアントが時期尚早に切断されました」または次のいずれかで失敗します。

writev(): Broken pipe [proto/uwsgi.c line 124] during GET /api/nodes/mostviewed/9/?format=json

私のアプリケーションについてもう少し詳しく説明します。基本的には、すべてのコンテンツを含むMySQLテーブルを反映するモデルのコレクションです。フロントエンドには、jsonコンテンツをクライアントに提供するdjango-rest-frameworkがあります。

django-profiling&django debugツールバーをインストールして、何が起こっているかを確認しました。django-profilingで、単一のリクエストを実行したときに得られるものは次のとおりです。

Instance wide RAM usage

Partition of a set of 147315 objects. Total size = 20779408 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  63960  43  5726288  28   5726288  28 str
     1  36887  25  3131112  15   8857400  43 tuple
     2   2495   2  1500392   7  10357792  50 dict (no owner)
     3    615   0  1397160   7  11754952  57 dict of module
     4   1371   1  1236432   6  12991384  63 type
     5   9974   7  1196880   6  14188264  68 function
     6   8974   6  1076880   5  15265144  73 types.CodeType
     7   1371   1  1014408   5  16279552  78 dict of type
     8   2684   2   340640   2  16620192  80 list
     9    382   0   328912   2  16949104  82 dict of class
<607 more rows. Type e.g. '_.more' to view.>



CPU Time for this request

         11068 function calls (10158 primitive calls) in 0.064 CPU seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.064    0.064 /usr/lib/python2.6/site-packages/django/views/generic/base.py:44(view)
        1    0.000    0.000    0.064    0.064 /usr/lib/python2.6/site-packages/django/views/decorators/csrf.py:76(wrapped_view)
        1    0.000    0.000    0.064    0.064 /usr/lib/python2.6/site-packages/rest_framework/views.py:359(dispatch)
        1    0.000    0.000    0.064    0.064 /usr/lib/python2.6/site-packages/rest_framework/generics.py:144(get)
        1    0.000    0.000    0.064    0.064 /usr/lib/python2.6/site-packages/rest_framework/mixins.py:46(list)
        1    0.000    0.000    0.038    0.038 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:348(data)
     21/1    0.000    0.000    0.038    0.038 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:273(to_native)
     21/1    0.000    0.000    0.038    0.038 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:190(convert_object)
     11/1    0.000    0.000    0.036    0.036 /usr/lib/python2.6/site-packages/rest_framework/serializers.py:303(field_to_native)
    13/11    0.000    0.000    0.033    0.003 /usr/lib/python2.6/site-packages/django/db/models/query.py:92(__iter__)
      3/1    0.000    0.000    0.033    0.033 /usr/lib/python2.6/site-packages/django/db/models/query.py:77(__len__)
        4    0.000    0.000    0.030    0.008 /usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py:794(execute_sql)
        1    0.000    0.000    0.021    0.021 /usr/lib/python2.6/site-packages/django/views/generic/list.py:33(paginate_queryset)
        1    0.000    0.000    0.021    0.021 /usr/lib/python2.6/site-packages/django/core/paginator.py:35(page)
        1    0.000    0.000    0.020    0.020 /usr/lib/python2.6/site-packages/django/core/paginator.py:20(validate_number)
        3    0.000    0.000    0.020    0.007 /usr/lib/python2.6/site-packages/django/core/paginator.py:57(_get_num_pages)
        4    0.000    0.000    0.020    0.005 /usr/lib/python2.6/site-packages/django/core/paginator.py:44(_get_count)
        1    0.000    0.000    0.020    0.020 /usr/lib/python2.6/site-packages/django/db/models/query.py:340(count)
        1    0.000    0.000    0.020    0.020 /usr/lib/python2.6/site-packages/django/db/models/sql/query.py:394(get_count)
        1    0.000    0.000    0.020    0.020 /usr/lib/python2.6/site-packages/django/db/models/query.py:568(_prefetch_related_objects)
        1    0.000    0.000    0.020    0.020 /usr/lib/python2.6/site-packages/django/db/models/query.py:1596(prefetch_related_objects)
        4    0.000    0.000    0.020    0.005 /usr/lib/python2.6/site-packages/django/db/backends/util.py:36(execute)
        1    0.000    0.000    0.020    0.020 /usr/lib/python2.6/site-packages/django/db/models/sql/query.py:340(get_aggregation)
        5    0.000    0.000    0.020    0.004 /usr/lib64/python2.6/site-packages/MySQLdb/cursors.py:136(execute)
        2    0.000    0.000    0.020    0.010 /usr/lib/python2.6/site-packages/django/db/models/query.py:1748(prefetch_one_level)
        4    0.000    0.000    0.020    0.005 /usr/lib/python2.6/site-packages/django/db/backends/mysql/base.py:112(execute)
        5    0.000    0.000    0.019    0.004 /usr/lib64/python2.6/site-packages/MySQLdb/cursors.py:316(_query)
       60    0.000    0.000    0.018    0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:231(iterator)
        5    0.012    0.002    0.015    0.003 /usr/lib64/python2.6/site-packages/MySQLdb/cursors.py:278(_do_query)
       60    0.000    0.000    0.013    0.000 /usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py:751(results_iter)
       30    0.000    0.000    0.010    0.000 /usr/lib/python2.6/site-packages/django/db/models/manager.py:115(all)
       50    0.000    0.000    0.009    0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:870(_clone)
       51    0.001    0.000    0.009    0.000 /usr/lib/python2.6/site-packages/django/db/models/sql/query.py:235(clone)
        4    0.000    0.000    0.009    0.002 /usr/lib/python2.6/site-packages/django/db/backends/__init__.py:302(cursor)
        4    0.000    0.000    0.008    0.002 /usr/lib/python2.6/site-packages/django/db/backends/mysql/base.py:361(_cursor)
        1    0.000    0.000    0.008    0.008 /usr/lib64/python2.6/site-packages/MySQLdb/__init__.py:78(Connect)
  910/208    0.003    0.000    0.008    0.000 /usr/lib64/python2.6/copy.py:144(deepcopy)
       22    0.000    0.000    0.007    0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:619(filter)
       22    0.000    0.000    0.007    0.000 /usr/lib/python2.6/site-packages/django/db/models/query.py:633(_filter_or_exclude)
       20    0.000    0.000    0.005    0.000 /usr/lib/python2.6/site-packages/django/db/models/fields/related.py:560(get_query_set)
        1    0.000    0.000    0.005    0.005 /usr/lib64/python2.6/site-packages/MySQLdb/connections.py:8()

..等

ただし、django-debug-toolbarは次のように表示されます。

Resource Usage
Resource    Value
User CPU time   149.977 msec
System CPU time 119.982 msec
Total CPU time  269.959 msec
Elapsed time    326.291 msec
Context switches    11 voluntary, 40 involuntary

and 5 queries in 27.1 ms

問題は、「top」が負荷平均が急速に上昇していることを示し、ローカルサーバーとネットワーク内のリモートマシンの両方で実行したapacheベンチマークが、1秒あたり多くのリクエストを処理していないことを示していることです。何が問題ですか?これは、コードをプロファイリングするときに到達できる範囲であるため、誰かが私がここで行っていることを指摘できれば幸いです。

編集(2013年2月23日):Andrew Alcockの回答に基づいて詳細を追加: 注意/回答が必要なポイントは(3)(3)MySQLで「グローバル変数の表示」を実行し、MySQLの構成を見つけましたmax_connections設定に151がありました。これは、uwsgiで開始しているワーカーにサービスを提供するのに十分です。

(3)(4)(2)私がプロファイリングしている単一のリクエストは、最も重いリクエストです。django-debug-toolbarに従って4つのクエリを実行します。何が起こるかというと、すべてのクエリはそれぞれ3.71、2.83、0.88、4.84ミリ秒で実行されます。

(4)ここで、メモリページングについて言及していますか?もしそうなら、私はどのように言うことができますか?

(5)16のワーカー、100の同時実行率、1000の要求で、負荷の平均は最大12になります。さまざまな数のワーカーでテストを実行しました(同時実行レベルは100)。

  1. 1人のワーカー、平均負荷〜1.85、19リクエスト/秒、リクエストあたりの時間:5229.520、0非2xx
  2. 2ワーカー、平均負荷〜1.5、19リクエスト/秒、リクエストあたりの時間:516.520、0非2xx
  3. 4ワーカー、負荷平均〜3、16リクエスト/秒、リクエストあたりの時間:5929.921、0非2xx
  4. 8ワーカー、負荷平均〜5、18リクエスト/秒、リクエストあたりの時間:5301.458、0非2xx
  5. 16ワーカー、平均負荷〜19、15リクエスト/秒、リクエストあたりの時間:6384.720、0非2xx

ご覧のとおり、ワーカーが多いほど、システムにかかる負荷も大きくなります。uwsgiのデーモンログを見ると、ワーカーの数を増やすと、ミリ秒単位の応答時間が長くなることがわかります。

16人のワーカーで、500の同時実行レベルの要求を実行すると、uwsgiはエラーのログ記録を開始します。

 writev(): Broken pipe [proto/uwsgi.c line 124] 

負荷も最大10になります。また、2xx以外の応答は1000のうち923であるため、テストにそれほど時間はかかりません。これが、ここでの応答がほとんど空であるため、非常に高速である理由です。これは、要約のポイント4への回答でもあります。

ここで私が直面しているのは、I / Oとネットワークに基づくOSレイテンシーであると仮定すると、これをスケールアップするために推奨されるアクションは何ですか?新しいハードウェア?より大きなサーバー?

ありがとう

4

3 に答える 3

153

編集1あなたが1つの仮想コアを持っているというコメントを見て、すべての関連するポイントにコメントを追加します

編集2マーベリックからのより多くの情報、それで私は除外されたアイデアを排除し、確認された問題を開発しています。

編集3uwsgiリクエストキューとスケーリングオプションに関する詳細を記入しました。文法の改善。

マーベリックからの4つのアップデートとマイナーな改善を編集

コメントが小さすぎるので、ここにいくつかの考えがあります:

  1. 負荷平均は、基本的に、CPUで実行されている、またはCPUの注意を待っているプロセスの数です。1つのCPUコアを備えた完全にロードされたシステムの場合、ロード平均は1.0である必要があります。4コアシステムの場合、4.0である必要があります。Webテストを実行した瞬間、スレッディングロケットが発生し、CPUを待機しているプロセスがたくさんあります。負荷平均がCPUコアの数を大幅に超えない限り、問題にはなりません。
  2. 最初の「リクエストあたりの時間」の値は4秒で、リクエストキューの長さに相関します。1000個のリクエストがほぼ瞬時にDjangoにダンプされ、サービスに平均4秒かかり、そのうち約3.4秒がキューで待機していました。これは、要求の数(100)とプロセッサの数(16)の不一致が非常に大きく、84個の要求が常にプロセッサを待機しているためです。
  3. 100の同時実行で実行すると、テストは24リクエスト/秒で41秒かかります。16個のプロセス(スレッド)があるため、各リクエストは約700ミリ秒で処理されます。トランザクションのタイプを考えると、それはリクエストごとに長い時間です。これは次の理由による可能性があります。

    1. Djangoでは各リクエストのCPUコストが高くなります(デバッグツールバーのCPU値が低い場合はほとんどありません)。
    2. OSは多くのタスク切り替えを行っており(特に負荷平均が4〜8を超える場合)、レイテンシーは純粋にプロセスが多すぎることによるものです。
    3. 16個のプロセスにサービスを提供する十分なDB接続がないため、プロセスは1つが使用可能になるのを待っています。プロセスごとに少なくとも1つの接続を利用できますか?
    4. DBの周りにはかなりの待ち時間があります:

      1. 数十の小さなリクエストがそれぞれ、たとえば10ミリ秒かかりますが、そのほとんどはネットワークのオーバーヘッドです。もしそうなら、キャッシングを導入するか、SQL呼び出しをより少ない数に減らすことができますか?または
      2. 1つまたは2つのリクエストに数百ミリ秒かかります。これを確認するには、DBでプロファイリングを実行します。その場合は、そのリクエストを最適化する必要があります。
  4. システムとユーザーのCPUコストの分割は、システム全体で異常に高くなりますが、合計CPUは低くなります。これは、Djangoでの作業のほとんどが、ネットワークやディスクなどのカーネル関連であることを意味します。このシナリオでは、ネットワークコストが発生する可能性があります(たとえば、HTTPリクエストの送受信、DBへのリクエストの送受信)。ページングが原因で、これが高くなる場合があります。ページングが行われていない場合は、おそらくこれについてまったく心配する必要はありません。

  5. プロセスを16に設定しましたが、負荷平均が高くなっています(記述しない高さ)。理想的には、CPUを待機しているプロセスを常に少なくとも1つ持つ必要があります(CPUがアイドル状態で回転しないようにするため)。ここでのプロセスはCPUにバインドされているようには見えませんが、かなりのレイテンシがあるため、コアよりも多くのプロセスが必要です。あといくつ?最高のスループットが得られるまで、さまざまな数のプロセッサ(1、2、4、8、12、16、24など)でuwsgiを実行してみてください。平均的なプロセスのレイテンシーを変更する場合は、これを再度調整する必要があります。
  6. 500の同時実行レベルは間違いなく問題ですが、それはクライアントですか、それともサーバーですか?レポートによると、50(100のうち)のコンテンツの長さが正しくないため、サーバーの問題が発生している可能性があります。非2xxもそこを指しているようです。デバッグのために2xx以外の応答をキャプチャすることは可能ですか?スタックトレースまたは特定のエラーメッセージは非常に便利であり(編集)、デフォルト値の100で実行されているuwsgi要求キューが原因です。

したがって、要約すると:

ここに画像の説明を入力してください

  1. Djangoは問題ないようです
  2. 負荷テスト(100または500)とプロセス(16)の同時実行性の不一致:処理するプロセスの数に対して、システムにあまりにも多くの同時要求をプッシュしています。プロセスの数を超えると、WebサーバーのHTTPリクエストキューを長くするだけです。
  3. レイテンシーが大きいので、どちらか

    1. プロセス(16)とCPUコア(1)の不一致:負荷平均が3より大きい場合は、プロセスが多すぎる可能性があります。少数のプロセスで再試行してください

      1. 負荷平均>2->8つのプロセスを試す
      2. 負荷平均>4->4つのプロセスを試す
      3. 負荷平均>8->2つのプロセスを試す
    2. 負荷平均が3未満の場合は、DBにある可能性があるため、DBのプロファイルを作成して、小さな要求の負荷があるか(さらにレイテンシーを引き起こしている)、または1つまたは2つのSQLステートメントが問題であるかどうかを確認します。

  4. 失敗した応答をキャプチャせずに、500の同時実行での失敗について私が言えることはあまりありません

アイデアの開発

シングルコアマシンでの平均負荷が10を超えると、非常に厄介であり、(観察したとおり)多くのタスク切り替えと一般的な低速動作につながります。個人的には、平均負荷が19のマシン(16のプロセスで使用できます)を見たのを覚えていません。これほど高くなったことをおめでとうございます;)

DBのパフォーマンスは素晴らしいので、今はそれをすべて明確にしておきます。

ページング:ページングの表示方法に関する質問に答えるために、OSのページングをいくつかの方法で検出できます。たとえば、上部のヘッダーにはページインとページアウトがあります(最後の行を参照)。

プロセス:合計170、実行中3、スタック4、スリープ中163、スレッド927:15:06:31
負荷平均:0.90、1.19、1.94 CPU使用率:1.37%ユーザー、2.97%sys、95.65%アイドルSharedLibs:144M常駐、0Bデータ、24Mlinkedit。
MemRegions:合計31726、居住者2541M、プライベート120M、共有817M。PhysMem:1420M有線、3548Mアクティブ、1703M非アクティブ、6671M使用、1514M無料。
VM:392G vsize、1286Mフレームワークvsize、1534241(0)ページイン、0(0)ページアウト。ネットワーク:パケット:789684 / 288M入力、912863/482M出力。ディスク:739807 / 15G読み取り、996745/24G書き込み。

プロセス数:現在の構成では、プロセス数が多すぎますプロセス数を2に戻します。このサーバーからさらに負荷をシフトすることに応じて、この値を後で上げる可能性があります。

Apacheベンチマークの場所:1つのプロセスの平均負荷1.85は、uwsgiと同じマシンで負荷ジェネレーターを実行していることを示しています-それは正しいですか?

もしそうなら、あなたは本当にこれを別のマシンから実行する必要があります、さもなければテスト実行は実際の負荷を表していない-あなたは負荷ジェネレータで使用するためにウェブプロセスからメモリとCPUを取っています。さらに、負荷ジェネレーターの100または500スレッドは、通常、実際には発生しない方法でサーバーに負荷をかけます。確かに、これがテスト全体が失敗する理由かもしれません。

DBの場所:1つのプロセスの平均負荷は、Webプロセスと同じマシンでDBを実行していることも示しています-これは正しいですか?

DBについて正しければ、スケーリングを開始する最初の最良の方法は、DBを別のマシンに移動することです。これを行う理由はいくつかあります。

  1. DBサーバーには、処理ノードとは異なるハードウェアプロファイルが必要です。

    1. ディスク:DBには高速で冗長なバックアップディスクが多数必要であり、処理ノードには基本ディスクのみが必要です。
    2. CPU:処理ノードは、余裕のある最速のCPUを必要としますが、DBマシンは、多くの場合、それなしで実行できます(多くの場合、そのパフォーマンスはディスクとRAMでゲートされます)
    3. RAM:DBマシンは一般にできるだけ多くのRAMを必要とします(そして最速のDBはすべてのデータをRAMに保存します)が、多くの処理ノードははるかに少ない必要があります(プロセスごとに約20MBが必要です-非常に小さい
    4. スケーリング:アトミックDBは、多数のCPUを搭載したモンスターマシンを使用することで最適にスケーリングしますが、Web層(状態を持たない)は、多数の同一の小さなボックスを接続することでスケーリングできます。
  2. CPUアフィニティ:CPUの負荷平均は1.0で、プロセスはシングルコアにアフィニティである方が適切です。そうすることで、CPUキャッシュの使用が最大化され、タスク切り替えのオーバーヘッドが最小化されます。DBノードと処理ノードを分離することにより、HWでこのアフィニティを適用します。

例外を除いて500の同時実行性上記の図の要求キューは最大で100です。キューがいっぱいになったときにuwsgiが要求を受信すると、要求は5xxエラーで拒否されます。これは500の同時実行負荷テストで発生したと思います。基本的に、キューは最初の100ほどのスレッドでいっぱいになり、残りの400のスレッドは残りの900のリクエストを発行し、すぐに5xxエラーを受け取りました。

1秒あたり500のリクエストを処理するには、次の2つのことを確認する必要があります。

  1. リクエストキューのサイズは、バーストを処理するように構成されています。--listen引数を使用してuwsgi
  2. システムは、500が通常の状態の場合は1秒あたり500リクエストを超え、500がピークの場合は少し下のスループットでスループットを処理できます。以下のスケーリングに関する注意事項を参照してください。

uwsgiでは、DDoS攻撃をより適切に処理するために、キューの数が少なく設定されていると思います。大きな負荷がかかると、ほとんどのリクエストはほとんど処理されずにすぐに失敗し、ボックス全体が管理者に応答できるようになります。

システムをスケーリングするための一般的なアドバイス

最も重要な考慮事項は、おそらくスループットを最大化することです。応答時間を最小限に抑えるもう1つの可能性がありますが、ここではこれについては説明しません。スループットを最大化するには、個々のコンポーネントではなく、システムを最大化しようとしています。一部のローカルな減少により、システム全体のスループットが向上する可能性があります(たとえば、DBのパフォーマンスを向上させるために、Web層に遅延を追加する変更を加えることは、純利益です)。

詳細について:

  1. DBを別のマシンに移動します。topこの後、実行してお気に入りのMySQL監視ツールを使用して、負荷テスト中にDBのプロファイルを作成します。プロファイルできる必要があります。DBを別のマシンに移動すると、リクエストごとに追加のレイテンシ(数ミリ秒)が発生するため、同じスループットを維持するために、Web層のプロセス数をわずかに増やすことを期待してください。
  2. 引数uswgiを使用してトラフィックのバーストを処理するのに十分な大きさの要求キューがあることを確認してください。--listenこれは、システムが処理できる1秒あたりの最大定常状態要求の数倍である必要があります。
  3. Web /アプリ層の場合:プロセスの数とCPUコアの数、およびプロセスに固有のレイテンシーのバランスを取ります。プロセスが多すぎるとパフォーマンスが低下します。少なすぎると、システムリソースを十分に活用できなくなります。すべてのアプリケーションと使用パターンが異なるため、固定のバランスポイントはありません。ベンチマークと調整を行ってください。各タスクに次のような場合は、ガイドとしてプロセスのレイテンシーを使用してください。

    • レイテンシが0%の場合、コアごとに1つのプロセスが必要です
    • 50%のレイテンシー(つまり、CPU時間は実際の時間の半分です)、コアごとに2つのプロセスが必要です
    • 67%のレイテンシーの場合、コアごとに3つのプロセスが必要です
  4. topテスト中に、(コアごとに)CPU使用率が90%を超えており、負荷平均が1.0を少し上回っていることを確認ます。負荷平均が高い場合は、プロセスを縮小します。すべてがうまくいけば、ある時点でこの目標を達成できなくなり、DBがボトルネックになる可能性があります

  5. ある時点で、Web層でより多くの電力が必要になります。マシンにCPUを追加して(比較的簡単)、プロセスを追加するか、処理ノードを追加する(水平スケーリング可能性)かを選択できます。後者は、ŁukaszMierzwaがここで説明した方法を使用してuwsgiで実現できます。
于 2013-02-23T06:53:14.330 に答える
7

ベンチマークを1分よりもはるかに長く実行してください(少なくとも5〜10)。このような短いテストでは、実際には多くの情報を取得できません。そして、uWSGIのカーボンプラグインを使用して統計をカーボン/グラファイトサーバーにプッシュします(必要になります)。デバッグのためのより多くの情報があります。

アプリに500の同時リクエストを送信し、そのような負荷を処理できない場合、各バックエンドのリッスンキューはすぐにいっぱいになります(デフォルトでは100リクエストです)。それを増やしたいと思うかもしれませんが、ワーカーが処理できない場合高速でリッスンするキュー(バックログとも呼ばれます)がいっぱいになると、Linuxネットワークスタックはリクエストをドロップし、エラーが発生し始めます。

最初のベンチマークでは、単一のリクエストを最大42ミリ秒で処理できるため、単一のワーカーが最大で1000ミリ秒/ 42ミリ秒=1秒あたり最大23のリクエストを処理できると述べています(同時実行性が上がるにつれてdbやアプリスタックの他の部分の速度が低下しなかった場合) 。したがって、500の同時リクエストを処理するには、少なくとも500/23 = 21のワーカーが必要です(実際には少なくとも40と言います)。16しかないので、このような負荷がかかると壊れてしまうのも不思議ではありません。

編集:レートと同時実行性を混合しました-少なくとも21のワーカーにより、500の同時リクエストではなく、1秒あたり500のリクエストを処理できます。本当に500の同時リクエストを処理したい場合は、単に500のワーカーが必要です。アプリを非同期モードで実行する場合を除き、uWSGIドキュメントの「Gevent」セクションを確認してください。

PS。uWSGIには、バックエンド自動構成を備えた優れたロードバランサーが付属しています(「サブスクリプションサーバー」および「FastRouter」のドキュメントを参照してください)。必要に応じて新しいバックエンドをホットプラグできるように設定できます。新しいノードでワーカーを起動するだけで、FastRouterにサブスクライブし、リクエストの取得を開始します。これは、水平方向にスケーリングするための最良の方法です。また、AWSのバックエンドを使用すると、これを自動化して、必要なときに新しいバックエンドをすばやく開始できるようになります。

于 2013-02-24T09:44:55.957 に答える
1

ワーカーを追加してr/sを減らすということは、リクエストが「純粋なCPU」であり、別のワーカーが別のリクエストを処理するために使用できるIO待機がないことを意味します。

スケーリングする場合は、より多くの(またはより高速な)CPUを搭載した別のサーバーを使用する必要があります。

ただし、これは総合的なテストです。取得するr / sの数は、テストしている正確なリクエストの上限です。本番環境に入ると、パフォーマンスに影響を与える可能性のある変数がさらに多くなります。

于 2013-02-24T06:47:02.673 に答える