Flask Web App 도킹 후 정기적인 "쿼리 중 MySQL 서버 연결 끊김"
이전에는 다음을 사용하여 독립 실행형 서버에서 실행하던 Flask 웹 앱을 가지고 있습니다.
- 플라스크/SQ라케미
- 마리아DB
- uwsgi
- nginx
스탠드 아론 서버에서는, 이 애플리케이션은 정상적으로 동작했습니다.
그 후, 이 애플리케이션을 2개의 컨테이너에 걸쳐 「도커화」했습니다.
도커라이즈 후 다음 오류가 발생할 수 있습니다(끝에 전체 트레이스백이 게시됩니다).
Lost connection to MySQL server during query
MariaDB 로그에 상세 로깅과 함께 다음 오류가 표시됩니다.
2020-05-10 18:35:32 130 [Warning] Aborted connection 130 to db: 'flspection2' user: 'fl-server' host: '172.19.0.1' (Got an error reading communication packets)
2020-05-10 18:45:34 128 [Warning] Aborted connection 128 to db: 'flspection2' user: 'fl-server' host: '172.19.0.1' (Got timeout reading communication packets)
이것은, 유저가 경험하는 것입니다.502 Bad Gateway
사용자가 페이지를 새로 고치면 문제가 해결되는 경우가 많습니다.이 문제는 랜덤으로 발생합니다.지금까지 마음대로 재현할 수 없었지만, 시간이 지나면 반드시 재현될 것입니다.
원인은 무엇이며 어떻게 해결할 수 있습니까?
내가 한 일:
- MariaDB 컨테이너의 타임아웃이 28800임을 확인.모든 컨테이너를 재기동한 후 28800초 이내에 에러가 발생하고 있기 때문에, 실제로는 타임 아웃의 문제는 아니라고 생각합니다.
- 세트
pool_recycle
할 수 있는 선택권120
- Flask-SQ 확인Lalchemy가 사용하고 있는 것은
scoped_session
이러한 타임아웃 문제를 회피할 수 있습니다. - 변경되었다.
network_mode
디폴트로 설정합니다.이것으로 문제가 해결되지 않았다.
플라스크와 데이터베이스의 접속은 신뢰할 수 없는 것 같습니다만, 도커 컨테이너는 같은 호스트상에서 동작하고 있기 때문에 매우 신뢰할 수 있지 않을까요?
관련 코드:
데이터베이스입니다.화이
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
config.py
class Config:
...
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://username:password@127.0.0.1/database?charset=utf8mb4'
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ENGINE_OPTIONS = {
'pool_recycle': 120
}
...
docker-param.yml
version: "3.7"
services:
db:
restart: "always"
build: ./docker/db
volumes:
- "~/db:/var/lib/mysql"
environment:
MYSQL_ROOT_PASSWORD: "password"
MYSQL_DATABASE: "database"
MYSQL_USER: "user"
MYSQL_PASSWORD: "password"
ports:
- '3306:3306'
nginx-uwsgi-flask:
restart: "always"
depends_on:
- "db"
build:
context: .
dockerfile: ./docker/nginx-uwsgi-flask/Dockerfile
volumes:
- "~/data/fileshare:/fileshare"
ports:
- "80:80"
- "443:443"
network_mode: "host"
트레이스백
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1193, in _execute_context
context)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 509, in do_execute
cursor.execute(statement, parameters)
File "/usr/local/lib/python3.6/site-packages/pymysql/cursors.py", line 170, in execute
result = self._query(query)
File "/usr/local/lib/python3.6/site-packages/pymysql/cursors.py", line 328, in _query
conn.query(q)
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 517, in query
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 732, in _read_query_result
result.read()
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 1075, in read
first_packet = self.connection._read_packet()
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 657, in _read_packet
packet_header = self._read_bytes(4)
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 707, in _read_bytes
CR.CR_SERVER_LOST, "Lost connection to MySQL server during query")
pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query')
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/usr/local/lib/python3.6/site-packages/flask_user/decorators.py", line 132, in decorator
allowed = _is_logged_in_with_confirmed_email(user_manager)
File "/usr/local/lib/python3.6/site-packages/flask_user/decorators.py", line 17, in _is_logged_in_with_confirmed_email
if user_manager.call_or_get(current_user.is_authenticated):
File "/usr/local/lib/python3.6/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/usr/local/lib/python3.6/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/usr/local/lib/python3.6/site-packages/flask_login/utils.py", line 26, in <lambda>
current_user = LocalProxy(lambda: _get_user())
File "/usr/local/lib/python3.6/site-packages/flask_login/utils.py", line 335, in _get_user
current_app.login_manager._load_user()
File "/usr/local/lib/python3.6/site-packages/flask_login/login_manager.py", line 359, in _load_user
return self.reload_user()
File "/usr/local/lib/python3.6/site-packages/flask_login/login_manager.py", line 321, in reload_user
user = self.user_callback(user_id)
File "/usr/local/lib/python3.6/site-packages/flask_user/user_manager.py", line 130, in load_user_by_user_token
user = self.db_manager.UserClass.get_user_by_token(user_token)
File "/usr/local/lib/python3.6/site-packages/flask_user/user_mixin.py", line 51, in get_user_by_token
user = user_manager.db_manager.get_user_by_id(user_id)
File "/usr/local/lib/python3.6/site-packages/flask_user/db_manager.py", line 179, in get_user_by_id
return self.db_adapter.get_object(self.UserClass, id=id)
File "/usr/local/lib/python3.6/site-packages/flask_user/db_adapters/sql_db_adapter.py", line 48, in get_object
return ObjectClass.query.get(id)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 924, in get
ident, loading.load_on_pk_identity)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 1007, in _get_impl
return db_load_fn(self, primary_key_identity)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 250, in load_on_pk_identity
return q.one()
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 2954, in one
ret = self.one_or_none()
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 2924, in one_or_none
ret = list(self)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 2995, in __iter__
return self._execute_and_instances(context)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 3018, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 948, in execute
return meth(self, multiparams, params)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 269, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1060, in _execute_clauseelement
compiled_sql, distilled_params
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1200, in _execute_context
context)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1413, in _handle_dbapi_exception
exc_info
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 265, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 248, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1193, in _execute_context
context)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 509, in do_execute
cursor.execute(statement, parameters)
File "/usr/local/lib/python3.6/site-packages/pymysql/cursors.py", line 170, in execute
result = self._query(query)
File "/usr/local/lib/python3.6/site-packages/pymysql/cursors.py", line 328, in _query
conn.query(q)
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 517, in query
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 732, in _read_query_result
result.read()
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 1075, in read
first_packet = self.connection._read_packet()
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 657, in _read_packet
packet_header = self._read_bytes(4)
File "/usr/local/lib/python3.6/site-packages/pymysql/connections.py", line 707, in _read_bytes
CR.CR_SERVER_LOST, "Lost connection to MySQL server during query")
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query') [SQL: 'SELECT user.is_active AS user_is_active, user.id AS user_id, user.username AS user_username, user.password AS user_password, user.reset_password_token AS user_reset_password_token, user.email AS user_email, user.email_confirmed_at AS user_email_confirmed_at, user.first_name AS user_first_name, user.last_name AS user_last_name \nFROM user \nWHERE user.id = %(param_1)s'] [parameters: {'param_1': 13}] (Background on this error at: http://sqlalche.me/e/e3q8)
이 문제는 에서 이행하여 해결했습니다.mariadb
로의 컨테이너.mysql
아직 근본 원인을 모르겠어요.
풀에 오래된 연결이 있는 것을 제외하려면 다음 작업을 수행합니다.
https://docs.sqlalchemy.org/en/13/core/pooling.html#pool-disconnects 에서
이 접근방식은 접속 체크 아웃프로세스에 약간의 오버헤드를 더하지만, 그렇지 않으면 오래된 풀링 접속으로 인한 데이터베이스 오류를 완전히 제거하는 가장 간단하고 신뢰성 높은 접근방식입니다.발신측 애플리케이션은, 풀로부터 체크 아웃 한 오래된 접속으로부터 회복하기 위해서, 조작의 정리에 신경 쓸 필요는 없습니다.
create_engine()에서 create_engine() 경유로 사용할 수 있는 Pool.pre_ping 인수를 사용하면 체크아웃 시 접속을 비관적으로 테스트할 수 있습니다.pool_pre_ping 인수:
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
사용하고 있는 버전은 알 수 없지만 'SQLALCHEMY_POOL_SIZE'와 'SQLALCHEMY_POOL_RECYCLE'을 설정해 보셨습니까?
저도 멀티 스레드 장고 앱을 가지고 있어서 비슷한 문제에 직면했습니다.스레드 데이터베이스 접속이 끊어졌을 때.장고벌레가 있어요https://code.djangoproject.com/ticket/21597
이 회피책으로 해결할 수 있습니다.
from django.db import connection
def is_connection_usable():
try:
connection.connection.ping()
except:
return False
else:
return True
def do_work():
while(True): # Endless loop that keeps the worker going (simplified)
if not is_connection_usable():
connection.close()
try:
do_a_bit_of_work()
except:
logger.exception("Something bad happened, trying again")
————————————————
版权声明:本文为CSDN博主「orangleliu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lzz957748332/java/article/details/41480417
먼저 데이터베이스 연결을 확인합니다. 연결이 끊어지면 연결이 닫힙니다. 연결을 다시 시도하면 연결이 끊어집니다.
Bkz https://blog.csdn.net/lzz957748332/article/details/41480417
언급URL : https://stackoverflow.com/questions/61665212/periodic-lost-connection-to-mysql-server-during-query-after-dockerizing-flask
'programing' 카테고리의 다른 글
PHP를 사용하여 Google 캘린더에서 읽을 ical 파일을 동적으로 게시하려면 어떻게 해야 합니까? (0) | 2022.11.23 |
---|---|
Eclipse에서 Tomcat을 시작할 때 "SetPropertiesRule" 경고 메시지 (0) | 2022.11.23 |
mysql 랜덤 정수 범위를 가져오려면 어떻게 해야 합니까? (0) | 2022.11.23 |
{this.props.children}에게 소품을 전달하는 방법 (0) | 2022.11.23 |
변수 선언에 'var'를 사용하는 것은 옵션입니까? (0) | 2022.11.23 |