NGinX背后的AWS Redis + uWSGI - 高负载

Orz*_*Orz 7 python amazon-web-services redis uwsgi redis-py

我正在使用uwsgi + nginx并使用aws elasticache(redis 2.8.24)运行python应用程序(flask + redis-py).

在尝试改善我的应用程序响应时间的同时,我注意到在高负载下(使用loader.io每秒500请求/ 30秒)我正在丢失请求(对于此测试我只使用一台没有负载的服务器平衡器,1个uwsgi实例,4个进程,用于测试). 压力测试

我挖得更深一点,发现在这个负载下,对ElastiCache的一些请求很慢.例如:

  • normal load:cache_set time 0.000654935836792
  • 重载:cache_set时间0.0122258663177 这不会发生在所有请求中,只是随机发生..

我的AWS ElastiCache基于cache.m4.xlarge上的2个节点(默认AWS配置设置).查看过去3小时内连接的当前客户端: aws弹性客户端

我认为这没有意义,因为目前有14台服务器(其中8台具有XX RPS的高流量使用这个集群),我希望看到更高的客户端速率.

uWSGI config(版本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
Run Code Online (Sandbox Code Playgroud)

Nginx只是使用unix socket的uWSGI的web代理.

这是我打开redis连接的方式:

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

这是我设置值的方法,例如:

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)
Run Code Online (Sandbox Code Playgroud)

这就是我获得价值的方式:

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)
Run Code Online (Sandbox Code Playgroud)

版:

  • uWSGI:2.0.5.1
  • 烧瓶:0.11.1
  • redis-py:2.10.5
  • Redis:2.8.24

所以得出结论:

  1. 如果连接了14台服务器,每台有4个进程,并且每个服务器都在redis集群中打开与8个不同数据库的连接,那么为什么AWS客户端数量很少
  2. 是什么导致请求响应时间爬升?
  3. 非常感谢任何关于ElastiCache和/或uWSGI在重载下的性能的建议

Orz*_*Orz 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
Run Code Online (Sandbox Code Playgroud)

这会将 uwsgi 统计信息公开给 uwsgitop。

然后,我使用loader.io以每秒 350-500 个请求对应用程序进行压力测试。

我在之前的配置中发现,uWSGI 工作线程的使用内存大小不断增长,直到内存堵塞,然后 CPU 激增。需要重新生成的新工作人员也需要 cpu,这会导致服务器出现某种过载 - 这会导致 nginx 超时并关闭这些连接。

因此,我做了一些研究和配置修改,直到我设法获得下面的设置,目前每个实例上管理约 650rps,响应时间约 13 毫秒,这对我来说非常好。

* 我的应用程序使用(仍然使用一些)磁盘腌制的 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
Run Code Online (Sandbox Code Playgroud)

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;
    ...
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!