gpt4 book ai didi

python - 在 Flask 中使用 pymysql 时出错

转载 作者:可可西里 更新时间:2023-11-01 07:06:51 25 4
gpt4 key购买 nike

我正在使用 pymysql 客户端连接到我的 flask API 中的 mysql,几天(大约 1-2 天)一切正常,然后突然开始抛出此错误

Traceback (most recent call last):
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 1039, in _write_bytes
self._sock.sendall(data)
TimeoutError: [Errno 110] Connection timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "Main.py", line 194, in post
result={'resultCode':100,'resultDescription':'SUCCESS','result':self.getStudentATData(studentId,args['chapterId'])}
File "Main.py", line 176, in getStudentATData
cur.execute("my query")
File "/usr/local/lib/python3.4/dist-packages/pymysql/cursors.py", line 166, in execute
result = self._query(query)
File "/usr/local/lib/python3.4/dist-packages/pymysql/cursors.py", line 322, in _query
conn.query(q)
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 855, in query
self._execute_command(COMMAND.COM_QUERY, sql)
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 1092, in _execute_command
self._write_bytes(packet)
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 1044, in _write_bytes
"MySQL server has gone away (%r)" % (e,))
pymysql.err.OperationalError: (2006, "MySQL server has gone away (TimeoutError(110, 'Connection timed out'))")

如果重新启动应用程序它再次工作正常,我已经尝试了一切但似乎无法摆脱这个,任何人都可以帮忙吗?按照建议,我实现了一种重试机制,但这并没有解决问题

def connect(self):
#db connect here
def cursor(self):
try:
cursor = self.conn.cursor()
except Exception as e:
print(e)
self.connect()
cursor = self.conn.cursor()
return cursor

像 DB().cursor() 一样使用它

最佳答案

首先,你需要决定是否要保持与MySQL的持久连接。后者性能更好,但需要一些维护。

默认 wait_timeout在 MySQL 中是 8 小时。只要连接空闲时间超过 wait_timeout,它就会关闭。当 MySQL 服务器重新启动时,它还会关闭所有已建立的连接。因此,如果您使用持久连接,则需要在使用连接之前检查它是否存在(如果不存在,则重新连接)。如果您使用按请求连接,则不需要维护连接状态,因为连接总是新鲜的。

每个请求连接

对于每个传入的 HTTP 请求,非持久性数据库连接具有明显的打开连接、握手等(对于数据库服务器和客户端)的开销。

这里引用Flask官方教程regarding database connections :

Creating and closing database connections all the time is very inefficient, so you will need to keep it around for longer. Because database connections encapsulate a transaction, you will need to make sure that only one request at a time uses the connection. An elegant way to do this is by utilizing the application context.

但是请注意,应用程序上下文 是根据请求初始化的(这有点被效率问题和 Flask 的行话掩盖了)。因此,它仍然非常低效。但是它应该可以解决您的问题。这是它建议应用于 pymysql 的内容的摘录:

import pymysql
from flask import Flask, g, request

app = Flask(__name__)

def connect_db():
return pymysql.connect(
user = 'guest', password = '', database = 'sakila',
autocommit = True, charset = 'utf8mb4',
cursorclass = pymysql.cursors.DictCursor)

def get_db():
'''Opens a new database connection per request.'''
if not hasattr(g, 'db'):
g.db = connect_db()
return g.db

@app.teardown_appcontext
def close_db(error):
'''Closes the database connection at the end of request.'''
if hasattr(g, 'db'):
g.db.close()

@app.route('/')
def hello_world():
city = request.args.get('city')

cursor = get_db().cursor()
cursor.execute('SELECT city_id FROM city WHERE city = %s', city)
row = cursor.fetchone()

if row:
return 'City "{}" is #{:d}'.format(city, row['city_id'])
else:
return 'City "{}" not found'.format(city)

持久连接

对于持久连接数据库连接有两个主要选项。您有一个连接池或将连接映射到工作进程。因为通常 Flask WSGI 应用程序由具有固定线程数的线程服务器(例如 uWSGI)提供服务,线程映射更容易和高效。

有一个包裹,DBUtils ,它实现了,和 PersistentDB用于线程映射连接。

维护持久连接的一个重要警告是事务。重新连接的A​​PI是ping .自动提交单语句是安全的,但它可能会在事务之间中断(更多细节 here )。 DBUtils 会处理这个问题,并且应该只在 dbapi.OperationalErrordbapi.InternalError 上重新连接(默认情况下,由 failures 控制到 的初始化程序code>PersistentDB) 在事务之外引发。

下面是使用 PersistentDB 时上面的代码片段的样子。

import pymysql
from flask import Flask, g, request
from DBUtils.PersistentDB import PersistentDB

app = Flask(__name__)

def connect_db():
return PersistentDB(
creator = pymysql, # the rest keyword arguments belong to pymysql
user = 'guest', password = '', database = 'sakila',
autocommit = True, charset = 'utf8mb4',
cursorclass = pymysql.cursors.DictCursor)

def get_db():
'''Opens a new database connection per app.'''

if not hasattr(app, 'db'):
app.db = connect_db()
return app.db.connection()

@app.route('/')
def hello_world():
city = request.args.get('city')

cursor = get_db().cursor()
cursor.execute('SELECT city_id FROM city WHERE city = %s', city)
row = cursor.fetchone()

if row:
return 'City "{}" is #{:d}'.format(city, row['city_id'])
else:
return 'City "{}" not found'.format(city)

微基准

为了从数字上给出一些性能影响的线索,这里是微基准。

我跑了:

  • uwsgi --http :5000 --wsgi-file app_persistent.py --callable app --master --processes 1 --threads 16
  • uwsgi --http :5000 --wsgi-file app_per_req.py --callable app --master --processes 1 --threads 16

并通过并发 1、4、8、16 对它们进行负载测试:

siege -b -t 15s -c 16 http://localhost:5000/?city=london

chart

观察结果(针对我的本地配置):

  1. 持久连接快约 30%,
  2. 在并发度 4 及更高时,uWSGI 工作进程的峰值超过 100% 的 CPU 使用率(pymysql 必须在纯 Python 中解析 MySQL 协议(protocol),这是瓶颈),
  3. 在并发 16 时,mysqld 的 CPU 利用率对于每个请求约为 55%,对于持久连接约为 45%。

关于python - 在 Flask 中使用 pymysql 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47711689/

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