Alarm Service in Server
알림 서비스로 시작하는 서버 개발 / if(kakao)2022
카카오 뱅크가 만든 알림서비스
점점 커저가는 서비스를 Scale out & sharding을 통해 해결.
기존 구조
알림 생성 서버 → 알림 서버 → DB
만약 알림 생성에 부하가 걸린다면?
상황1: cpu 사용률 100%
상황2: 시스템 스레드 고갈
알림 생성에 대한 장애가 알림 조회에 까지 전파되는 상황 발생
🧐 알림 조회까지 문제가 생겨야 하나?
해결방안 1: 알림 서버를 알림 생성, 알림 조회 서버로 분리
생성 서버의 장애가 분리되고, 조회 서버는 원활하게 서비스 제공
✅ 안정적으로 고객에게 서비스를 줄 수 있다
❗ 관리 포인트가 증가
하지만, 알림 생성 요청이 많아져 지연 응답 발생한다면?
상황:
감당할 수 없는 알림생성 요청으로 생성 서버의 스레드가 모두 고갈되고, 응답시간이 느려짐.
이로 인해, 알림때문에, 실제 수행되는 비즈니스 로직이 안됨.
해결 방안 3: 짧은 Timeout 설정과 비동기 호출
서버의 장애가 분리되고, 조회 서버는 원활하게 서비스 제공
✅ 짧은 Timeout 설정 및 비동기 호출로 주요 기능으로 부터 격리가 가능
❗ But. 연계 시스템은 계속 늘어날 것이므로 대책 필요
연계 시스템은 알림 생성 서버를 신뢰하지 못함
어떻게 신뢰있는 생성 서버로 만들 수 있을까?
해결 방안 4: 생성 서버 내부에서 비동기로 알림을 생성
서버의 장애가 분리되고, 조회 서버는 원활하게 서비스 제공
✅ Timeout 설정, 비동기 호출이 아니라, 생성 서버내부에서 비동기로 알림을 생성
연계 시스템은 생성 서버에 알림 생성을 요청
생성 서버는 알림 생성을 비동기로 던지고, 빠르게 응답을 반환
알림시스템의 장애가, 연계시스템으로 전파되는 것을 예방
❗하지만, 연계 시스템은 알림이 정상적으로 만들어졌는지 알 수가 없음
알림 생성 요청 응답을 먼저 받고 그 후, 비동기로 알림이 만들어지기 때문
이에 대비해, 알림 생성 실패 조회 API를 제공
❗실시간으로 알림을 만들어주지는 못함
그러나, 알림 서비스의 특성상, 약간의 지연은 감안 가능
지연 모니터링은 지속 중임.
생성 서버가 다운되거나 재시작되면?
❓
만약 비동기로 알림 생성 중, 서버가 다운되거나 재시작된다면?
❗ 알림은 유실되어 사라짐: 운영 신뢰성을 높이려는 비동기 방식이, 역으로 알림이 유실되어 데이터 신뢰성을 보장할 수 없는 상황을 야기
알림 유실을 위한 개발 및 관리 포인트 증가: 알림이 유실되었는지 확인하고 유실되었다면 재처리 로직이 필요
해결방안 5: Message Queue 도입
목적 : 알림 유실에 대한 관리포인트를 줄이기 위함.
연계 시스템은 생성 서버에 알림 생성 요청
생성 서버는 Queue에 저장 후, 빠르게 연계 시스템에 응답
Queue는 consumer에게 Dequeue
consumer는 알림 생성 비즈니스 로직을 거친 후, DB에 저장
Message Queue 또한 비동기 특성을 갖기 때문에 이전 시스템과 동일하게 비동기성을 갖는다. 알림 요청이 와도 Queue에 넣고 바로 응답하기 때문에 알림 생성 장애/지연이 알림 요청으로 전파될 확률이 낮아짐
Consumer에 장애가 발생하더라도, 큐의 설정에 따라 재처리를 하게됨.
Queue에 장애가 발생하면?
Enqueue의 요청을 받지 못하여 유실되는 알림 발생
해결 방안 6: Database를 두어, Enqueue 요청을 저장
DB를 둠으로써, Queue가 다운되더라도, Enqueue로 받지 못한 요청을 DB에 저장.
추후 재처리가 가능해졌습니다.
최종 아키텍처:
컨슈머에 장애가 발생하여 ACK를 보내지 못하면?
Queue에서는 완료되지 않았기 때문에 설정에 따라 재처리 시도
MQ에 대한 장애도 고려해 봐야 함.
disk에 저장하고 MQ가 재시작하면 disk에서 조회
Queue 장애 시 enque를 막고, 요청을 DB에 저장 → 처리하지 못한 알림을 재처리 가능
알림 조회
App → 알림 조회 서버 → DB
고객에게 안정적이고 빠른 서비스 제공
간단해진 조회, 무거워진 생성
추가 요구사항
12개월 전 알림까지 조회해야 함
대용량의 알림 템플릿을 엑셀로 다운로드/업로드 하고자 함
12개월의 알림 데이터를 보관해야 하지만, 최근 3개월의 알림 데이터가 집중적으로 조회됨
해결 방안 1. DB 분리
Service DB: [90일 전 ~ 오늘] 알림 데이터
빠른 성능, 빈번한 CRUD
Archive DB: [365일 전 ~ 90일 전] 알림 데이터
데이터 변경 X, 낮은 빈도의 데이터 조회, 빠른 성능 제공 X
데이터 압축률이 높은 엔진 사용
추가 요구사항: 알림 파기.
비용적인 측면 고려
Service DB 는 3개월 데이터만 보관하기 떄문에 3개월 초과된 데이터들은 제거해야 함
3개월 이전의 데이터를 삭제해야 한다면?
Delete 쿼리를 사용해 제거하면 I/O 부하, 락이 지속적으로 잡히는 등의 부하 문제가 있고, 서비스에 영향을 줄 수 있음.
해결방안 2. Partitioning
하나의 큰 테이블을 월 별로 저장하는 파티셔닝 수행
안정적으로 달 별로 데이터 보관
월별 테이블만 제거하면 되어서 용이함
유지 보수에 용이
단점: 어떻게 테이블을 찾아가야 할지에 대한 기준(key) 가 필요
알림 개수가 달 별로 달라질 수 있다는 문제
애플리케이션이 복잡해짐
고객수도 늘어나고 서비스도 다양해져, 알림 수, 트래픽이 증가
점점 커져가는 서비스에 대한 대비를 해보자
해결방안 3. Application Scale-Out
✅ Application 서버가 분산하여 요청 처리
CPU 사용률 50%를 넘으면 서버 추가 고려하는 편임
하지만, 애플리케이션만 확장한다고 커지는 서비스 트래픽을 감당할 수 없음
그에 맞춰 DB도 확장해야함.
해결방안 4. Sharding
늘어나는 트래픽을 위해 DB도 확장
같은 테이블 구조를 가진 데이터를 다수에 DB에 분산하여 저장하는 기법.
성능을 높이지만 관리 복잡도 높임
데이터를 찾아가기 위해 어떤 DB로 요청해야할지 지정해야 함
❗ 하지만, DB 확장 시
DB: 균등한 요청을 위해 데이터 재분배
애플리케이션: 올바른 DB로의 라우팅 재설정 필요
해결방안 5. DB 스키마 기능으로 DB 확장 문제 해결
DB: 4개의 DB와 각 DB에는 4개의 스키마가 존재.
애플리케이션: 알고리즘을 통해 라우팅
확장이 필요할 때
4개의 DB 추가하여 스키마를 통째로 옮기는 작업 수행
변경된 스키마에 맞는 DB URL로 수정하여 라우팅 (라우팅 용이)
느낀점:
카카오뱅크의 알림 시스템 개선 과정을 통해, 서비스가 성장할수록 단순한 확장이 아닌 구조적 분리와 장애 격리가 중요하다는 점을 배웠습니다. 특히 비동기 처리, 메시지 큐 도입, 파티셔닝 및 샤딩을 단계적으로 적용하며 신뢰성과 확장성을 확보해가는 접근이 인상 깊었습니다. 시스템 설계 시, 실시간성보다 유실 방지와 회복 가능성이 더 중요할 수 있다는 점을 느꼈고, 테크 리뷰를 바탕으로 제 개발에도 반영해볼 기회가 있으면 좋겠습니다.
Last updated