[SQLAlchemy] Lost connection to MySQL server during query
문제 상황
MySQLdb.OperationalError : (2013, ‘Lost connection to MySQL server during query’)
몇초 내로 응답이 나가는 일반적인 요청이 아닌 분 단위로 걸리는 요청을 처리하다보니 세션이 끊기는 현상이 있었다.
trackback에 나오는 애러 발생 로직들은 서버 로직에서 출발한게 아니었고, 에러 메시지를 보니 커넥션 이슈라고 생각이 들었다.
생각해보니 DB 커넥션 설정을 별도로 수정하지 않고 사용해왔고, 오래 걸리는 작업이 최근에 부쩍 늘게 돼서 이제야 마주칠 수 있던
이슈는 아니었을까 생각이 들었다.
해결 방법
pool_pre_ping 설정하기
pool_pre_ping
을 True로 설정하면 연결하기 전에 말 그대로 ping을 날려서 연결이 유효한지 확인한다. (SELECT 1)
유효하지 않으면 커넥션 풀에서 유효한 커넥션으로 가져와 재연결을 시도한다.
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
pool_recycle을 MySQL의 wait_timeout보다 작게 설정하기
문제 상황에서 오래 걸리는 요청이 있다고 언급했었는데, 작업 중간에 연결이 유효한지 주기적으로 확인하고 갱신할 필요가 있었다.
그래서 pool_recycle
을 설정해줬으며 이때 MySQL의 wait_timeout
설정값 보다는 작아야 한다.
wait_timeout
이 커넥션을 유지하는 최대 시간이니까 그 시간동안 주기적으로 체크하기 위함이다!
engine = create_engine(
"mysql+pymysql://user:pw@host/db", pool_recycle=3600)
- MySQL 설정은
my.cnf
에서 설정했다. wait_timeout
의 기본값은 8시간이다.
wait_timeout을 늘리기
어떤 서비스인지에 따라 다르겠지만,wait_timeout
이 너무 늘면 DB의 커넥션 풀을 고갈시킬 수 있어서 좋지 않다.
(일반적인 서비스라면 wait_timeout
값은 작게 설정하는게 옮다고 개인적으로 생각한다)
다만 트래픽이 적은 케이스이고 작업이 오래 걸린다면 wait_timeout
을 늘리는 것도 필요하다.
wait_timeout
을 줄인다면 오래 걸리는 작업은 완료되지 않으니까 말이다.
보통은 기본값인 8시간이면 다 처리될텐데 임의로 과도하게 줄여놓은 상황이라면 이 부분도 점검해보면 좋을 것 같다.
(참고) Flask-SQLAlchemy 설정
참고로 Flask-SQLAlchemy
를 사용하고 있다면 SQLALCHEMY_POOL_RECYCLE
말고 SQLALCHEMY_ENGINE_OPTIONS
를 설정하자.
SQLALCHEMY_POOL_RECYCLE
는 v2.4에서 deprecated 되었다.
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
'pool': QueuePool(creator),
'pool_size': 10,
'pool_recycle': 120,
'pool_pre_ping': True
}
댓글남기기