7

uwsgi + nginxでpythonアプリケーション(フラスコ+ redis-py)を実行し、aws elasticache(redis 2.8.24)を使用しています。

アプリケーションの応答時間を改善しようとしているときに、高負荷 (1 秒あたり 500 リクエスト/loader.io を使用して 30 秒間) でリクエストが失われていることに気付きました (このテストでは、負荷のない単一のサーバーのみを使用しています)バランサー、1 つの uwsgi インスタンス、4 つのプロセス、テスト目的で)。 ストレステスト

もう少し詳しく調べたところ、この負荷がかかると、ElastiCache への一部のリクエストが遅くなることがわかりました。例えば:

  • 通常の負荷: cache_set 時間 0.000654935836792
  • 高負荷: cache_set time 0.0122258663177 これはすべてのリクエストで発生するわけではなく、ランダムに発生します..

私の AWS ElastiCache は、cache.m4.xlarge の 2 つのノードに基づいています (デフォルトの AWS 構成設定)。過去 3 時間に接続された現在のクライアントを表示します。 aws エラスティックアッシュ クライアント

現在 14 台のサーバー (そのうちの 8 台は XX RPS の高トラフィックでこのクラスターを使用) であるため、これは意味がないと思います。クライアント レートがはるかに高くなると予想されます。

uWSGI 構成 (バージョン 2.0.5.1)

processes = 4
enable-threads = true
threads = 20
vacuum = true
die-on-term = true
harakiri = 10
max-requests = 5000
thread-stacksize = 2048
thunder-lock = true
max-fd = 150000
# currently disabled for testing
#cheaper-algo = spare2
#cheaper = 2
#cheaper-initial = 2
#workers = 4
#cheaper-step = 1

Nginx は、unix ソケットを使用した uWSGI への単なる Web プロキシです。

これは、redis への接続を開く方法です。

rdb = [
    redis.StrictRedis(host='server-endpoint', port=6379, db=0),
    redis.StrictRedis(host='server-endpoint', port=6379, db=1)
]

これは、たとえば値を設定する方法です。

def cache_set(key, subkey, val, db, cache_timeout=DEFAULT_TIMEOUT):
    t = time.time()
    merged_key = key + ':' + subkey
    res = rdb[db].set(merged_key, val, cache_timeout)
    print 'cache_set time ' + str(time.time() - t)
    return res

cache_set('prefix', 'key_name', 'my glorious value', 0, 20)

これは私が値を取得する方法です:

def cache_get(key, subkey, db, _eval=False):
    t = time.time()
    merged_key = key + ':' + subkey
    val = rdb[db].get(merged_key)
    if _eval:
        if val:
            val = eval(val)
        else:  # None
            val = 0
    print 'cache_get time ' + str(time.time() - t)
    return val

cache_get('prefix', 'key_name', 0)

バージョン:

  • uWSGI: 2.0.5.1
  • フラスコ: 0.11.1
  • redis-py: 2.10.5
  • レディス: 2.8.24

したがって、結論は次のとおりです。

  1. 14 台のサーバーが接続され、それぞれに 4 つのプロセスがあり、それぞれが redis クラスター内の 8 つの異なるデータベースへの接続を開くと、AWS クライアントの数が少なくなる理由
  2. リクエストの応答時間が長くなる原因は何ですか?
  3. 高負荷時の ElastiCache や uWSGI のパフォーマンスに関するアドバイスをいただければ幸いです。
4

1 に答える 1

2

簡潔な答え

したがって、私の場合、問題は Elasticache リクエストではなく、uWSGI メモリ使用量でした。

長い答え

このセットアップでuwsgitopをインストールしました:

### Stats
### ---
### disabled by default
### To see stats run: uwsgitop /tmp/uwsgi_stats.socket
### uwsgitop must be install (pip install uwsgitop)
stats = /tmp/uwsgi_stats.socket

これにより、uwsgi 統計が uwsgitop に公開されます。

次に、loader.ioを使用して、1 秒あたり 350 ~ 500 リクエストでアプリケーションのストレス テストを行いました。

以前の構成で発見したことは、メモリが詰まるまで uWSGI ワーカーの使用メモリ サイズが増加し続け、その後 CPU が急上昇したことです。再スポーンが必要な新しいワーカーも CPU を要求し、サーバーに何らかの過負荷を引き起こしました。これにより、nginx がタイムアウトし、それらの接続が閉じられました。

そのため、以下のセットアップを取得するまで、いくつかの調査と構成の変更を行いました.

* 私のアプリケーションは (まだいくつか使用している) ディスク ピクルされた dat ファイルを使用していました。

将来それを見るかもしれない人のために-迅速な対応が必要な場合-できる限りすべてを非同期にします。たとえば、可能であれば、すべてのデータベース リクエストに celery+rabbitmq を使用します

uWSGI 構成:

listen = 128
processes = 8
threads = 2
max-requests = 10000
reload-on-as = 4095
reload-mercy = 5
#reload-on-rss = 1024
limit-as = 8192
cpu-affinity = 3
thread-stacksize = 1024
max-fd = 250000
buffer-size = 30000
thunder-lock = true
vacuum = true
enable-threads = true
no-orphans = true
die-on-term = true

NGINX 関連パーツ:

user nginx;
worker_processes 4;
worker_rlimit_nofile 20000;
thread_pool my_threads threads=16;
pid /run/nginx.pid;

events {
    accept_mutex off;
    # determines how much clients will be served per worker
    # max clients = worker_connections * worker_processes
    # max clients is also limited by the number of socket connections available on the system (~64k)
    worker_connections 19000;

    # optmized to serve many clients with each thread, essential for linux -- for testing environment
    use epoll;

    # accept as many connections as possible, may flood worker connections if set too low -- for testing environment
    multi_accept on;
}

http {
    ...
    aio                     threads;
    sendfile                on;
    sendfile_max_chunk      512k;
    tcp_nopush              on;
    tcp_nodelay             on;
    keepalive_timeout       5 5;
    keepalive_requests      0;
    types_hash_max_size     2048;
    send_timeout            15;
    ...
}

それが役に立てば幸い!

于 2017-02-26T15:01:23.257 に答える