Gunicorn worker가 계속 재시작된다면, 원인은 timeout 압박, 메모리 증가, boot-time failure, 의도된 recycle 설정, 혹은 signal 경로일 수 있습니다.
그래서 restart 장애는 읽기가 어렵습니다. 어떤 restart는 설정상 정상이고, 어떤 restart는 실제 런타임 문제를 뜻합니다. 이 둘을 먼저 나누지 않으면 멀쩡한 recycle을 crash처럼 디버깅하게 될 수 있습니다.
이 글은 실전 순서에 집중합니다.
- boot failure, runtime restart, deliberate recycle을 어떻게 구분할지
- restart timing이 어떤 힌트를 주는지
- timeout, memory, startup 경로에서 무엇을 먼저 볼지
짧게 말하면 restart가 boot에서 나는지, runtime에서 나는지, 설정상 예상된 recycle인지 먼저 구분하고, 그다음 트래픽, 메모리, timeout-heavy 경로와 타이밍을 비교하는 편이 빠릅니다.
더 넓은 Python 분기부터 다시 보고 싶다면 Python 트러블슈팅 가이드로 가세요.
먼저 재시작 타이밍부터 보기
worker가 언제 재시작되는지부터 보세요.
- 부팅 직후
- 트래픽 spike 이후
- 일정 시간이나 요청 수 이후
- 메모리가 오른 뒤
이 타이밍은 stack trace 하나를 따로 읽는 것보다 훨씬 빨리 갈래를 좁혀줍니다.
특히 아래를 나누는 데 유용합니다.
- startup failure
- runtime instability
- expected recycle behavior
이 첫 분기 없이 보면 모든 restart를 crash로 오해하기 쉽습니다.
boot failure와 runtime restart는 완전히 다르다
worker가 부팅 직후 재시작된다면 아래를 먼저 의심해야 합니다.
- import failure
- config mistake
- environment mismatch
- readiness 전 startup path 실패
반대로 traffic나 memory 변화 뒤에 재시작된다면 아래 branch가 더 가깝습니다.
- worker timeout
- memory pressure
- request path instability
- load 중 signal 또는 platform restart
이 두 branch는 해결책이 완전히 다릅니다.
자주 나오는 원인
1. worker timeout
요청이나 upstream dependency가 worker 시간 제한을 넘어갈 수 있습니다.
자주 보이는 단서는 아래와 같습니다.
- 트래픽 spike 구간에서 restart가 집중됨
- timeout-heavy endpoint가 로그에서 많이 보임
- 긴 request나 blocked dependency 뒤에 restart가 나타남
이 경우 restart는 랜덤이 아니라, worker가 주어진 시간 안에 작업을 못 끝내는 결과에 가깝습니다.
2. 메모리 압박
메모리가 높아지면서 worker가 recycle되거나 kill될 수 있습니다.
보통은 아래처럼 보입니다.
- restart timing이 메모리 증가와 비슷하게 움직임
- 특정 worker class나 endpoint가 더 크게 할당함
- memory-heavy request 뒤에 패턴이 심해짐
그래서 worker restart와 Python 메모리 장애는 자주 같이 보입니다.
3. boot-time import / config 실패
worker가 healthy 상태까지 올라오지 못해 반복 재시작될 수 있습니다.
자주 보이는 패턴은:
- import-time exception
- 누락된 env var
- unavailable service에 의존하는 startup code
- worker 초기화를 깨뜨리는 config 변경
이 branch라면 runtime traffic을 오래 보는 것보다 boot log를 먼저 보는 편이 맞습니다.
4. 정상 recycle을 장애로 오해
일부 restart는 Gunicorn 설정이나 플랫폼 동작상 예상된 현상일 수 있습니다.
예를 들면:
- worker recycle policy
- request-count 기반 제한
- platform restart
- deployment restart를 애플리케이션 불안정으로 오해
핵심은 이 restart가 실제로 해로운지, 아니면 단지 눈에 보이는 것인지 구분하는 것입니다.
실전 점검 순서
worker가 계속 재시작될 때는 아래 순서가 가장 도움이 됩니다.
- restart가 boot인지, runtime인지, expected recycle인지 구분
- restart timing과 트래픽 / 메모리 변화 비교
- timeout-heavy request path 확인
- boot log와 최근 import / config 변경 확인
- startup failure인지, runtime pressure인지, normal recycle인지 판단
이 순서가 중요한 이유는 두 가지 흔한 실수를 막기 때문입니다.
- restart timing을 모른 채 worker 수부터 조정하는 실수
- 실제 원인은 startup path나 request runtime인데 Gunicorn 설정 탓부터 하는 실수
CPU나 memory 압박이 같이 보인다면 Python CPU 사용량이 높을 때와 Python 메모리 사용량이 높을 때를 같이 보세요.
아주 작은 예시가 보여주는 핵심
gunicorn app:app --workers 4 --timeout 30
slow startup, memory spike, import failure, aggressive timeout 모두 worker restart loop를 만들 수 있습니다.
이 명령 자체가 원인을 알려주지는 않습니다. 실제 힌트는 restart 직전 worker가 무엇을 하고 있었는지, 로그와 타이밍이 무엇을 가리키는지에 있습니다.
restart 장애마다 물어볼 질문
각 restart 패턴마다 아래를 물어보면 도움이 됩니다.
- restart 직전 worker는 무엇을 하고 있었는가
- 트래픽 처리 중이었는가, 부팅 중이었는가, 그냥 대기 중이었는가
- memory 압박이 먼저 왔는가, timeout이 먼저 왔는가
- 사용자 트래픽이 전혀 없어도 이 restart가 계속 나는가
이 프레이밍이 좋은 이유는 Gunicorn 장애가 설정 문제이기 전에 timing 문제인 경우가 많기 때문입니다.
FAQ
Q. worker가 재시작되면 항상 Gunicorn이 고장 난 건가요?
아닙니다. application startup failure, timeout-heavy path, memory pressure, expected recycle behavior 때문에도 restart가 날 수 있습니다.
Q. 무엇부터 보는 게 가장 빠른가요?
restart timing부터 보세요. boot, runtime request path, expected recycle 중 어디 branch인지가 거의 결정됩니다.
Q. 왜 traffic spike와 worker restart가 같이 보이나요?
traffic spike가 timeout-heavy endpoint, memory-heavy path, blocked dependency를 훨씬 더 강하게 드러내기 때문입니다.
Read Next
- Python 전체 분기부터 다시 보고 싶다면 Python 트러블슈팅 가이드로 가세요.
- CPU 압박이 같이 보이면 Python CPU 사용량이 높을 때를 보세요.
- memory 압박이 같이 보이면 Python 메모리 사용량이 높을 때를 보세요.
Related Posts
Sources:
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.