Celery Worker 최적화를 통한 MQTT 메시징 시스템 개선

bae.200.ok
7 min readFeb 12, 2022

--

안녕하세요. 배민혁 입니다.

최근 운영하던 서비스에 장애가 발생했습니다. 해당 장애에 대해서 분석하고 해결했던 내용을 작성해보려 합니다.

1 Situation: 고객사의 편성 패턴 변화

지금 운영하는 서비스는 CMS(Content Management System) 통한 컨텐츠(이미지,영상 및 광고) 송출 솔루션 입니다. 도메인은 DOOH(Digital Out-Of-Home)입니다.

사용자 A는 많은 스크린을 운영중이며 사용 패턴 또한 특이합니다.그렇다보니 여러 방식을 통해서 시스템의 부하를 분산하고 있었습니다.

2202년 01월 12일, 사용자 A의 편성 패턴에 변화가 생겼습니다. 이것을 시작으로 다른 사용자 및 시스템 전체에 장애가 전파되는 문제가 발생했습니다.

표면으로 드러나 사용자가 알게된 상황은 “편성을 정상적으로 수정했음에도 불구하고 반영이 안된다.”였습니다. 이제 어떤 문제가 있었는지 정리해보겠습니다.

2 Task: Action을 위한 분석하기

2.1 시스템 배경 설명

현재 운영중인 서비스는 다음과 같은 순으로 동작하는 부분이 있습니다.

  1. 사용자가 컨텐츠 편성을 변경한다.
  2. Celery를 통해 변경된 컨텐츠 편성이 반영되어야할 스크린에 MQTT를 발행한다.

2.2 모니터링 툴로 분석

시스템이 AWS에 상에서 운영이 되고 있기 때문에, Cloudwatch로 분석을 시작했습니다. 확인하던 중 Celery Worker A(이하 worker_a)를 운영하고 있는 서버의 지표에 특이사항을 확인했습니다.

날짜 별 메모리 사용률

첫번째 지표를 보면 1/12일 이전과는 다르게 메모리 사용률이 30% 정도로 떨어졌으며, CPU 사용률은 0%가 되었습니다. 아예 일을 안하고 있는 상황이 되버린겁니다.

worker_a의 메모리 사용률
worker_a의 CPU 사용률

2.3 로그로 분석

2.3.1 DeadLock

DeadLock 발생 로그(전체를 캡쳐하고 보니 너무 작네요;)

특정 celery task에서 DeadLock이 발생하는 것을 확인했습니다. 그 이유를 확인해보면 특정 로우에 짧은 간격을 두고 자주 요청이 발생하는 것을 확인 할 수 있었습니다.

해당 celery task소스를 분석해보면, 동일한 스크린을 대상으로 select, update 쿼리가 여러번 발생하는 것을 확인할 수 있었습니다.

이것은 DB에 문제를 일으키며 더많은 문제를 전파하는 요소가 될 수 있음에 틀림없습니다. 하지만 이것으로 인해 worker_a가 아예 동작하지 못하게 되었다는 것을 보장할 수는 없다고 생각해서 더 분석을 진행하기로 했습니다.

2.3.2 Connection to broker lost

flower를 통해서 celery worker를 모니터링을 진행하고 있습니다 worker_a의 status가 offline인 것을 확인했습니다. offline은 브로커와 연결 상태를 말합니다. online으로 복구가 되지 않는 상황이었기에 관련된 로그를 더 확인해봅니다.

  • consumer: Connection to broker lost. …
  • Worker exited prematurely: sig 9 (SIGKILL) Job: …
  • Unrecoverable error: …

이 로그들을 보면서 문제를 파악했다고 생각했습니다. 제가 확인한 문제의 원인은 다음과 같습니다.

  • celery worker가 broker와 연결을 잃어버리면서 메모리, CPU 사용률이 모두 떨어진 상태를 유지했다.

3 Action: 선/후 조치

3.1 선조치

지표를 보면 일단 메모리가 부족하여 프로세스 할당을 못했다고 판단했기 때문에 메모리를 증설한 후, worker를 재시작하였습니다.

제가 내린 결론은 celery worker가 broker와의 연결 유실이었습니다. 그렇기 때문에 재시작만으로 해결은 가능했습니다. 하지만, 재시작을 한 이후에도 정상적으로 동작하지 않았습니다.

그 이유는, worker가 동작하지 않는 동안에도 task는 여전히 broker에 누적이 되고 있었습니다. 그렇기때문에 worker가 재시작을 한 이후 누적된 task를 처리하느라 CPU와 메모리를 모두 100% 사용하게됩니다. 여기서 새로운 task를 받아서 처리하려고 해도 메모리를 모두 사용하여 메모리 할당을 못하게 됩니다. 실제로 로그에 cannot allocate memory라는 로그를 볼 수 있었습니다.

이렇게 문제는 메모리라고 생각이 되어서 메모리 증설도 같이 진행하게 되었습니다. 그렇게 시간이 지나자 모든 task를 처리하고 서버는 정상으로 돌아왔습니다.

[Action]

  • 메모리 증설
  • 워커 재시작

3.2 후조치

선조치는 표면적인 해결을 위함이었습니다. 위에서 celery worker가 broker와 연결을 잃어버리는 것이 문제의 시작이라고 판단했습니다. 그렇다면 그 이유는 무엇인지 확인해볼 필요가 있었습니다.

해당 issue를 읽어보면 정확히 어떤 것이 문제인지 판단하기 어려웠습니다. 여기서는 특정 모듈의 문제, 브로커의 문제, 브로커의 버전 문제 등 여러가지 언급이 있었습니다.

정확히 원인를 판단하기는 어려워서, 다음에도 유사한 장애가 발생하면 더 자세히 살펴보기로 했습니다.

그래도 당연히 장애는 발생하면 안되기 때문에, 해당 task를 전담하는 worker를 분리하는 작업을 진행했습니다. worker를 분리하기 이전에는 worker_a가 많은 task를 처리하고 있었습니다. 그렇기 때문에 부하도 높았으며 worker_a가 동작하지 않게되면 다른 task들도 처리할 수 없는 최악의 상황에 빠졌습니다. worker 분리를 안할 수 없는 상황입니다.

또한, 정확한 전조증상을 잡아내기 어려운 상태이니 몇가지 의심하고 있는 부분들에 대해서 알림을 받을 수 있도록 처리하였습니다.

추가로 celery 옵션으로만 autoscale하는 것이 아니라, worker가 동작하는 서버 또한 autoscale이 되도록 설정을 변경하였습니다.

[Action]

  • mqtt 발행 celery task를 전담하는 worker 분리
  • 전조증상으로 의심되는 로그 발생시 알림 발송
  • 컴퓨팅 autoscale 설정 추가
  • +) deadlock이 발생하는 부분 개선 작업 추가

4 Result: 현황 및 회고

4.1 시스템

현재는 관련된 장애가 발생하지 않고 있습니다. 또한 전조증상으로 의심되는 로그가 발생하면 면밀히 모니터링하여 정확한 원인을 파악하고자 힘쓰고 있습니다.

4.2 개인 회고

개인적으로는 정말 많은 것을 공부하고 배우게 된 계기가 되었습니다. 그 동안은 수면에 올라 온, 보이는 문제들에만 집중해서 작업을 진행 했던 것 같습니다.

이번 장애로 수면 아래까지 고민해야한다는 것을 다시한번 깨닫게 되었습니다. 또한 해결하지 못할 것 같았던 문제를 해결하니 다른 문제들도 해결할 수 있다는 자신감을 얻었습니다.

--

--