从多个uWSGI工作程序查询MySQL返回不匹配的行

时间:2016-10-19 18:01:25

标签: python mysql flask uwsgi pymysql

我正在使用带有多个工作人员的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!!!

1 个答案:

答案 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参数,该参数强制在创建每个工作程序时运行所有代码。