이 블로그는 Channel Corporation의 이해빈님, 박진영님과 함께 작성되었습니다. 채널코퍼레이션은 올인원 AI 메신저 ‘채널톡’을 운영하는 B2B SaaS 스타트업으로 Amazon DynamoDB의 수평 확장성, ACID 트랜잭션과 같은 특징을 활용해 빠르게 성장하는 비즈니스를 문제없이 수행하고 있습니다. 이 시리즈의 1부에서는 채널코퍼레이션이 Amazon DynamoDB를 선택한 이유와 Amazon DynamoDB에서 트랜잭션을 처리한 방법을 살펴보았습니다. 2부에서는 채널코퍼레이션이 두 가지 유형의 DynamoDB 스트림을 사용하여 이벤트 […] ||
이 블로그는 Channel Corporation의 이해빈님, 박진영님과 함께 작성되었습니다.
채널코퍼레이션은 올인원 AI 메신저 ‘채널톡’을 운영하는 B2B SaaS 스타트업으로 Amazon DynamoDB의 수평 확장성, ACID 트랜잭션과 같은 특징을 활용해 빠르게 성장하는 비즈니스를 문제없이 수행하고 있습니다. 이 시리즈의 1부에서는 채널코퍼레이션이 Amazon DynamoDB를 선택한 이유와 Amazon DynamoDB에서 트랜잭션을 처리한 방법을 살펴보았습니다. 2부에서는 채널코퍼레이션이 두 가지 유형의 DynamoDB 스트림을 사용하여 이벤트 기반 아키텍처를 구현한 방법을 소개하였습니다.
이번 3부에서는 채널톡의 Badge 사례를 통해, 범용 DynamoDB User 테이블을 역할별로 분리하여 문제를 해결한 경험을 공유합니다.
배경: Badge
채널톡에서 뱃지(Badge)는 사용자에게 읽지 않은 메시지나 새로운 알림이 있다는 걸 알려주는 시각적 표시입니다.
그림 1: 읽지 않은 메시지를 나타내는 채널톡의 badge
채널톡에는 세 가지 유형의 사용자가 있습니다.
User: 채널톡을 통해 문의를 남기는 일반 고객. (고객사의 고객)
Team Member: 고객사에서 상담을 담당하는 직원
Account: 채널톡을 구독하는 고객사 계정 (1 Account : N Team Members)
이 중 DynamoDB의 User 테이블은 총 용량 1.8TB에 달하는 약 16억 8천만 개의 레코드를 담고 있었습니다. 하루동안 이 Badge의 업데이트 요청이 여러 차례 급증하게 되면서, 전체 User 서비스가 악영향을 받기 시작했습니다. User 테이블이 느려지면, 채널톡의 핵심 기능인 “부트” 기능이 마비됩니다. 부트란 고객이 채널톡이 설치된 웹사이트나 앱에 방문했을 때 고객 정보를 채널톡에 연동하는 과정으로, 이 기능이 동작하지 않으면 고객사 홈페이지에서 채널톡 자체를 쓸 수 없게 됩니다.
“Badge 업데이트만 했는데 왜 User 테이블 전체가 느려지는 걸까요?”
User 테이블의 쓰로틀링: 두 가지 원인
첫번째로 User 테이블은 프로필, 태그, 뱃지, 상태 등 많은 역할을 담당하고 있었습니다. 그런데 Badge 업데이트는 급격하게 치솟는 특성이 있습니다. 일회성 메시지(OTM)를 많은 사용자에게 한꺼번에 보낼 때 트래픽이 폭증합니다. 예를 들어, 10,000명의 사용자에게 단일 OTM을 보내면 10,000건의 동시 쓰기가 발생합니다. Badge 업데이트는 단일 항목의 Badge 관련 속성(alert, unread)만 수정합니다. DynamoDB에서 Write Capacity Unit(WCU)은 항목 단위로 소비되므로, 일부 속성만 수정하더라도 전체 항목 크기를 기준으로 WCU가 소비됩니다.
1부에서 소개한 바와 같이, 채널톡에서 메시지를 보낼 때 채팅 세션 정보(ChatSession)와 Badge는 TransactWriteItems API를 통해 트랜잭션으로 처리됩니다. 단일 Badge 업데이트는 2개의 항목을 갱신하며, 이는 4 WCU(2개 항목 × 트랜잭션 쓰기당 2 WCU)를 소비합니다. 그러나 진짜 문제는 트랜잭션 충돌입니다. DynamoDB 트랜잭션에서 커밋 시점에 충돌이 감지되면 전체 트랜잭션이 롤백되고 클라이언트가 재시도합니다. 메시지 전송이 동시에 발생하면 충돌이 빈번하게 일어나고, 각 재시도마다 추가 WCU


