-
ssl error decryption failed or bad record mac 에러는 PostgreSQL의 isolation level을 설정할 때에 나는 에러입니다.
self.conn.set_isolation_level(_ext.ISOLATION_LEVEL_AUTOCOMMIT) 과 같은 로직이 있는데 해당 부분이 에러를 낼 때도 있고 내지 않을 때도 있습니다.
원인
이 문제는 uWSGI의 fork가 끝날 때 발생합니다. 마스터 프로세스로 여러 프로세스들에 대해 작업이 진행될 때, uWSGI는 마스터 프로세스 내의 어플리케이션들을 초기화하고 각각의 worker 프로세스로 어플리케이션을 복사합니다. 여기서 문제는 만약 어플리케이션을 초기화 할 때, 데이터베이스의 connection이 open된다면 여러 프로세스들이 동일한 연결을 공유하게 되어 ssl error decryption failed or bad record mac와 같은 에러를 발생하게 됩니다.
해결책
이 문제에 대한 해결책은 uWSGI의 config파일에 lazy 옵션을 지정하여 각 프로세스에서 어플리케이션을 완전히 로딩이 되도록 강요하는 것입니다.
uWSGI 옵션
lazy
lazy mode ( 마스터가 아닌 worker들의 어플리케이션을 로드)
이 옵션은 Copy-on-Write 의미가 아닌, 메모리를 사용하는 의미를 가집니다. lazy 모드가 활성화 되면, worker들은 uWSGI의 reload 신호에 의해 reload됩니다. 이때 master는 여전히 살아있는 상태입니다. 따라서 uWSGI의 config 파일의 변경내용은 master가 reload할 때 worker들이 선택되지 않습니다. 해당 옵션은 좋은 방법이 아니므로 lazy-apps 옵션 사용을 권장합니다.
lazy-apps
master가 아닌 각 worker들의 어플리케이션을 로드
이 옵션은 Copy-on-Write 의미가 아닌, 메모리를 사용하는 의미를 가집니다. lazy옵션과는 달리, 이 옵션은 어플리케이션이 로드되는 방식에만 영향을 주며, reload 시 master의 동작에는 영향을 주지 않습니다.
config 파일 예제
[uwsgi] # Django-related settings # the base directory (full path) chdir = /home/api/api # Django's wsgi file module = base.wsgi:application # process-related settings # master master = true # maximum number of worker processes processes = 4 # the socket (use the full path to be safe) socket = /home/uwsgi/uwsgi.sock # ... with appropriate permissions - may be needed chmod-socket = 666 # clear environment on exit vacuum = true env = DJANGO_SETTINGS_MODULE=base.settings.dev daemonize = /var/log/superbook.log # the fix 아래 추가 lazy = true # 해당 옵션은 낡은 방법으로 아래 옵션을 추가하는 것을 권장 lazy-apps = true
lazy 옵션 문제점
lazy 옵션은 오래되었다는 단점이 있습니다. 또한 매우 침입적이고 실망스러운 방법이라고 설명합니다.( 이전 버전과의 호환성을 위해서만 존재합니다.)
uWSGI는 호출이 가능할 때마다 fork()의 Copy-on-Write 의미를 사용(남용)하려고 시도합니다. 기본적으로 어플리케이션을 로드한 다음, 가능한 많은 메모리를 공유하기 위해 fork를 합니다. 만약 이러한 동작을 원하지 않을 경우 lazy-apps 옵션을 사용해야 합니다. 이 옵션을 사용하면, uWSGI가 각 worker의 fork() 후 어플리케이션을 로드하도록 명령을 내립니다.