我们有一个具有32个核的大型EC2实例,目前正在运行Nginx、Tornado和Redis,平均每秒提供5000个请求。一切似乎都很正常,但CPU负载已经达到了70%,而且我们需要支持更多的请求。其中一个想法是用uWSGI替换Tornado,因为我们实际上没有使用Tornado的异步特性。
我们的应用程序由一个函数组成,它接收一个JSON(约为4KB),执行一些阻塞但非常快速的操作(Redis),然后返回JSON。
- 代理HTTP请求到Tornado实例之一(Nginx)
- 解析HTTP请求(Tornado)
- 读取POST正文字符串(字符串化的JSON)并将其转换为Python字典(Tornado)
- 从位于同一机器上的Redis(py-redis with hiredis)中获取数据(阻塞)
- 处理数据(Python3.4)
- 在同一台机器上更新Redis(py-redis with hiredis)
- 为响应准备字符串化的JSON(Python3.4)
- 将响应发送给代理(Tornado)
- 将响应发送给客户端(Nginx)
我们认为速度的提升将来自uwsgi协议,我们可以在单独的服务器上安装Nginx,并将所有请求代理到使用uwsgi协议的uWSGI。但是,在尝试所有可能的配置并更改操作系统参数后,我们仍然无法在当前负载下使其正常工作。大多数情况下,nginx日志包含499和502错误。在某些配置中,它停止接收新请求,就像达到了某些操作系统限制。
所以,正如我所说,我们有32个核,60GB的可用内存和非常快的网络。我们没有做重负载的操作,只有非常快速的阻塞操作。在这种情况下,最好的策略是什么?进程、线程、异步?应设置哪些操作系统参数?
当前的配置为:
[uwsgi]
master = 2
processes = 100
socket = /tmp/uwsgi.sock
wsgi-file = app.py
daemonize = /dev/null
pidfile = /tmp/uwsgi.pid
listen = 64000
stats = /tmp/stats.socket
cpu-affinity = 1
max-fd = 20000
memory-report = 1
gevent = 1000
thunder-lock = 1
threads = 100
post-buffering = 1
Nginx配置:
user www-data;
worker_processes 10;
pid /run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
操作系统配置:
sysctl net.core.somaxconn
net.core.somaxconn = 64000
我知道限制太高了,开始尝试每个可能的值。
更新:
我最终采用了以下配置:
[uwsgi]
chdir = %d
master = 1
processes = %k
socket = /tmp/%c.sock
wsgi-file = app.py
lazy-apps = 1
touch-chain-reload = %dreload
virtualenv = %d.env
daemonize = /dev/null
pidfile = /tmp/%c.pid
listen = 40000
stats = /tmp/stats-%c.socket
cpu-affinity = 1
max-fd = 200000
memory-report = 1
post-buffering = 1
threads = 2
%Cpu(s): 7,8 us, 3,3 sy, 0,0 ni, 89,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
(用户/系统/空闲/等待/硬件中断/软件中断/被窃)。请参阅 http://linuxaria.com/howto/understanding-the-top-command-on-linux 了解详细说明。在 top 中按1
键可查看每个单独 CPU 核心的统计信息。 - Freek Wiekmeijer