안정적으로 50만명의 유저에게 Push notification 보내기
Push notification은 engagement 관리에 중요한 역할을 합니다. 유저와 유저간의 대화, 그룹 채팅, 마케팅 push등 다양한 방식으로 유저의 engagement를 이끌어 낼 수 있습니다. Sendbird Chat에서는 이 모든 형태의 채팅에서 Push notification을 지원하여, 고객의 다양한 use case에 맞춰 빠르게 사용할 수 있도록 합니다.
Broadcast Push notification
Sendbird Chat에서는 마케팅, 공지 등을 위해 broadcast channel을 지원합니다. Broadcast channel 에서는 고객사에서 원하는 유저들을 상대로 일괄적으로 Push notification을 보낼 수 있습니다.
Broadcast channel의 크기에 대한 제약이 명시적으로 있지는 않았지만, 한 항공사에서 큰 규모로 사용하기 전에 어느정도 제약이 있는지 확인할 필요가 있었습니다. 내부적으로 테스트해본 결과, 약 50만명 정도의 유저를 안정적으로 지원할 수 있었고, 더 큰 크기의 채널을 지원하기 위해 아키텍처를 개선할 필요가 있었습니다.
기존 아키텍처는 큰 규모의 Push notification 발송에 따른 Database 부하를 완화하기 위해 15분에 걸쳐 순차적으로 Push를 보내고 있었습니다. Push를 보내면서 유저의 정보를 조회하여야 하기에, Push를 보낼 유저가 늘 수록 Database에 가해지는 시간당 쿼리가 많아지게 됩니다. 이러한 문제로 인해 50만명 이상의 유저에게 Push를 보내면 Database가 불안정해지는 이슈가 있었습니다.
이 문제를 해결 하기 위해 Database를 Scale-out 하여 성능을 높이는 방법도 있지만, 비례적으로 비용이 증가하고 시스템의 복잡성이 증가하기 때문에 적절하지 않았습니다. 따라서 Database는 유지하되, 일정한 rate로 순차적으로 Push를 보내서 Database에 전해지는 부하를 일정하게 만들어 장애를 방지하고 더 많은 유저를 지원할 수 있습니다..
The only UIKit you need.
SQS Delay Seconds Limits
기존에 Push가 15분에 나누어서 보내지던 이유는 SQS Delayed Queue의 Delay seconds 제한이 15분이었기 때문입니다. 일정한 rate로 순차적으로 보내기 위해서는 지금보다 더 긴 Delay가 필요하기에 1~2시간 정도 Delay를 줄 수 있는 방법들을 검토해 보았습니다.
우선 Cron을 통해 내부적으로 관리하는 방법도 있었지만, 관리 포인트가 늘어나고 장애 가능성이 늘어나는 등 단점이 있어 Managed Service를 사용하기로 결정했습니다. 기존에 SQS를 사용하는 결정도 동일한 이유로 이루어졌습니다.
다음으로는 SQS Delay Queue에서 메시지를 Queue에 여러번 되먹임 하면 충분한 delay를 구현할 수 있습니다. 여러개의 큐를 두거나, 하나의 큐에서 반복해서 넣으면서 구현 할 수 있습니다. 다만 전자의 경우 Delay에 비례하여 Queue가 필요하기에 Queue의 수가 늘어나고, Scalability가 떨어집니다. 후자의 경우에는 여러 단계의 메시지들이 큐에 쌓여있기에 정상 작동 여부를 판단하는 Metric을 세우기 어려워집니다. 따라서 다른 도구가 필요한 상황이었습니다.
AWS Step Functions을 Delayed Queue로 사용
AWS에 Ticket을 보내 문의해본 결과, Step function의 Wait step을 활용하면 원하는 만큼의 Delay를 사용 할 수 있다고 답변을 받았습니다. Step function은 AWS에서 제공하는 Low code workflow service로, Step Functions에서 제공하는 다양한 Step을 통해 Application을 구축할 수 있습니다.
Step function이 현재의 Usecase에 비해 너무 General한 문제를 풀기 위한 도구로 보이지만, 일단 요구되는 조건을 모두 만족하기에 검토하여 보았습니다. Low code service인 만큼, 단순한 Queue인 SQS에 비해 단위 요청당 비용이 약 100배 가량 높았지만, Push notification 발송과정에서 Queue의 비용이 매우 작은부분에 불과하였기에 문제가 되지 않을것으로 판단했습니다. 만약 Queue의 사용량이 커서 비용 문제가 발생하는 경우에는 Message Chunking 등으로 사용량을 줄일 필요가 있을것으로 보입니다.
Step function에서 Wait Step를 사용하면 임의의 delay time을 설정 할 수 있었습니다.이후 Lambda Invoke Step을 통해 원하는 Lambda를 trigger 해주었습니다. Wait Step과 Lambda Invoke Step을 조합하여 SQS Delayed Queue와 동일한 효과를 얻을 수 있었고, Function을 구성하고 SQS 대신 Step function endpoint에 Job을 보내는것으로 기존 구조를 대체할 수 있었습니다. 이후 새로운 아키텍처에 맞추어 모니터링 시스템을 구축하는것으로 모든 작업이 완성되었습니다.
새로운 아키텍처를 완성하고 Load Test를 해본 결과, 50만명 유저에게 2시간에 걸쳐 순차적으로 Push를 보낼 수 있었습니다. 유저 수와 상관없이 동일한 속도로 Push를 보내는 Scalable한 구조이기 때문에 그 이상의 유저 수도 충분히 지원 가능할것입니다.