我们有一个具有32个内核的大型EC2实例,当前正在运行Nginx,Tornado和Redis,平均每秒处理5000个请求。一切似乎都可以正常工作,但CPU负载已达到70%,我们必须支持更多请求。一种想法是用uWSGI替换Tornado,因为我们实际上并没有使用Tornado的异步功能。
我们的应用程序由一个函数组成,它接收一个JSON(〜= 4KB),进行一些阻塞但非常快速的操作(Redis),并返回JSON。
我们认为速度的提高将来自uwsgi协议,我们可以将Nginx安装在单独的服务器上,并使用uwsgi协议将所有请求代理到uWSGI。但是,在尝试了所有可能的配置并更改了OS参数之后,即使在当前负载下,我们仍然无法使其正常运行。大多数时候,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
我认为您的请求处理大致分为以下几类:
您可以在接近闲置的系统上确定处理时间。我的直觉是往返将花费2到3毫秒。在70%的CPU负载下,这可能会增加大约4或5毫秒(不计算花费在nginx请求队列中的时间,仅是uWSGI worker中的处理时间)。
在5k req / s时,您的平均进程内请求可能在20 ... 25范围内。与您的VM相称的游戏。
下一步是平衡CPU内核。如果您有32个内核,则分配1000个工作进程是没有意义的。您可能最终因上下文切换开销而使系统受阻。一个良好的平衡将使可用的CPU内核数量上的工作总量(nginx + uWSGI + redis)达到数量级,也许还有一些额外的功能可以覆盖阻止I / O(即文件系统,但主要是完成网络请求)到其他主机(如DBMS)。如果阻塞I / O成为方程式的重要组成部分,请考虑将其重写为异步代码并集成异步堆栈。
初步观察:您正在向nginx分配10个工作程序。但是,nginx在请求上花费的CPU时间比uWSGI在请求上花费的时间低很多。我将从将大约10%的系统专用于nginx(3或4个工作进程)开始。
其余的必须在uWSGI和Redis之间分配。我不知道您在redis中的索引大小,也不知道您的python代码的复杂性,但是我的第一次尝试是在uWSGI和redis之间进行75%/ 25%的分配。这将使redis约6名工人和uWSGI约20名工人+一个大师。
至于uwsgi配置中的threads选项:线程切换比进程切换轻,但是如果您的python代码的很大一部分受CPU限制,则由于GIL而不会运行。如果很大一部分处理时间被I / O阻塞,则线程选项将非常有趣。您可以禁用线程,或者尝试使用worker = 10,thread = 2作为初始尝试。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句