首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >uWSGI python高负载配置

uWSGI python高负载配置
EN

Stack Overflow用户
提问于 2015-04-06 20:22:08
回答 1查看 10.4K关注 0票数 13

我们有一个包含32个核心的大型EC2实例,目前运行的是Nginx、旋风和Redis,平均每秒提供5K请求。一切似乎都很好,但CPU负载已经达到70%,我们必须支持更多的请求。其中一个想法是用uWSGI取代旋风,因为我们并没有真正使用龙卷风的异步特性。

我们的应用程序由一个函数组成,它接收一个JSON (~=4KB),执行一些阻塞但速度非常快的操作(Redis)并返回JSON。

  • 对龙卷风实例之一的代理HTTP请求(Nginx)
  • 解析HTTP请求(旋风)
  • 读取POST body string (字符串化JSON)并将其转换为python字典(旋风)
  • 从位于同一台机器(py-redis和hiredis)的Redis (阻塞)中提取数据。
  • 处理数据(python3.4)
  • 在同一台机器上更新Redis (py-redis和hiredis)
  • 准备用于响应的字符串化JSON (python3.4)
  • 向代理发送响应(龙卷风)
  • 向客户端发送响应(Nginx)

我们认为速度的提高将来自于uwsgi协议,我们可以在单独的服务器上安装Nginx,并使用uWSGI协议代理所有对uwsgi的请求。但是,在尝试了所有可能的配置和更改操作系统参数之后,即使在当前负载下,我们仍然无法使它工作。大多数情况下,nginx日志包含499和502错误。在一些配置中,它只是停止接收新的请求,就像它达到了一些OS限制一样。

因此,正如我所说,我们有32个核心,60 as的空闲内存和非常快的网络。我们不做重物,只做非常快的封堵操作。在这种情况下,最好的策略是什么?进程,线程,异步?应该设置哪些操作系统参数?

目前的配置是:

代码语言:javascript
复制
[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配置:

代码语言:javascript
复制
user www-data;
worker_processes 10;
pid /run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;
    use epoll;
}

OS配置:

代码语言:javascript
复制
sysctl net.core.somaxconn
net.core.somaxconn = 64000

我知道极限太高了,开始尝试每一个可能的价值。

更新

最后,我得到了以下配置:

代码语言:javascript
复制
[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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-07 14:17:51

我认为您的请求处理大致如下:

  • HTTP解析,请求路由,JSON解析
  • 执行生成redis请求的python代码
  • (阻塞) redis请求
  • 执行一些python代码,处理redis响应。
  • JSON序列化,HTTP响应序列化

您可以在接近空闲的系统上对处理时间进行基准测试。我的预感是往返时间会缩短到2到3毫秒。在70%的CPU负载下,这将增加到大约4或5 ms (不包括在nginx请求队列中花费的时间,仅包括uWSGI工作者中的处理时间)。

在5k req/s时,您的平均进程内请求可能在20 . 25范围内。和你的VM很相配。

下一步是平衡CPU核心。如果您有32个核心,那么分配1000个工作进程是没有意义的。最后,您可能会因为上下文切换开销而阻塞系统。一个很好的平衡将使总工作量(nginx+uWSGI+redis)成为可用的CPU核心,可能会有一些额外的开销来阻塞I/O (即文件系统,但主要是对其他主机(如DBMS)进行网络请求)。如果阻塞I/O成为等式的重要部分,请考虑将其重写为异步代码并集成异步堆栈。

第一个观察:您正在为nginx分配10名员工。然而,nginx在请求上的CPU时间比uWSGI在请求上的时间要低得多。首先,我要将大约10%的系统用于nginx (3或4个工作流程)。

剩下的将不得不在uWSGI和redis之间进行分割。我不知道您的索引在redis中的大小,也不知道python代码的复杂性,但我的第一次尝试是uWSGI和redis之间75%/25%的分割。这将使大约6名工人和uWSGI大约20名工人+一名硕士。

至于uwsgi配置中的线程选项:线程切换比进程切换轻,但是如果您的python代码的很大一部分是CPU绑定的,它将不会因为GIL而运行。如果您处理时间的很大一部分被I/O阻塞,那么线程选项主要是有趣的。您可以禁用线程,或者尝试使用workers=10、threads=2作为初始尝试。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29479041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档