我正在使用带有多个工作人员的uWSGI运行的Flask应用程序对MySQL数据库运行查询。我注意到有时当我通过id查询资源时,返回行的id与我查询的id不同。
我认为查询隔离意味着这是不可能的。但是,似乎MySQL正在混淆查询。我不能在不使用uWSGI时重现这一点,但这可能只是因为它在本身测试Flask服务器时在localhost而不是服务器上运行。
为什么输入ID和结果ID不匹配?
from flask import Flask
import pymysql.cursor, random
class Database:
def __init__(self, user, password, host, database):
self.connection = pymysql.connect(
user=user,
password=password,
host=host,
database=database,
cursorclass=pymysql.cursors.DictCursor
)
def query(self, sql, **kwargs):
with self.connection.cursor() as cursor:
cursor.execute(sql, kwargs)
return cursor
app = Flask(__name__)
database = Database('user', 'password', 'localhost', 'database')
@app.route('/resources/<path:id>')
def resource(id):
item = database.query(
'SELECT resources.id FROM resources WHERE resources.id = %(id)s',
id=id
).fetchone()
identifier = random.random()
print(identifier, 'ID 1:', id)
print(identifier, 'ID 2:', item['id'])
if int(item['id']) != int(id):
print('Error found!!!')
return 'Done', 200
if __name__ == '__main__':
app.run()
[pid: 2824|app: 0|req: 1/1] xxx.xxx.xxx.xxx () {44 vars in 737 bytes} [Wed Oct 19 18:38:07 2016] GET /resources/10 => generated 4 bytes in 6 msecs (HTTP/1.1 200) 2 headers in 78 bytes (1 switches on core 0)
0.687535338604848 ID 1: 11
0.687535338604848 ID 2: 11
[pid: 2821|app: 0|req: 1/2] xxx.xxx.xxx.xxx () {44 vars in 737 bytes} [Wed Oct 19 18:38:07 2016] GET /resources/11 => generated 4 bytes in 5 msecs (HTTP/1.1 200) 2 headers in 78 bytes (1 switches on core 0)
0.9216930740141296 ID 1: 13
0.9216930740141296 ID 2: 13
[pid: 2823|app: 0|req: 1/3] xxx.xxx.xxx.xxx () {44 vars in 737 bytes} [Wed Oct 19 18:38:07 2016] GET /resources/13 => generated 4 bytes in 6 msecs (HTTP/1.1 200) 2 headers in 78 bytes (1 switches on core 0)
0.9053128320497649 ID 1: 12
0.9053128320497649 ID 2: 14
Error found!!!
0.794023616025622 ID 1: 15
0.794023616025622 ID 2: 15
[pid: 2824|app: 0|req: 2/4] xxx.xxx.xxx.xxx () {44 vars in 737 bytes} [Wed Oct 19 18:38:07 2016] GET /resources/15 => generated 4 bytes in 1 msecs (HTTP/1.1 200) 2 headers in 78 bytes (1 switches on core 0)
[pid: 2822|app: 0|req: 1/5] xxx.xxx.xxx.xxx () {44 vars in 737 bytes} [Wed Oct 19 18:38:07 2016] GET /resources/12 => generated 4 bytes in 31 msecs (HTTP/1.1 200) 2 headers in 78 bytes (1 switches on core 0)
0.3608322871408709 ID 1: 14
0.3608322871408709 ID 2: 16
Error found!!!
[pid: 2825|app: 0|req: 1/6] xxx.xxx.xxx.xxx () {44 vars in 737 bytes} [Wed Oct 19 18:38:07 2016] GET /resources/14 => generated 4 bytes in 18 msecs (HTTP/1.1 200) 2 headers in 78 bytes (1 switches on core 0)
0.8346421078513786 ID 1: 16
0.8346421078513786 ID 2: 17
Error found!!!
答案 0 :(得分:0)
对于遇到此问题的其他人,我找到了以下解决方案。
根据http://uwsgi-docs.readthedocs.io/en/latest/ThingsToKnow.html。
uWSGI尽可能尝试(ab)使用fork()调用的Copy On Write语义。默认情况下,它会在加载应用程序之后进行分叉,以尽可能多地共享内存。如果出于某种原因不希望出现此行为,请使用lazy-apps选项。这将指示uWSGI在每个worker的fork()之后加载应用程序。
在看了uWSGI, Flask, sqlalchemy, and postgres: SSL error: decryption failed or bad record mac之后,我意识到我的问题与创建多个进程的事实有关。
但是,因为uWSGI默认情况下从一个主工作程序加载所有进程(并且每次都不运行整个Flask应用程序),所以所有工作人员最终共享数据库连接(不会结束好!)。
解决方案是包含lazy-apps
参数,该参数强制在创建每个工作程序时运行所有代码。