2016-11-27 9 views
7

Я запускаю приложение python (фляга + redis-py) с uwsgi + nginx и используя aws elasticache (redis 2.8.24).AWS Redis + uWSGI за NGINX - высокая нагрузка

При попытке улучшить время отклика приложения, я заметил, что при высокой нагрузке (500 запросов в секунду/в течение 30 секунд с использованием loader.io) я теряю запросы (для этого теста я использую только один сервер без балансировки нагрузки, 1 экземпляр uwsgi, 4 процесса, предназначенные для тестирования). stress test

Я углубился и узнал, что под этой нагрузкой некоторые запросы к ElastiCache медленны. , например:

  • нормальная нагрузка: время cache_set +0,000654935836792
  • тяжелая нагрузка: время cache_set 0.0122258663177 этого не происходит для всех запросов, просто случайно occurres ..

Моего AWS ElastiCache основан на 2 узлах на cache.m4.xlarge (настройки конфигурации AWS по умолчанию). См текущих клиентов, подключенных в течение последних 3-х часов: aws elasticache clients

Я думаю, что это не имеет смысла, так как в настоящее время 14 серверов (8 из них с высокой интенсивностью движения ХХ 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 является только веб-прокси uWSGI с помощью UNIX сокета.

Это, как я открыть соединение с 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-ру: 2.10.5
  • Redis: 2.8.24

Итак вывод:

  1. Почему клиенты AWS считаются низкими, если подключено 14 серверов, каждый из которых имеет 4 процесса, и каждый из них открывает соединение с 8 различными базами данных в кластере redis
  2. Что заставляет время отклика запросов подниматься?
  3. бы оценить какие-либо рекомендации относительно ElastiCache и/или производительность uWSGI при большой нагрузке
+0

Orz, смогли ли вы найти решение? Я столкнулся с той же проблемой. Буквально ... nginx + flask + uwsgi все в порядке, но поскольку я добавил redis на Elasticache, я столкнулся с проблемами длительных запросов в Elasticache. – camelCase

ответ

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 для стресс-тестирования приложения с 350-500 запросами в секунду.

Что я обнаружил в своей предыдущей конфигурации, так это то, что работники uWSGI продолжали расти в объеме используемой памяти до тех пор, пока память не задохнулась, а затем процессор упал. новым работникам, которые нуждались в повторном появлении, также требовался процессор, который вызывал некоторую перегрузку на серверах, что вызвало тайминги nginx и закрытие этих соединений.

Так что я сделал некоторые исследования и модификацию конфигурации, пока мне не удалось получить установку ниже, которая в настоящее время управляет ~ 650rps в каждом экземпляре с временем отклика ~ 13 мс, что отлично подходит для меня.

* Мое приложение используется (до сих пор использует некоторые) диск маринованных DAT-файлы, некоторые из них были тяжелыми для загрузки - Я уменьшил диск зависимость минимальный *

Для тех, кто мог видеть его в будущем - если вам нужны быстрые ответы - асинхронизируйте все, что сможете. для бывшего, используйте сельдерей + 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; 
    ... 
} 

Надеется, что это помогает!

 Смежные вопросы

  • Нет связанных вопросов^_^