Go worker pool 에서 작업이 계속 쌓인다면, queue 는 보통 들어오는 작업 속도가 끝나는 속도보다 빠르다고 말해 주는 것입니다. 실제 문제는 느린 downstream call, 비싼 job 비용, 없는 backpressure, 혹은 overload 를 제어하지 못하고 숨기기만 하는 pool 구조인 경우가 많습니다.
짧게 말하면 핵심은 이것입니다. worker 를 더 늘리기 전에 job 유입 속도와 완료 속도를 비교해야 합니다. 커지는 queue 는 보통 scheduler 미스터리가 아니라 throughput mismatch 입니다.
queue 증가와 completion pace 부터 본다
worker 수를 만지기 전에, 시스템이 아래 중 무엇인지 알아야 합니다.
- 처리가 너무 느린가
- 유입이 너무 많은가
- 같은 작업을 retry 로 반복하는가
- downstream system 에 막히는가
이 네 가지는 모두 queue growth 를 만들지만 fix 는 다릅니다.
worker-pool backpressure 는 실전에서 어떻게 보이나
운영 환경에서는 보통 이렇게 보입니다.
- queue depth 가 꾸준히 오른다
- worker 는 바쁜데 throughput 은 회복되지 않는다
- saturation 이 분명한데도 producer 는 계속 일을 넣는다
- retry 와 requeue 가 backlog 를 더 악화시킨다
- 운영자는 worker 수를 늘렸다가 downstream 문제를 더 키운다
그래서 queue growth 는 단순 worker 설정 문제가 아니라 시스템 신호로 봐야 합니다.
흔한 원인
1. worker 가 각 job 에 너무 오래 머문다
DB, HTTP, file I/O, CPU-heavy step 이 effective throughput 을 낮출 수 있습니다.
job 당 비용이 커지면 pool size 가 그대로여도 queue 는 커집니다.
2. queue input 에 backpressure 가 없다
시스템이 이미 포화됐는데도 producer 가 계속 작업을 밀어 넣을 수 있습니다.
즉 queue 가 overload 를 제어하는 대신 흡수하고 있는 상태입니다.
3. worker 수가 실제 workload 와 맞지 않는다
worker 가 너무 적으면 throughput 이 막히고, 너무 많아도 downstream contention 과 resource pressure 를 더 키울 수 있습니다.
worker 는 많을수록 좋은 게 아닙니다.
4. retry 와 requeue 가 queue pressure 를 곱한다
실패하는 dependency 하나 때문에 같은 job 이 반복해서 쌓일 수 있습니다.
이 경우 backlog 는 capacity 문제가 아니라 failure-amplification 문제인 경우가 많습니다.
5. 작업 분포가 하나의 느린 stage 를 숨긴다
pool 전체가 작다기보다, 특정 stage 또는 job type 하나가 훨씬 느려서 queue age 를 지배하는 경우도 있습니다.
실전 점검 순서
1. job 유입 속도와 완료 속도를 비교한다
핵심 신호입니다.
유입이 완료보다 꾸준히 크다면 queue 증가 자체는 당연하고, 이제 왜 그런지 찾아야 합니다.
2. queue depth 와 worker utilization 을 같이 본다
queue 는 큰데 worker utilization 이 낮으면 한 종류의 문제고,
queue 도 크고 worker 도 포화면 다른 종류의 문제입니다.
3. 각 job 안의 blocking downstream step 을 찾는다
아래를 보세요.
- HTTP wait
- DB wait
- file 또는 network latency
- lock 또는 channel stall
worker 대부분이 기다리는 중이라면, worker 를 늘려도 waiting 만 넓게 퍼질 수 있습니다.
4. retry, requeue, duplicate work 패턴을 점검한다
이 단계는 자주 건너뛰지만, worker 가 바빠 보이는데도 queue 가 계속 커지는 이유를 설명하는 경우가 많습니다.
5. throughput 한계가 분명해진 뒤에만 worker 수를 조정한다
실제 bottleneck 이 downstream 또는 duplicated work 라면, worker tuning 만으로는 queue 가 안 풀립니다.
예시: worker 는 살아 있는데 queue 는 계속 커지는 경우
jobs := make(chan Job, 100)
for i := 0; i < 4; i++ {
go worker(jobs)
}
producer 가 worker 완료 속도보다 빠르게 일을 넣으면 queue depth 는 계속 커지고, backpressure 는 결국 시스템 다른 곳에서 터집니다.
핵심 질문은 “왜 worker 가 incoming work 대비 너무 느리게 끝나는가” 입니다.
bottleneck 을 찾은 뒤 무엇을 바꾸면 좋나
job 자체가 너무 느리다면
비싼 경로를 최적화하거나 job 당 비용을 줄여야 합니다.
backpressure 가 없다면
bounded queue, producer throttling, rejection behavior 를 넣어 overload 를 더 일찍 보이게 해야 합니다.
worker 수가 mis-sized 라면
실제 throughput 과 dependency behavior 를 바탕으로 조정해야 합니다.
retry 가 pressure 를 키운다면
scale 보다 retry discipline 을 먼저 고쳐야 합니다.
특정 stage 가 backlog 를 지배한다면
그 stage 를 분리하거나 pipeline 설계를 다시 봐야 합니다.
장애 중에 던져볼 질문
이 질문이 꽤 유용합니다.
queue 가 커지는 이유가 worker 가 적어서인가, job 이 느려서인가, 아니면 시스템이 안전하게 끝낼 수 있는 양보다 더 많은 work 를 계속 받아서인가?
이 구분이 보통 fix path 를 바로 드러냅니다.
FAQ
Q. worker 를 더 늘리면 항상 해결되나
아닙니다. downstream bottleneck 을 더 크게 만들 수도 있습니다.
Q. 가장 빠른 첫 단계는 무엇인가
queue growth 와 completion pace 를 동시에 측정하는 것입니다.
Q. retry 만으로도 backpressure 처럼 보일 수 있나
그렇습니다. 실패한 작업 반복만으로도 pool 이 부족해 보일 수 있습니다.
Q. queue 는 항상 bounded 여야 하나
항상은 아니지만, 무제한 축적은 overload 를 너무 늦게 보여 주는 경우가 많습니다.
Read Next
- worker 는 살아 있지만 coordination path 를 못 끝내는 쪽이라면 Golang WaitGroup Stuck 을 같이 보세요.
- background worker 가 drain 되지 않고 쌓이는 유형이라면 Golang Goroutine Leak 를 이어서 보세요.
- 더 넓은 concurrency pressure 는 Golang Troubleshooting Guide 에서 이어 볼 수 있습니다.
Related Posts
- Golang WaitGroup Stuck
- Golang Goroutine Leak
- Golang Mutex Contention High
- Golang Troubleshooting Guide
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를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.