본문 바로가기
카테고리 없음

AWS Lambda와 DynamoDB로 치지직 방송 알림 디스코드 봇 구축하기

by junah201 2026. 10. 31.

치지직 스트리머의 방송 시작을 감지해 디스코드 채널에 자동으로 알림을 전송하는 서비스를 구축하려면 어떤 아키텍처가 필요할까요? 이번 프로젝트에서는 AWS Lambda, Amazon DynamoDB, Amazon EventBridge를 활용해 별도의 상시 실행 서버 없이 동작하는 서버리스 방송 알림 봇을 개발했습니다.

단순히 방송 상태를 확인하고 메시지를 보내는 기능부터 데이터 모델 설계, Lambda 실행 시간 최적화, 동시성 제한 문제 해결까지 실제 운영 과정에서 마주한 기술적 문제와 해결 방법을 소개합니다.

1. 치지직 방송 알림 봇의 개발 목표와 아키텍처

이번 프로젝트의 핵심은 적은 운영 비용으로 안정적인 방송 알림 서비스를 구현하는 것입니다. 특히 서버를 직접 관리하지 않고도 등록된 스트리머가 늘어나는 상황에 대응할 수 있는 구조를 설계하는 데 중점을 두었습니다.

서버리스 아키텍처를 선택한 이유

DynamoDB를 활용한 사이드 프로젝트를 고민하던 중 네이버의 게임 스트리밍 플랫폼인 치지직이 등장했습니다. 이를 계기로 치지직 스트리머의 방송 시작을 디스코드로 알려주는 서비스를 개발하기로 했습니다.

초기 개발 단계에서 설정한 목표는 다음과 같습니다.

  • 빠른 알림 전달: 스트리머가 방송을 시작한 뒤 5분 이내에 알림을 전달합니다.
  • 웹 기반 관리: 사용자가 웹 대시보드에서 알림 설정을 추가하거나 삭제하고, 테스트할 수 있도록 합니다.
  • 서버리스 운영: API부터 디스코드 봇의 명령어 처리까지 AWS Lambda 중심으로 구현합니다.
  • 낮은 운영 비용: 월간 AWS 사용료를 5,000원 이하로 유지하는 것을 목표로 합니다.

서버리스 구조를 선택한 이유는 별도의 EC2 인스턴스를 상시 운영하지 않아도 되기 때문입니다. 작업이 발생할 때 필요한 컴퓨팅 자원을 실행하는 방식을 활용하면 서버 관리 부담을 줄일 수 있습니다.

다만 서버리스라고 해서 비용이 항상 저렴한 것은 아닙니다. 함수 호출 횟수, 실행 시간, 데이터베이스 요청량, 외부 API 호출 빈도 등에 따라 실제 비용이 달라집니다.

2. 치지직 방송 상태를 확인하는 API 분석

방송 알림 기능을 구현하려면 먼저 특정 스트리머가 현재 방송 중인지 확인할 방법이 필요합니다. 치지직 웹사이트에서 사용하는 네트워크 요청을 분석해 방송 정보를 확인할 수 있는 API를 찾아보았습니다.

방송 정보 조회 API의 구조

치지직의 개별 라이브 페이지는 다음과 같은 형태로 접근할 수 있습니다.

https://chzzk.naver.com/live/{채널ID}

브라우저 개발자 도구의 Network 탭에서 Fetch/XHR 요청을 확인하면 live-detail이라는 이름의 방송 정보 조회 요청을 찾을 수 있습니다. 당시 확인한 응답에는 방송 상태와 채널에 관한 여러 정보가 포함되어 있었습니다.

대표적인 데이터는 다음과 같습니다.

  • liveId: 방송을 식별하는 고유 ID
  • liveTitle: 방송 제목
  • liveImageUrl: 방송 미리보기 이미지 주소
  • status: 방송 진행 상태
  • channelId: 치지직 채널 식별자
  • channelName: 스트리머 채널명

당시에는 별도의 로그인 없이 해당 정보를 조회할 수 있었습니다. 따라서 이 데이터를 주기적으로 확인하면 방송 시작 여부를 판별할 수 있다고 판단했습니다.

다만 웹사이트 내부에서 사용하는 API는 공식적인 외부 개발자용 API와 다를 수 있습니다. 응답 형식이나 접근 정책이 변경될 가능성이 있으므로 실제 서비스를 운영할 때는 최신 정책을 확인하고 요청 빈도 제한을 준수해야 합니다.

방송 시작을 판별하는 방법

핵심 아이디어는 마지막으로 확인한 방송 ID와 현재 조회한 방송 ID를 비교하는 것입니다.

예를 들어 데이터베이스에 저장된 마지막 방송 ID가 6309322이고, 새롭게 조회한 방송 ID가 6309324라고 가정하겠습니다. 이때 현재 방송 상태가 OPEN이라면 새로운 방송이 시작된 것으로 판단할 수 있습니다.

반대로 방송 상태가 종료 상태이거나 새로운 방송 ID가 확인되지 않았다면 알림을 전송하지 않습니다.

이 방식은 방송 상태를 매번 복잡하게 분석하지 않고도 이전 데이터와 현재 데이터를 비교해 변경 사항을 감지할 수 있다는 장점이 있습니다.

다만 방송 ID가 변경되었다는 사실만으로 항상 새로운 방송 시작을 확정할 수 있는 것은 아닙니다. 실제 구현에서는 방송 상태, 마지막 처리 기록, 중복 실행 가능성 등을 함께 고려해야 합니다.

3. DynamoDB 단일 테이블 설계와 데이터 접근 패턴

방송 알림 서비스에서는 스트리머 정보와 디스코드 알림 설정을 효율적으로 조회할 수 있어야 합니다. 이를 위해 Amazon DynamoDB의 파티션 키와 정렬 키, 글로벌 보조 인덱스(GSI)를 활용했습니다.

저장해야 하는 데이터와 관계

관계형 데이터베이스를 기준으로 생각하면 필요한 데이터는 크게 두 종류입니다.

첫 번째는 치지직 채널 정보입니다. 채널 ID와 마지막으로 확인한 방송 ID를 저장합니다.

두 번째는 알림 설정입니다. 어떤 디스코드 서버 또는 채널이 특정 치지직 스트리머의 방송 알림을 받을지 기록합니다.

한 스트리머의 방송 알림을 여러 디스코드 채널에 등록할 수 있으므로 두 데이터 사이에는 일대다(1) 관계가 형성됩니다.

이번 설계에서는 여러 테이블을 개별적으로 관리하는 대신 단일 테이블 설계(Single-Table Design) 를 적용했습니다. DynamoDB에서는 데이터가 어떻게 저장되는지뿐 아니라 실제 서비스에서 어떤 조건으로 데이터를 조회하는지가 중요하기 때문입니다.

세 가지 주요 데이터 조회 패턴

테이블을 설계하기 전에 서비스가 반복적으로 수행할 조회 작업을 정리했습니다.

  1. 방송 상태를 확인하기 위해 등록된 모든 치지직 채널을 조회합니다.
  2. 특정 치지직 채널에 연결된 모든 알림 설정을 조회합니다.
  3. 특정 디스코드 서버에 등록된 전체 알림 설정을 조회합니다.

이 세 가지 접근 패턴을 효율적으로 지원하도록 기본 키를 구성하고, 기본 키만으로 처리하기 어려운 조회는 GSI로 보완했습니다.

파티션 키와 정렬 키 구성

치지직 채널 정보와 알림 설정을 같은 테이블에 저장하기 위해 데이터 종류를 구분하는 접두사를 사용했습니다.

치지직 채널 정보는 다음과 같은 구조입니다.

  • PK: CHZZK#bb382c2c0cc9fa7c86ab3b037fb5799c
  • SK: CHZZK#bb382c2c0cc9fa7c86ab3b037fb5799c

여기서 PK는 파티션 키(Partition Key), SK는 정렬 키(Sort Key)입니다. 동일한 채널 ID를 두 키에 사용해 채널 정보를 고유하게 식별하도록 구성했습니다.

알림 설정은 다음과 같이 저장합니다.

  • PK: CHZZK#bb382c2c0cc9fa7c86ab3b037fb5799c
  • SK: DISCORD#1235906309161750583

이 구조에서는 동일한 치지직 채널 ID를 가진 항목을 조회하면 해당 채널의 정보와 연결된 알림 설정을 함께 가져올 수 있습니다.

또한 CHZZK#, DISCORD#와 같은 접두사를 활용하면 데이터 종류를 명확하게 구분할 수 있습니다. 이는 단일 테이블에 서로 다른 유형의 데이터를 저장할 때 유용한 패턴입니다.

GSI를 활용한 역방향 조회

기본 키 구조만으로는 특정 디스코드 서버에 등록된 알림을 효율적으로 찾기 어렵습니다. 알림 설정의 기본 PK가 치지직 채널 ID이기 때문에 디스코드 서버 ID를 기준으로 조회하려면 별도의 접근 경로가 필요합니다.

이 문제를 해결하기 위해 글로벌 보조 인덱스(Global Secondary Index, GSI)를 추가했습니다. GSI는 기본 테이블의 PK와 SK 외에 다른 속성을 기준으로 데이터를 조회할 수 있도록 지원합니다.

예를 들어 알림 항목에 디스코드 서버 ID를 저장하고 이를 GSI의 파티션 키로 사용하면 특정 서버에 연결된 알림 설정을 효율적으로 검색할 수 있습니다.

단일 테이블 설계에서 중요한 점은 무조건 테이블 수를 줄이는 것이 아닙니다. 실제 조회 패턴에 맞는 키와 인덱스를 설계해 불필요한 데이터 검색과 비용을 줄이는 것이 핵심입니다.

4. AWS Lambda와 EventBridge를 이용한 방송 감지

데이터 구조를 설계한 뒤에는 방송 상태를 주기적으로 확인하는 Lambda 함수를 구현했습니다. 함수 이름은 live_check로 지정했으며, EventBridge가 정해진 간격으로 함수를 실행하도록 구성했습니다.

방송 확인부터 디스코드 알림까지의 처리 과정

live_check 함수는 다음과 같은 순서로 동작합니다.

  1. DynamoDB에서 방송 확인 대상인 치지직 채널 정보를 조회합니다.
  2. 각 채널의 ID를 사용해 치지직 방송 정보 API를 요청합니다.
  3. 응답에서 현재 방송 상태와 방송 ID를 확인합니다.
  4. 이전에 저장한 방송 ID와 비교해 새로운 방송인지 판단합니다.
  5. 새로운 방송이 확인되면 해당 스트리머의 알림을 구독하는 디스코드 채널을 조회합니다.
  6. 대상 디스코드 채널에 방송 정보를 전달합니다.
  7. 처리한 방송 정보를 저장해 다음 실행에서 중복 알림을 방지합니다.

이처럼 Lambda는 방송 상태 확인, 데이터 조회, 알림 전송을 수행하는 실행 단위로 사용됩니다. EventBridge는 정해진 일정에 따라 해당 작업을 시작하는 역할을 담당합니다.

서버를 직접 유지 관리하지 않아도 된다는 점은 장점이지만, 등록된 채널이 많아지면 한 번의 실행에서 처리해야 하는 API 요청이 늘어납니다. 결국 전체 시스템의 성능은 Lambda의 실행 시간과 외부 API의 응답 속도에 영향을 받게 됩니다.

알림이 전송된 모습

5. 등록 채널 증가로 발생한 Lambda 실행 시간 문제

초기에는 방송 확인 작업이 큰 문제 없이 동작했습니다. 그러나 서비스에 등록되는 스트리머와 알림 설정이 증가하면서 live_check 함수의 실행 시간이 점차 길어졌습니다.

실행 시간 그래프

순차적인 API 요청의 한계

기존 구조에서는 각 채널에 대한 API 요청을 하나씩 처리했습니다. 이전 요청의 응답을 기다린 뒤 다음 채널을 확인하는 방식이므로 채널 수가 늘어날수록 전체 실행 시간이 길어졌습니다.

예를 들어 한 번의 실행에서 수천 개의 채널을 확인해야 한다면, 개별 요청의 응답 시간이 짧더라도 전체 처리 시간은 상당히 길어질 수 있습니다.

초기에는 약 5분 간격으로 실행되도록 설정했지만, 함수 실행 시간이 5분을 넘기기 시작하면서 실행 간격을 약 7분으로 조정했습니다. 이후 실행 시간이 10분을 초과하는 상황이 발생하자 실행 주기를 약 15분으로 변경했습니다.

하지만 실행 간격을 늘리는 방식은 처리 시간을 줄이는 근본적인 해결책이 아닙니다. 방송 확인 작업이 길어지면 알림 전달이 늦어지고, 등록 채널이 계속 증가할 경우 동일한 문제가 반복될 수 있습니다.

비동기 요청만으로 해결하기 어려웠던 이유

실행 시간을 단축하기 위해 여러 API 요청을 비동기로 처리하는 방법도 검토했습니다. 요청을 병렬로 보내면 전체 처리 시간을 줄일 수 있지만, 외부 API의 요청 제한을 고려해야 합니다.

당시에는 치지직 API의 Rate Limit에 걸릴 가능성이 있어 무제한으로 요청을 병렬화하는 방법을 적용하기 어려웠습니다.

따라서 단순히 요청 수를 늘리는 대신, 방송 확인 작업 자체를 여러 실행 단위로 나누어 처리하는 방향으로 접근했습니다.

6. 채널 ID를 기준으로 방송 확인 작업 분산하기

실행 시간 문제를 해결하기 위해 방송 확인 대상을 여러 그룹으로 나누는 방식을 도입했습니다. 핵심은 모든 Lambda가 전체 채널을 처리하는 대신, 각 함수가 자신에게 할당된 채널만 확인하도록 만드는 것입니다.

채널 ID를 이용한 그룹 분할

치지직 채널 ID는 다음과 같은 16진수 문자열 형태입니다.

bb382c2c0cc9fa7c86ab3b037fb5799c

이 값을 정수로 변환한 뒤 10으로 나눈 나머지를 계산하고, 그 결과를 index 속성에 저장했습니다.

계산 결과는 0부터 9까지 총 10개의 그룹으로 나뉩니다. 예를 들어 나머지가 1인 채널은 1번 그룹에, 나머지가 9인 채널은 9번 그룹에 할당하는 방식입니다.

당시에는 특정 그룹에 채널이 집중되지 않을까 우려했지만, 실제 데이터에서는 비교적 고르게 분배되는 결과를 확인했습니다.

다만 해시나 나머지 연산을 이용한 분산 방식이 모든 데이터에서 균등한 분포를 보장하는 것은 아닙니다. 채널 ID의 분포와 그룹별 데이터 수를 지속적으로 관찰하는 것이 중요합니다.

EventBridge 트리거를 활용한 실행 분산

채널을 10개 그룹으로 분리한 다음, live_check Lambda에 각 그룹을 담당하는 트리거를 구성했습니다.

각 실행은 자신에게 할당된 index에 해당하는 채널만 조회하도록 변경했습니다. 이를 통해 하나의 함수가 전체 채널을 순차적으로 확인하던 구조를 여러 함수 실행이 각각 일부 채널을 처리하는 구조로 바꾸었습니다.

그 결과 기존에 비해 실행 시간이 약 10분의 1 수준으로 감소했습니다. 이후 등록 채널이 증가하더라도 한 번의 실행에서 처리하는 데이터가 제한되므로 실행 시간 증가폭도 줄어들었습니다.

다만 실제 개선 효과는 그룹별 데이터 분포, API 응답 시간, Lambda 설정과 동시 실행 상황에 따라 달라질 수 있습니다.

또한 여러 작업이 동시에 실행될 수 있으므로 방송 ID를 저장하는 시점과 중복 알림 방지 로직도 함께 설계해야 합니다.

7. Lambda 동시성 제한으로 발생한 API 오류

작업 분산을 적용한 뒤 실행 시간은 크게 개선되었지만, 새로운 문제가 나타났습니다. API Gateway에 연결된 Lambda에서 간헐적으로 오류가 발생했으며, 함수 내부 로그만으로는 원인을 파악하기 어려웠습니다.

CloudWatch 지표에서 발견한 스로틀링

문제를 조사하는 과정에서 AWS 모니터링 대시보드의 스로틀링(Throttling) 지표가 급격하게 증가한 것을 확인했습니다.

Lambda에는 계정 및 리전 단위의 동시 실행 제한이 있습니다. 여러 함수가 동시에 실행되면서 해당 한도를 초과하면 새로운 호출이 제한될 수 있습니다.

당시 사용하던 계정의 기본 동시 실행 한도는 10이었습니다. live_check 작업을 10개 그룹으로 나누면서 여러 실행이 겹칠 경우 사용 가능한 동시성 자원을 대부분 점유할 수 있는 구조가 되었습니다.

이로 인해 API 요청을 처리하는 다른 Lambda가 실행 자원을 확보하지 못하면서 간헐적인 오류가 발생한 것으로 판단했습니다.

중요한 점은 Lambda 함수 내부에서 예외가 발생한 경우와, 함수가 실행되기 전 동시성 제한에 걸린 경우를 구분해야 한다는 것입니다. 후자의 경우에는 애플리케이션 코드의 오류 로그만으로 원인을 확인하기 어려울 수 있습니다.

동시성 자원 확보와 트리거 수 조정

우선 방송 확인용 트리거 수를 10개에서 6개로 줄여 동시 실행 부담을 낮췄습니다. 이후 AWS에 동시 실행 한도 상향을 요청해 다른 API 함수가 사용할 수 있는 여유 자원을 확보했습니다.

이 경험을 통해 Lambda를 여러 개로 분리하는 것만으로 성능 문제가 완전히 해결되지는 않는다는 사실을 확인했습니다.

작업을 병렬화하면 처리 시간은 단축될 수 있지만, 그만큼 동시에 실행되는 함수 수도 증가합니다. 따라서 실행 시간 최적화와 동시성 자원 관리는 함께 고려해야 하는 설계 요소입니다.

운영 환경에서는 함수별 예약 동시성, 계정 전체 동시성 한도, EventBridge 실행 주기, 외부 API의 요청 제한 등을 종합적으로 검토하는 것이 좋습니다.

8. 웹 대시보드와 서버리스 기반 운영 구조

방송 감지 기능 외에도 사용자가 알림 설정을 직접 관리할 수 있도록 웹 대시보드를 구축했습니다. 이를 통해 디스코드 채널에 알림을 등록하거나 삭제하고, 설정한 알림이 정상적으로 작동하는지 테스트할 수 있도록 했습니다.

웹 대시보드는 치지직 방송 알림 서비스에서 확인할 수 있습니다.

또한 API뿐 아니라 디스코드 봇의 슬래시 명령어 처리도 AWS Lambda를 통해 실행하도록 구성했습니다. 별도의 상시 실행 봇 프로세스를 운영하지 않고도 필요한 기능을 제공하는 것이 목표였습니다.

서버리스 환경에서는 각 기능을 독립된 실행 단위로 나누기 쉽고, 사용량에 따라 자원을 관리할 수 있다는 장점이 있습니다. 반면 함수별 실행 제한, 권한 설정, 오류 추적, 외부 서비스 연결 상태 등을 체계적으로 관리해야 합니다.

특히 외부 API를 호출하는 서비스는 네트워크 오류와 요청 제한이 발생할 수 있으므로 적절한 재시도 정책과 타임아웃 설정을 고려해야 합니다. 재시도 과정에서 동일한 알림이 여러 번 전송되지 않도록 멱등성(Idempotency)을 확보하는 것도 중요합니다.

9. 치지직 방송 알림 봇의 운영 결과와 비용

프로젝트를 통해 초기 목표 중 대부분의 기능을 구현했지만, 알림 전달 시간과 월간 운영 비용에서는 목표와 차이가 있었습니다. 이는 서비스 규모가 증가하면서 성능과 비용 사이의 균형을 고려해야 했기 때문입니다.

방송 알림 전달 시간과 관리 기능

초기 목표는 방송 시작 후 5분 이내에 알림을 전달하는 것이었습니다. 그러나 작성 당시 등록된 치지직 채널 수가 7,053개에 도달하면서 모든 채널을 더 짧은 간격으로 확인하는 데 드는 비용을 고려해야 했습니다.

이에 따라 알림 전달 목표를 조정했으며, 당시 운영 기준으로 약 8분 이내에 알림을 전달하는 것을 목표로 삼았습니다. 이는 모든 상황에서 보장되는 실시간 성능을 의미하지 않으며, 실제 전달 시간은 API 응답과 처리 지연에 따라 달라질 수 있습니다.

웹 대시보드에서는 알림 추가, 삭제, 테스트 기능을 제공해 사용자가 직접 설정을 관리할 수 있도록 했습니다.

서버리스 목표와 실제 AWS 비용

모든 API와 디스코드 봇의 슬래시 명령어 처리를 Lambda 중심으로 구현한다는 목표는 달성했습니다.

반면 월간 AWS 비용을 5,000원 이하로 유지하겠다는 목표는 달성하지 못했습니다. 당시 기록 기준으로 월간 비용은 약 11달러였습니다.

서버리스 아키텍처는 서버 관리 비용을 줄일 수 있지만, 실행 빈도와 처리량이 증가하면 비용도 함께 증가할 수 있습니다. 따라서 서비스 규모가 커질수록 Lambda 실행 시간, DynamoDB 읽기 및 쓰기 요청, 로그 저장량 등을 정기적으로 확인해야 합니다.

단순히 가장 저렴한 설정을 선택하는 것보다 알림 지연 시간, 안정성, 운영 비용을 함께 고려해 적절한 균형점을 찾는 것이 중요합니다.

10. 서버리스 방송 알림 시스템에서 얻은 교훈

이번 프로젝트는 AWS Lambda와 DynamoDB만으로도 상당한 규모의 방송 알림 서비스를 구성할 수 있음을 보여주었습니다. 동시에 서비스 규모가 커지면 데이터 모델뿐 아니라 외부 API 제한과 컴퓨팅 자원 관리까지 함께 고려해야 한다는 점을 확인했습니다.

첫째, DynamoDB에서는 데이터 구조를 먼저 설계하기보다 실제 조회 패턴을 먼저 정의하는 것이 중요합니다. 단일 테이블 설계와 GSI를 적절히 활용하면 여러 유형의 데이터를 효율적으로 관리할 수 있습니다.

둘째, Lambda의 실행 시간이 길어질 때는 실행 간격을 늘리는 것만으로 문제를 해결하기 어렵습니다. 작업을 여러 그룹으로 나누고 각 실행이 담당하는 데이터 범위를 제한하면 처리 시간을 줄일 수 있습니다.

셋째, 병렬 실행은 성능 개선과 함께 동시성 사용량 증가를 가져옵니다. Lambda를 분산할 때는 다른 API 함수가 사용할 수 있는 실행 자원도 확보해야 합니다.

넷째, 서버리스 환경이라고 해서 비용이 자동으로 낮아지는 것은 아닙니다. 실제 사용량을 바탕으로 실행 시간과 요청량을 분석하고, 서비스가 제공해야 하는 알림 지연 시간에 맞춰 실행 주기를 조정해야 합니다.

마지막으로, 이 프로젝트에서 가장 큰 의미는 단순한 기능 구현을 넘어 실제 운영 과정에서 발생한 문제를 데이터와 모니터링 지표를 통해 해결했다는 점입니다. 서버리스 시스템을 설계할 때는 초기 구현뿐 아니라 서비스 규모가 증가했을 때의 확장성과 장애 대응 방법까지 함께 고려해야 합니다.

프로젝트 소스 코드는 GitHub 저장소에서 확인할 수 있습니다.

기술적인 개선 사항이나 새로운 기능에 대한 Issue와 Pull Request도 환영합니다.