엔지니어링

Announcements 기능 재설계를 통한 최적화하기

Share
Announcements 기능 재설계를 통한 최적화하기

Get Started!

Sign up for a full-featured 30 day free trial. No credit card required.

Free Trial

센드버드의 Announcements API는 프리미엄 feature로, 그룹채널의 대규모 유저들에게 메세지를 보내고 수신 결과에 대한 통계를 제공하는 기능입니다. 이번 글은 Announcements v2를 소개하는 글이며, 저희가 어떻게 이 feature을 v1에서 v2로 재설계했는지, EKS 및 컨테이너 기술을 이용하여 배치성 작업들을 어떻게 스케일 아웃했는지, 어떻게 스케줄링 전략을 개선하여 비용을 줄였는지, 그리고 유저를 기반한 Queue 를 설계하여 어떻게 Announcement 의 ordering 문제를 해결하였는지 공유드리겠습니다.

Announcements의 첫번째 버전(v1)은 성능과 확장성에 있어 명확한 한계가 있었습니다. 첫 버전은 배치서버의 단일 프로세스를 기반으로 작동하였고 동일한 서버 인스턴스에 있는 다른 프로세스들의 영향을 받았습니다. 이 때문에 아쉽게도 다양한 사이즈의 workloads 요청에 대한 확장성이나 융통성은 부족했습니다.

Announcements v1.5는 이러한 한계를 극복하기 위해 AWS의 ECS를 활용하여 스케줄링되는 메시지들을 병렬로 처리하도록 구성하였습니다. 이를 위해 분 단위로 ECS 태스크를 실행하였고, 각 ECS 태스크는 메시지 한 건을 맡아 전송하는 역할을 했습니다. v1.5는 AWS ECS 기술을 처음 적용한 사례였기 때문에 추가적인 개선을 요했습니다. v1.5는 AWS CloudWatch (CW) 이벤트에 의해 작동하는 스케줄링된 액션을 사용했는데, 이 이벤트를 이용하여 ECS 컨테이너들을 실행시켰습니다. 이런 구성상의 문제로 ECS 와 CloudWatch (CW) 에서 발생하는 모든 Incident(장애)에 영향받을 수밖에 없었습니다. 뿐만 아니라, ECS 태스크 당 Announcement Job 하나밖에 처리하지 못하기 때문에 전체 Job들을 처리하기 위해서 프로비저닝에 너무 많은 시간을 소비해야만 했습니다. 또한 문제가 생긴 Stale Announcement Job 은 수동으로 처리해야 했습니다.

 

이런 문제점들을 효율적으로 해결하기 위해 서로 다른 성격의 태스크 2개를 적용한 v1.6을 런칭하였습니다. 하나는 worker 태스크로, 스케줄링된 Announcement Job에 맞춰 대상 채널/유저에게 메시지를 전송하는 역할을 합니다. 다른 하나는 scheduler 태스크로, 스케줄링된 Announcement Job을 식별하여 필요한 worker 태스크의 갯수를 계산하고 launch 까지 시키는 역할을 합니다. 많은 계산과 IO를 요하는 worker 태스크와 달리, scheduler 태스크는 적은 컴퓨팅 파워로도 충분합니다. 적은 스펙의 scheduler 태스크를 하루종일 돌리고 Announcement 메시지 처리가 필요할 경우에만 worker 태스크를 런칭시키면 무거운 ECS 태스크를 매분 돌릴 때보다 비용을 훨씬 절감할 수 있습니다. 또한 Announcements v1.5는 n개의 ECS 태스크를 시작하는 데에 n분이 소요된 반면에, v1.6 은 동시에 필요한 만큼의 worker ECS 들을 한번에 시작할 수 있도록 설계하였습니다.

뿐만 아니라 scheduler와 worker 태스크 사이에 큐를 만들어, 이미 큐에 job이 있을 경우 worker 태스크가 한 개 이상의 job을 처리할 수 있도록 하였습니다. ECS Fargate 태스크를 시작할 때는 프로비저닝, 이미지 가져오기, 컨테이너 실행 작업이 포함되어 약 1분이 소요됩니다. V1.5는 ECS 태스크 당 한 Announcement job만 처리하고 종료되었던 반면에 v1.6의 worker 태스크는 ​​큐에 모든 작업이 dequeue 되어 비워질 때까지 종료되지 않고 동시에 처리할 수 있기 때문에 시간과 비용을 줄일 수 있습니다. 

데이터베이스 부하를 적절하게 제어하기 위해서 v1.6 에 속도 제한(Rate limiter) 기능을 개발하였고 데이터베이스의 작업량이 많을 경우(ex. CPU 사용량이 높을 때) Announcements 서비스의 메시지 전송 속도를 통제할 수 있도록 하였습니다. 뿐만 아니라, 데이터 베이스에 유입되고 있는 주요 쿼리들의 트래픽을 특정 interval 동안 기록, 계산하여 일정 이상의 부하가 들어가지 않도록 조절하였습니다. 또한 예상치 못한 동작이 발생하였을 때 멈춘 메시지들을 자동으로 복구할 수 있도록 개발한 결과, Announcements의 이슈 처리량과 빈도가 훨씬 감소했습니다.

Announcements v2에 많은 개선사항이 있었지만, 여전히 개선의 여지가 남아있습니다. 몇몇 고객들은 요청 순서대로 Announcements 메시지가 전송되길 원합니다.즉, 동일한 채널 및 사용자들을 대상으로 하는 Announcement job이 2건 이상 있을 경우, 이전에 스케줄된 메시지가 먼저 전송되도록 하는 것입니다. 현재 저희 Announcements 는 job 요청 순서에 상관없이 병렬로 메시지를 발송하기 있기 때문에, 동일한 채널에 동시에 요청된 job 들의 순서가 보장되지 않습니다. 유저(발송자)를 기반으로 순서를 보장할 수 있는 큐를 구현함으로써 이 프로세스를 개선할 계획입니다. 추후에 더 많은 업데이트 소식을 전해드리겠습니다!

Categories: 엔지니어링