Flask 在 cheroot/gunicorn 上的可扩展性

Flask 在 cheroot/gunicorn 上的可扩展性

我已经使用 flask 开发了一个 HTTP API 端点,它接受 POST 请求上的 json 数据并返回 json 响应。

我尝试过使用多个 WSGI 服务器:gunicorn、cheroot、Nginx 后面的 Bjoern 作为反向代理。

我注意到,无论我使用哪个 WSGI 服务器,应用程序都无法处理每秒 500 个请求的持续负载。突然增加 500 个请求时可以很好地处理。但持续增加时则不行。请求开始延迟响应,并且相当多的请求会超时。

flask web 部署在一台 24 核物理服务器上。因此它有 48 个逻辑核心。我正在另一台类似的 24 核服务器上使用 C++ 应用程序异步触发这些请求。每 2ms 一个请求,因此每秒 500 个。

考虑以下我在 cheroot WSGI 服务器上创建的简单单文件 flask 应用程序的示例,以对性能进行基准测试。它仅记录请求 json 并返回响应 json。即使这样也无法在强大的 24 核物理服务器上处理 500 个请求的持续负载。测试期间 CPU 使用率始终低于 5%。

import os
import json
import logging
from logging.handlers import TimedRotatingFileHandler
from flask import Flask
from flask import request, jsonify
from cheroot.wsgi import PathInfoDispatcher
from cheroot.wsgi import Server

app = Flask(__name__)

# Setup logger for the app
if not os.path.exists('logs'):
        os.mkdir('logs')
file_handler = TimedRotatingFileHandler('logs/simpleflaskapp.log', when='midnight', interval=1, backupCount=10)
file_handler.setFormatter(logging.Formatter(
    '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)

app.logger.setLevel(logging.INFO)
app.logger.info("simpleflaskapp startup")
# end setup logger

@app.route( '/test', methods = [ 'POST' ] )
def test():
    app.logger.info(json.dumps(request.json))
    res = {
        "statusCode": 200,
        "message": "OK",
    }
    return jsonify(res)

d = PathInfoDispatcher({'/': app})
server = Server(('0.0.0.0', 8000), d, numthreads=os.cpu_count(), request_queue_size=int(os.cpu_count()/2))

if __name__ == '__main__':
    try:
        server.start()
    except KeyboardInterrupt:
        server.stop()

博客文章的作者https://www.appdynamics.com/blog/engineering/a-performance-analysis-of-python-wsgi-servers-part-2/能够在 2 核机器上每秒处理数千个请求。我做错了什么?

通过注释掉上述示例应用程序中的日志记录来消除磁盘 IO,我能够达到每秒 666 个请求。但不会更多了。考虑到我运行它的硬件,这仍然很低。

我已经检查了 Nginx 配置,它配置为处理更高的负载。我还尝试跳过 Nginx 直接向 WSGI 服务器发送请求,但结果更糟。

答案1

回答我自己的问题。

在尝试了各种使用 flask 的 WSGI 服务器但无果后,我决定试试 cherrypy。结果发现它也有类似的并发限制。

然后我遇到了萨尼奇。我在 sanic 上编写了相同的测试应用程序,并且能够持续处理每秒 10,000 个请求。

现在将我的项目从 flask 迁移到 sanic。

相关内容