MySQL Deadlock 발생하는 문제(SQLAlchemy)

Apr 1, 2017

Python, Flask 프레임웍으로 개발했던 서비스에서 월초만 되면 API에서 에러가 발생했다. DB는 MySQL, ORM은 SQLAlchemy를 사용했다. API 에러는 다음과 같았다.

ERROR in app: Exception on /XXXX/XXXX [POST]

...

OperationalError: (_mysql_exceptions.OperationalError) (1213, 'Deadlock found when trying to get lock; try restarting transaction') [SQL: u'INSERT INTO ...'] [parameters: (...)]

OperationalError 에러이고, 락을 가져오려고 할 때, Deadlock이 발견됐으니 트랜잭션을 다시 시작하라는 내용이다.

문제가 되는 부분을 찾았다. insert, commit 하는 부분이었다.

session.commit()

그래서 에러 메시지 내용에 따라 예외 처리를 했다.

try:
    session.commit()
except Exception as e:
    session.rollback()
    raise e

이 상태에서 예외를 처리하지 않으면, 다시 말해서 rollback을 하지 않으면 이 API(세션)는 더 이상 DB Select조차 할 수 없다. 그때 발생하는 에러는 다음과 같다.

InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush.

Dead Lock 발생으로 서비스가 되지 않는 문제는 rollback으로 해결했다. 이제 Dead Lock이 걸리는 원인을 찾아야겠다.

일단 2개의 MySQL 이벤트가 있다.

특이사항:

그래서 개발 서버에서 재현하려고 시도했다. jMeter로 API에 Insert를 대량 발생시켰다. 그러나 에러는 발생하지 않았다.

여러 가지 설정도 바꿔봤지만, Dead Lock은 전혀 발생하지 않았다.

개발 서버와 실 서버의 mysql 버전 차이도 영향이 있을까?

실 서버에서는 발생하는데 어째서 개발 서버에서는 발생하지 않을까? 정확한 원인은 찾지 못했다. 이벤트에서 테이블 락을 걸어주고, 프로시저 작업이 끝나면 락을 풀고, 에러가 발생하는지 확인해봐야겠다.