Flask-SocketIO 性能瓶颈-升级后 QueuePool 溢出

Flask-SocketIO 性能瓶颈-升级后 QueuePool 溢出

我会尽量简短,但我有很多代码示例要展示。如果您需要更多背景信息,请告诉我!

我们最近更新了我们的 flask 服务器,以使用 flask socketio 处理 Web 套接字连接。这造成了重大的性能损失(我们使用 k6 对生产服务器进行负载测试,并在 elastic search 中为各个 api 设置了 cloudwatch 日志),这是有道理的,因为您只能为服务器使用 1 个工作器(我们之前使用了 4 个)。

为了解决这个问题,我们调整了 nginx 配置以平衡多个 socketio 服务器的负载。这很有帮助,而且整体性能肯定有所提高。但在某些页面上,页面在 15-45 秒内不会加载。这种情况发生在涉及大量 API(50+)的页面上,我猜这与 sentry 中的这个错误有关,在添加 flask socketio 之前我们从未遇到过这种情况

设置用户时出现一般异常TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30 (Background on this error at: http://sqlalche.me/e/13/3o7r)根据此错误,似乎当同时发出过多请求并达到队列池限制时,服务器会挂起并导致加载时间极慢。因此,增加池大小和最大溢出应该有助于缓解此问题。

问题:如何优化 Flask-SocketIO 设置以消除 QueuePool 溢出错误并恢复以前的性能水平?除了增加资源限制和添加服务器节点之外,是否还应该考虑架构更改或高级技术?

这是 nginx 配置

upstream socketio_nodes {
   # This needs to be enabled for web sockets to work
    ip_hash;

    server 127.0.0.1:5000;
    server 127.0.0.1:5001;
    server 127.0.0.1:5002;
    # to scale the app, just add more nodes here!
}

server {
    listen 80;
    server_name *.our-site.com;

    location / {
        include proxy_params;
    proxy_pass http://socketio_nodes;
    }

    location /socket.io {
        include proxy_params;
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://socketio_nodes/socket.io;
    }
    # Consider blocking access to source maps for security reasons. These will be uploaded to sentry during build.
    # location ~ \.map$ {
    #     deny all;
    # }
}

这是服务器服务

[Unit]
Description=Gunicorn instance to serve our website
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/briefcase
Environment="PATH=/home/ubuntu/briefcaseEnv/bin:/usr/bin:/bin"
ExecStart=/home/ubuntu/briefcaseEnv/bin/gunicorn -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" -w 1 --bind 0.0.0.0:%i --log-level=warning wsgi:app

在这里部署我们启动了三台服务器

sudo systemctl restart [email protected]
sudo systemctl restart [email protected]
sudo systemctl restart [email protected]

如果有帮助的话,这里是 flask socketio 相关逻辑

套接字实例

from flask_socketio import SocketIO, emit
import os


# configure cors_allowed_origins
if os.environ.get('FLASK_ENV') == 'production':
    origins = [
        # app url here
    ]
else:
    # allow all origins for development
    origins = "*"

# initialize your socket instance
# TODO: do we need the async_mode specified? How will this work in production?
socketio = SocketIO(async_mode='gevent', cors_allowed_origins=origins)

在 app.py 中

# monkey patch at the top of the file
from gevent import monkey
monkey.patch_all()
from libs.Sockets.socket_instance import socketio

    socketio.init_app(app, message_queue='amqp://')

    if parsed_args.url_map:
        logging.info('\n\n########################################\n\n')
        logging.info(app.url_map)
        logging.info(
            '\n\n########################################\n^^^ App URL Map ^^^\n')
    socketio.run(app)(port=5000)

如果需要更多背景信息,请告诉我(例如 k6 摘要)

相关内容