LINE의 오픈챗은 대규모 트래픽을 처리하는 서비스 중 하나입니다.

 

특히 유명 가수의 콘서트 시, 수백만 팬들이 오픈챗에서 활발히 소통하면서 발생하는 트래픽 급증이 발생합니다.

 

이러한 상황에서 LINE은 '핫 챗 (Hot Chat)'으로 정의하며, 이 글에서는 핫 챗의 발생 패턴과 해결 방법을 살펴보겠습니다.

1. 오픈챗이 처리하는 트래픽의 규모

하나의 오픈챗은 수천에서 수만 명의 사용자를 수용할 수 있습니다.

 

오픈챗 서버는 분당 1천만 건, 일일 약 100억 건의 API 요청을 처리합니다. 활발한 하나의 오픈챗은 분당 최대 20만 건의 API 요청을 생성하기도 합니다.

2. 오픈챗 서비스의 구조

LINE의 오픈챗 서비스는 이벤트 기반 아키텍처로 구성되어 있습니다.

 

사용자가 메시지를 보내는 등의 이벤트가 발생하면, 이들은 데이터베이스에 기록되고 Kafka를 통해 전달됩니다.

 

이후 Publish 서비스가 Kafka 토픽에서 이벤트를 소비하고, 사용자들에게 이벤트를 알리는 서버 푸시를 합니다.

 

사용자들은 API 호출을 통해 필요한 데이터를 가져갑니다.

 

 

좀 더 자세하게 그려본 다이어 그램은 다음과 같습니다:

 

 

3. Hot Chat 패턴별로 발생하는 문제와 이를 해결하는 전략

3.1 오픈챗 트래픽 증가

3.1.1 사례:

수백만명의 가수의 팬들이 콘서트를 열 때 오픈챗에서 활발히 떠들다보니 오픈챗의 이벤트를 가져오려는 API 호출 트래픽이 급증하는 사례가 발생합니다.

 

3.1.2 발생하는 서버 증상:

  • 트래픽 급증으로 인한 데이터베이스 요청 증가, Slow Query 발생
  • API 서버의 GC, CPU 사용량 증가 및 응답 지연
  • 카프카의 Lag 증가

 

3.1.3 해결책:

일반적으로 Naive 하게 생각해 수 있는 해결책은 Shard 를 추가하는 것일텐데, 핫 챗은 전체 오픈챗 중의 0.1% 정도 되기 때문에 단순 샤드를 추가하는 건 영향이 작을 것입니다.

 

LINE 에서는 Hot Chat 을 Detecting 하고 일정시간 동안 Throttling 을 적용하는 방법으로 해결했습니다:

  • 핫 챗 탐지:
    • Publish 서버에서 발생한 채팅방의 이벤트 수를 추적하고, 특정 임계점이 넘었으면 이 채팅방을 Hot Chat 이라고 기록합니다. 
  • 트래픽 Throttling 적용:
    • 핫 챗으로 분류된 채팅방에서는 확률적으로 서버 푸시 메시지 전송 빈도를 조절합니다.
    • 이는 API 요청의 폭증을 방지하고 서버 부하를 줄이는 데 도움이 됩니다.
  • 정책 동적 조정:
    • 핫 챗 정책은 LINE의 오픈소스 솔루션인 Central Dogma를 사용하여 동적으로 조정됩니다.
    • 이를 통해 서비스 운영자는 배포 없이 실시간으로 트래픽 상황에 맞춰 정책을 조정할 수 있습니다.
  • Note:
    • 이 방법은 폭증하는 트래픽에서 서버를 보호하는 방법이지, 트래픽 자체를 해결하는 방법은 아닙니다.
    • 위의 LINE 의 사례와 같은 Hot Key 문제에 대해서 트래픽 자체를 해결하려면 하나의 샤드로 향하는 트래픽을 다른 샤드들로 분산시키는 것이 필요합니다.
    • 그래서 일반적인 해결 방법 중 하나는 Shard Key 에다가 Random Number 를 붙혀서 하나의 샤드에서 다른 샤드들로 저장되고 읽을 수 있도록 하는 것입니다. 이를 'Salted Key' 라고도 합니다.
    • 이 방법으로 할 경우 읽기 요청을 할 때가 문제라서 Hot Key 의 Shard Key 가 어떻게 분산되었는지를 추적할 수 있는 방법을 추가로 필요로 합니다.
    • 이 방식으로 해결해야한다는 뜻을 말하는 것은 아닙니다. 개인적인 생각으로는 활발한 오픈챗에서 이벤트 전달은 되게 작은 문제라고 보여서 Throttling 하는 것이 더 나은 솔루션 같아 보입니다.

 

3.2 오픈챗 참여 요청이 급증

3.2.1 사례:

인플루언서가 오픈챗 링크를 공유하면서 참여 요청이 갑자기 증가하는 상황이 발생할 수 있습니다.

 

3.2.2 발생하는 증상들:

  • MySQL Slow Log 증가, CPU 사용률 증가
  • openChat 서비스의 응답 타임아웃 증가

 

3.2.3 해결책:

MySQL INSERT 성능 최적화:

  • 아래의 오픈챗 참여 INSERT 는 단순 INSERT 가 아니라, INSERT 내부에서 SELECT 를 사용하는 쿼리입니다. 이는 내부적으로 Bulk Insert 로 취급이 됩니다.

  • Bulk Insert 에서 레코드가 Auto Increment 타입의 칼럼을 쓰고 있는 경우 auto_increment_lock_mode=1 로 설정되어 있는 경우에는 Auto Increment 의 값을 연속적으로 증가함을 보장하며 테이블 락을 잡습니다. (MySQL 8.0 이전에는 auto_increment_lock_mode 의 기본 값은 1입니다.)
  • 그래서 동시에 오픈챗 참여 요청을 하면 이런 테이블락의 경합으로 인해서 CPU 사용률이 치솟는 것입니다.
  • 이를 auto_increment_lock_mode=2 로 변경하면 Auto Increment 값이 연속적으로 증가함을 보장하지는 않지만, 테이블 락보다 가벼운 Mutex 를 사용해서 더 나은 성능을 낼 수 있습니다. 
  • 모든 기술이 그렇듯이 주의할 점이 있는데  auto_increment_lock_mode=2 로 적용할 경우에는 복제에서 statement-based replication 이 아니라 row-based replication 을 적용해야합니다. Auto Increment 값이 연속적으로 증가하지 않기 때문에 복제 서버에서는 다른 값이 될 수 있기 때문입니다. 

 

참여 요청에 대한 Throttling 적용:

  • auto_increment_lock_mode 를 튜닝해서 처리할 수 있는 성능을 높혔더라도, 언제든지 MySQL 이 처리할 수 있는 양보다 훨씬 많은 부하를 받을 수 있습니다.
  • 여기서 Throttling 을 적용할 때 중요했던 건 Hot Chat Throttling 과 달리 Throttling 을 지연없이 빠르게 적용할 수 있는가 입니다.
  • Redis 에서도 참여 요청의 수를 집계해서 Throttling 를 적용할 수도 있지만 얼마 안되는 핫 오픈챗에 대해서 전체 오픈챗에 대해 기록하는 건 큰 오버헤드라고 판단해서 Local Cache 에서 집계를 해서 Throttling 을 적용했습니다.

 

Reference: 

https://engineering.linecorp.com/ko/blog/how-line-openchat-server-handles-extreme-traffic-spikes

+ Recent posts