오늘은 우아콘 2020...이라 좀 오래됐지만
기업에서는 MSA를 어떻게 적용하게 되었는지 궁금해서
배달의 민족 김영한님의 세션 > 마이크로서비스 여행기를 시청하고 내용을 정리했다.
https://www.youtube.com/watch?v=BnS6343GTkY
2015
2015년의 배민은 모든 서비스가 루비 DB에 연결되어있었다.
따라서 루비가 죽는 순간 모든 서비스가 죽는다.
이때는 리뷰 테이블에 뭔가 문제가 있었는데, 하나의 오류가 다른 서비스 전체에 영향을 주었다.
생각해보면, 리뷰는 부가 기능이다.
따라서 리뷰 서비스에서 장애가 발생해도 고객이 주문하는 데 문제가 없어야 하는 것이 상식적이다.
2016
2016년부터는 하루 주문수가 10만을 돌파한다.
기존에는 php를 사용했지만, 이후 java로 교체하게 된다.
이러한 선택을 한 이유는 2가지였다.
1) 자바가 대용량 트래픽 안정적이다.
2) 국내 개발자 수급이 용이하다.
그리고 이때부터 MSA로의 도전을 시작하고,
결제, 주문중계를 독립시켰다.
여기에 더해 AWS 클라우드 인프라로 이전을 시작한다.
내가 느낀 가장 인상깊은 부분은 이 지점이었다.
MSA를 기술적으로 하고 싶어서라기 보다는
매년 2.3배가 주문이 느는 상황에서 다들 서버가 버틸 수 있을지, 레거시를 감당할 수 있을지 걱정하기 시작했다.
기존 시스템에서 계속 장애가 나고 해결하기 어려웠기 때문에 배민은 MSA로 갈 수밖에 없는 상황에 직면했다.
+) 넷플릭스에서는 MSA가 기술적 선택이 아니라 생존의 문제였다고 한다.
지금은 배달 주문은 앱으로 하는 것이 배민 덕분에 정말 당연해졌지만,
옛날을 기준으로 생각해보면 배민의 결제 서비스가 죽어도 전화로 주문하면 된다.
진짜 옛날에는 배달책(?) 같은 거에서 찾아보고 전화 주문을 많이 했었지...🥹
게다가 그 시절에는 법적으로 돈과 관련된 것을 클라우드에 올릴 수 없어서 결제는 IDC일 수밖에 없었다고 한다.
주문 중계
주문 중계 서비스는 간단히 포워딩하는 서버이다. 예를 들어 가게에 주문이 들어오면 사장님은 앱, PC, 단말기 등에서 주문을 확인할 수 있는데 주문 접수를 중간에서 포워딩해준다.
파리바게뜨 알바생으로 3년동안 일했었는데, 배민에서 보통 주문이 들어오면 사장님 폰이 제일 먼저 울린다 (카톡)
그리고 조금의 시간이 지나서 포스기에도 알림이 온다.
하나의 주문 접수에 대해서 여러 기기로 알림을 주는 형태!
중간에서 가볍게 node.js로 돌아가고 있었지만
(배민의 메인 기술이 Java였지만 필요성에 의해서 조금씩 맞는 기술 스택을 선택했다고 한다)
나중에는 무거워져서 java로 바꾸게 된다.
치킨 디도스
사람들이 선착순 할인에 환장한다고 한다.
개발자들은 매우 싫어한다.
1일차
생각한 것보다 몇배 이상 트래픽이 몰렸다.
프론트 서버 자체가 죽어서 백엔드 주문 단에 들어오지도 못했다.
2일차
근데 다음날도 이벤트가 있었다... 빨리 수습을 해야하는 상황.
이때 개발자들이 기적을 보여준다.
기존의 IDC에서 AWS로의 이전이 한 달짜리 프로젝트였는데
IDC 장비를 도저히 수급할 수 없어서 프론트 서버 이전이 하루가 걸렸다.
그래서 결국 프론트 단에서는 트래픽 받을 수 있었는데 주문 서버(IDC에 있던게) 죽어버렸다.
DB는 스펙이 좋아서 IDC로 버텼는데 프론트 서버, 주문 서버는 버틸 수가 없어서 AWS로 이전하게 된다.
3일차
배민에서 AWS로 어지저찌 서버를 늘려서 결제도 잘 되었다.
그런데 그 다음 단인 PG사에서 트래픽을 감당하지 못하고 죽어버렸다.
이 부분도 인상깊었다. 개발자의 입장에서 내가 개발하는 것의 모든 것을 고려하고
대책을 마련해두었는데 그게 끝이 아니라는 점. 현직자로 일하는 것은 이렇게나 머리 아픈 일이구나, 이게 현실이구나라는 점이 느껴졌다.
4일차
PG사에서 2배의 장비를 투입했고 치킨 디도스가 성공했다.
2017
이때부터는 하루 주문 수기 20만 건을 돌파했다.
AWS로 이전하고 있긴 했지만, 일부에 불과했고 비즈니스 로직을 손볼 것들이 너무 많았다고 한다.
트래픽은 계속 느는데 시스템은 레거시인 상태라 이때를
"대장애의 시대"라고 부른다.
주말 오후 5시가 긴장의 시간!
배민이 안 되면 전화 주문이라도 할 줄 알았는데(옛날 기준), 그렇지 않다고 한다.
치킨 먹고 싶다고 딱 들고 바로 주문까지 되어야 하는데 안 되면 엄청 짜증이 난다.
배민이 아닌 요기요에서 주문하게 된다.
나는 여기에서 사용자가 이탈하나? 라는 아기 대학생같은 생각을 했는데...(이건 정말 어쩔 수 없는 것 같다)
배민이 죽으면 요기요로 가서 요기요 서버가 터진다. 요기요가 안되면 또 다른 어플로 가서 거기 서버가 죽는다.
이 부분이 나에게 또 인상깊은 부분이었고, 개발 뿐만 아니라 도메인 지식이 왜 중요할지를 다시 한 번 느꼈다.
그래서, 배민은 생존에 의해 MSA를 해야한다고 느끼게 되었다.
- 루비 DB에서 elastic search로 가게 목록 + 검색을 빼냈다.
- 결과적으로는 루비 부하가 좀 줄었다.
2018
회사에서는 레거시 시스템을 개선하는 일이 우선순위가 높아지기 어렵다.
왜냐하면 매출에 거의 영향을 안 주기 때문이다.
따라서 윗선에 레거시 시스템 개선을 설득하기 매우 어렵다.
이 시기에는 하나의 가게는 하나의 광고만 할 수 있었다.
그러다보니 여러개의 광고를 하기 위해 사장님이 가게를 하나 더 파는 꼼수(?)가 발생했다.
그래서 개발자들은 하나의 가게가 여러 광고를 할 수 있게 만들고 싶었고,
여러 광고를 하는 데 이득이 발생하니 회사도 그 방향이 더 이득이었다.
하지만 이때는 장애에 대응하는 게 더 중요하다고 판단했고 미뤄지게 되었다.
- 가게 상세 (주요 장애 포인트)
- 쿠폰, 포인트 탈루비
- 오프라인 모드 적용
이때의 프론트 서버는 php로, 루비 DB를 바라보고 있었다.
루비를 다이나모 DB로 옮기고 싶었고
배치 작업을 1~5분 주기로 돌려 AWS 다이나모 DB로 데이터를 퍼부었다.
이러면 어쨌든 루비 DB로 가는 부담이 줄었다.
다이나모 DB는 차로 따지면 스포츠카이다.
트래픽을 매우 잘받지만 싱크가 좀 안 맞는 문제가 있었다. (당연함)
게다가 요구사항 바뀌면 수천줄짜리 배치 쿼리도 계속 바꾸어야 한다는 문제가 있었다.
주문, 리뷰 탈루비
배민 서비스에서는 주문이 제일 복잡하다.
왜냐하면 모든 시스템이랑 다 엮여있기 때문이다.
주문에 메뉴, 정산, 주문중계, 쿠폰, 포인트, 결제까지 엮여있는 상태이다.
레거시 3대장
1. 주문
- 지금까지 쌓인 주문 데이터 수억건.
- 비즈니스 연관도가 높다.
- 지금은 하루 수백만 데이터가 쌓인다
2. 가게/업주
- 가게/업주 데이터는 무조건 필요하다.
3. 광고
- 프로시저 사용 1위
- 돈을 다루다 보니까.. 돈 문제 삐끗하면 큰일난다. 회사의 메인 수익원 역할.
콘웨이의 법칙
시스템 설계가 조직의 구조를 따라간다.
주문서버
이때의 주문 서버는 이렇게 두 개로 나뉘어 개발되고 있었다.
1. 배민 주문 로직 > 배민 테이블
2. 라이더스 주문 로직 > 라이더스 테이블
심지어 조직도 달랐다.
그런데 문제는 배민 라이더스는 배민이랑 비슷하게 만들었다.
똑같은 거 같은데 다르고... 완전 다르지도 않고....(애매함..)
그래서 나중에 시스템을 통합하기로 했다.
하지만 통합이 잘 안 됐다. 그래서 그냥 따로 서비스를 하고 있던 상황이었다.
그래서 아예 새로운 주문 테이블을 설계하게 되었다.
도메인 하나로 정리하고 애플리케이션 레벨에서 나눠서 서비스했다.
여기에서 크게 두 가지 방법이 있었다.
1️⃣ 주문 시스템 -> (기존) API 기반 데이터 전달
1. 리뷰 시스템 전달
2. 레거시 DB 싱크
3. 라이더스 시스템
ex. 음식 받으면 리뷰 쓰라는 푸쉬 알림을 API로 줌.
2️⃣ 이벤트 기반의 MSA
이벤트를 네 가지로 정의한다 : 생성, 접수, 배달완료, 취소
그러면 주문 시스템은 이벤트만 발행한다.
여러 시스템이 리뷰 시스템을 consume만 하는 방식으로 작동한다.
이러면 다른 시스템이랑 주문 시스템이랑 상관이 없다.
리뷰 시스템이 죽었다 살면 SQS에 쌓여 있으면 깨어나서 다시 consume하면 된다.
결과적으로 회복력이 좋아지는 효과가 있다.
이제 주문 시스템은 SQS를 만들고 시스템에 꽂기만 하면 된다.
또한 주문팀이 행복해지는 효과도 있었다.
"연동해주세요" X ➡️ SQS만들테니 꽂아서 쓰세요.
여기에서 내가 예전에 개발했던 서버 관리 자동화 시스템이 생각났다.
나도 API를 외부 서버로 호출하는 일이 있었는데
외부 서버에 대한 의존성이 늘어나는 것 같고 처리 안 되면 어쩌지 불안불안...
막말해서... 요청 들어왔는데 까치가 또 날아들어서 서버 꺼지면 어떡함? 이라능 생각도...
그럼 중간에 없어진 애는 어케 되는 거지...😬
+ 연동에 대한 부담은 덤. 계속 바뀌는 API 문서를 확인하고 반영하느라 지쳤는데
이벤트 기반으로 전체적으로 개선하면 좋을 거 같단 생각이 들었다.
남은 레거시 2대장!
2. 가게 업주
3. 광고
이전에 가게랑 광고랑 1:1이라고 했었다.
이걸 바꾸기 어려웠던 이유가 가게(shop) 테이블 안에 광고가 컬럼으로 들어가있었다.
컬럼으로 들어가있어서 떼어내기가 어려운 상황이었다.
그래서 이 프로젝트 하려면 서비스를 stop 해야한다. ㅠㅠ
이거 손대면 저거가.. 저거 손대면 저거가...
기술적으로 MSA로 가려면 3~4달은 서비스 중단해야한다.
프로젝트 먼데이
그래서 '프로젝트 먼데이'라는 것을 진행한다.
이 프로젝트에만 기술을 집중하겠다는 의사결정을 하였다.
특히 이 프로젝트는 하나만 바꿔서 해결할 수 없는 문제였고, 하나 손대면 다 문제가 생기는 상황이었다.
우선 이렇게 분리한다.
1. 가게 상세 > 가게 노출 CQRS(Command Query Responsibility Segregation) 모델 사용 (서비스 조회용 가게 data를 분리한다.)
2. 가게 목록 + 검색 > 광고 리스팅, 검색
이때 API 조회 형식 vs CQRS 아키텍처 중 어떠한 의사결정을 했을까?
1안 - API 조회 형식으로.
- 데이터 동기화에 대한 고민이 필요없고, 간단하다.
- 장애 전파가 전파된다. 즉, 하나가 죽으면 연쇄적으로 죽는다.
- 고성능 조회의 트래픽이 이곳 저곳... 다른 도메인으로 전파된다.
- 이론적으로 모든 시스템 대용량 트래픽 고려하겠지만 이상적인 상황이다.
즉 1안에서는 3가지 문제가 있다고 정리할 수 있다.
성능
- 대용량 트래픽 대응 (점심, 저녁, 이벤트)
- 메인, 가게 리스트, 가게 상세 등은 초당 15000회 호출
장애 격리
서비스나 DB에 장애가 발생해도 고객 서비스를 유지하고 주문도 가능해야 한다.
데이터 동기화
데이터가 분산되어있어 동기화도 고려해야 한다.
2안 - CQRS 아키텍처 (전체를.)
명령 시스템과 조회 시스템을 분리하고, 조직 또한 분리함.
아직 뒤에 들을 게 조금 더 남았다.
다 들으면 나머지도 정리해서 느낀점과 함께 업데이트 할 예정@!
'이야기' 카테고리의 다른 글
| MZ가 바라본 AWS AI-DLC (일주일간 AWS로 출근지옥...) (1) | 2026.04.19 |
|---|---|
| GPU 서버 관리 자동화 시스템 알림 병목 해결기 (소비자-생산자 패턴, Redis Message Queue 알아보기) (0) | 2026.02.09 |
| 우리팀 아기를 위한 - Github 히스토리 기반 인수인계 봇 만들기 with Spring AI 찍먹 (1) | 2026.01.17 |
| 1년간의 대학교 GPU 서버 관리자 회고...무언가 돈을 받고 한다는 것 (2) | 2026.01.15 |
| 🏅제 6회 KDT 해커톤 최우수상(고용노동부장관상) 후기 - 구름톤 딥다이브부터 듀오블룸까지 (4) | 2024.12.17 |