zmq.error.ZMQError: Interrupted system call 해결

python 애플리케이션에서 다음 에러가 발생했다.

이 내용이 중요한 것 같다.

zmq.error.ZMQError: Interrupted system call

환경:

  • CentOS release 5.8 (Final)

Centos 6에서는 문제가 없는 앱이었는데, Centos 5에서만 이런 문제가 생겼다. 그래서 trace를 하게 되었다.

app.py는 다음과 같이 하나의 스레드로 0mq 소켓으로 수신 받고 있었다. strace를 하면 아래에 표시된 부분에서 에러가 발생했다.

다음과 같이 두 개의 터미널을 띄워놓고, 순서대로 커맨드를 실행했다.

try로 에러코드를 확인했다.

4번을 표준 errno 시스템 심볼을 확인하니 다음으로 나타났다.

errno.EINTR

Interrupted system call

Centos 6에서는 문제가 발생하지 않았다.

Centos 5에서는 strace 할 때 무엇인가 signal을 보내면서 문제가 발생하는 것으로 보인다. 그래서 우선 예외처리하는 것으로 문제를 해결했다.

 

Python에서 Signal 처리

Python 스크립트가 예기치 않게 종료했을 때, 어떤 signal에 의해 종료되었는지를 확인이 필요한 경우가 있다.  다음 코드를 변형해서 프로그램에 맞게, 적절히 적용할 수 있다.

이 외에도 종료되는 시점에 무엇인가 실행할 필요가 있을 때는 atexit를 사용 할 수 있다.

 

Python 개발 노트

Python으로 개발하면서 작성한 메모로, 기본적인이지만 오랜만에 Python을 사용할 때 참고할 만한 내용을 적어봤다. Python 2.7 버전 기준이다.

if문

예외처리

버전 알아내기

SQLAlchemy

SQLAlchemy는 Python에서 인기있는 ORM 모듈이다.

Flask

Flask는 가벼운 Python 웹프로임웍이다. RESTful API를 아주 쉽고 간단하게 만들 수 있다.

API의 예외 처리

Implementing API Exceptions 페이지에 아주 잘 나타나있다.

우선 예외 클래스를 만든다.

어떤 API에서 예외가 발생했을 때 표시할 페이지의 응답부분을 만든다.

이제 API에서 예외가 발생했을 때, invalidUsage 클래스를 사용해서 예외를 전파하면 된다.

Jsonify 에러

Flask의 이와 관련한 이슈에 따르면 simplejson을 설치하면 자동으로 jsonify가 그것을 사용한다고 했다.

PIP

설치

사용

에러

DistributionNotFound

setuptools를 설치한다.

MySQL Deadlock 발생하는 문제(Sqlalchemy)

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

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

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

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

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

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

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

  • 이벤트 A : 월마다 한 번 오전 9시에 A 테이블에 파티션 추가하는 프로시저 실행
  • 이벤트 B : 매일 한 번 오전 11시에 B 테이블에 파티션 추가하는 프로시저 실행

특이사항은:

  • 스토리지 엔진은 MyISAM.
    • 엔진 자체가 트랜잭션을 지원하지 않으므로, Sqlalchemy가 애플리케이션 단에서 처리하는 것 같음.
  • 매일 11시에 INSERT가 많이 발생한다.
  • lock 걸렸는지 확인한 결과 문제가 없었다.
  • 에러가 발생하고, Wait 상태인 프로세스도 없었다.
  • API만 재시작하면 정상 동작한다. 이것은 그 세션만 문제라는 얘기다.

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

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

  • concurrent_insert
  • table_lock_wait_timeout

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

  • Development : 5.1.73-log
  • Production 5.5.27-log

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