gpt4 book ai didi

mysql - 当查询复杂时,Flask/MySQL 应用程序似乎会阻止并发请求

转载 作者:行者123 更新时间:2023-11-29 04:50:48 26 4
gpt4 key购买 nike

我有一个简单的单页 Flask (v0.8) 应用程序,它查询 MySQL 数据库并根据不同的请求参数显示每个请求的结果。该应用程序使用 Tornado 而非 Nginx 提供服务。

最近我注意到,当数据库查询仍在运行时,应用程序似乎会阻止来自不同客户端的并发请求。例如 -

  1. 客户端发出复杂的数据库查询请求,需要一段时间(> 20 秒)才能完成。
  2. 另一个客户端向服务器发出请求并被阻止,直到第一个查询返回。

所以基本上,应用程序的行为就像一个为所有人服务的单一进程。我认为问题出在服务器上的共享数据库连接上,所以我开始使用 dbutils 模块进行连接池。那没有帮助。我想我可能在架构或服务器配置中遗漏了一些重要的东西,所以我很感激任何对此的反馈。

这是执行数据库查询的 Flask 代码(简化):

#... flask imports and such

import MySQLdb
from DBUtils.PooledDB import PooledDB

POOL_SIZE = 5

class DBConnection:

def __init__(self):
self.pool = PooledDB(MySQLdb,
POOL_SIZE,
user='admin',
passwd='sikrit',
host='localhost',
db='data',
blocking=False,
maxcached=10,
maxconnections=10)

def query(self, sql):
"execute SQL and return results"

# obtain a connection from the pool and
# query the database
conn = self.pool.dedicated_connection()
cursor = conn.cursor()
cursor.execute(sql)

# get results and terminate connection
results = cursor.fetchall()
cursor.close()
conn.close()
return results


global db
db = DBConnection()

@app.route('/query/')
def query():
if request.method == 'GET':
# perform some DB querying based query params
sql = process_request_params(request)
results = db.query(sql)
# parse, render, etc...

这是 Tornado 包装器 (run.py):

#!/usr/bin/env python
import tornado
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from myapplication import app
from tornado.options import define, options

define("port", default=8888, help="run on the given port", type=int)

def main():
tornado.options.parse_command_line()
http_server = HTTPServer(WSGIContainer(app), xheaders=True)
http_server.listen(options.port)
IOLoop.instance().start()

if __name__ == '__main__': main()

通过启动脚本启动应用:

#!/bin/sh
APP_ROOT=/srv/www/site
cd $APP_ROOT
python run.py --port=8000 --log_file_prefix=$APP_ROOT/logs/app.8000.log 2>&1 /dev/null
python run.py --port=8001 --log_file_prefix=$APP_ROOT/logs/app.8001.log 2>&1 /dev/null

这是 nginx 配置:

user nginx;
worker_processes 1;

error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
use epoll;
}

http {
upstream frontends {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
}

include /usr/local/nginx/conf/mime.types;
default_type application/octet-stream;

# ..

keepalive_timeout 65;
proxy_read_timeout 200;
sendfile on;

tcp_nopush on;
tcp_nodelay on;

gzip on;
gzip_min_length 1000;
gzip_proxied any;
gzip_types text/plain text/html text/css text/xml application/x-javascript
application/xml application/atom+xml text/javascript;

proxy_next_upstream error;

server {
listen 80;
root /srv/www/site;

location ^~ /static/ {
if ($query_string) {
expires max;
}
}

location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://frontends;
}

}
}

这是一个小型应用程序,服务于非常小的客户群,其中大部分是我继承的遗留代码,从来没有时间修复或重写。我只是在添加了需要更长时间才能完成的更复杂的查询类型之后才注意到这个问题。如果有任何问题,我将不胜感激您的反馈。谢谢。

最佳答案

连接池不会使 MySQLdb 异步。 results = cursor.fetchall() 阻塞 Tornado,直到查询完成。

这就是在 Tornado 中使用非异步库时发生的情况。 Tornado 是一个 IO 循环;这是一个线程。如果您有一个 20 秒的查询,服务器在等待 MySQLdb 返回时将没有响应。不幸的是,我不知道一个好的异步 python MySQL 库。有some Twisted ones但是它们给 Tornado 应用程序带来了额外的要求和复杂性。

Tornado 人员建议将慢速查询抽象为 HTTP 服务,然后您可以使用 tornado.httpclient 访问该服务。您还可以查看调整查询(>20 秒!),或运行更多 Tornado 进程。或者,您可以切换到具有异步 Python 库(MongoDB、Postgres 等)的数据存储。

关于mysql - 当查询复杂时,Flask/MySQL 应用程序似乎会阻止并发请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11860385/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com