이번에 처음으로 우아한형제들에서 기술 세미나를 개최했는데 바로 우아한테크콘서트, 우.아.콘이다.
배달의 민족 서비스는 현재 100% 클라우드 이전이 완료되어 클라우드에서 모든 서비스가 제공되고 있는데, 그 과정을 9개 세션으로 설명해주셨다.
9개 세션 모두 알차고 재밌었지만, 그 중에서 김영한님께서 진행하신 세션이 가장 기억에 남아 그 후기를 작성해본다.
배달의 민족 마이크로서비스 여행기 - 김영한
후기에 앞서
지금 내가 사이드 프로젝트를 마이크로서비스로 개발하고 있기 때문에 우아콘 참여 신청할 때부터 가장 궁금했던 세션이었다. 그리고 세션을 다 듣고나니 나와 같은 개발자들이나 회사에서 마이크로서비스를 시도하기 전에 반드시 들어야할 내용이라고 생각이 들었다.
사이드 프로젝트에 마이크로서비스아키텍쳐(MSA)를 적용하기로 결정한 이유는 아래와 같았다.
- MSA를 구현하는데 사용되는 기술이 궁금했다.
- MSA 구현 시, 서비스별로 다양한 방식으로 확장이 가능한 점이 매력적이었다.
(개발 언어라던가... Python을 해보고 싶었거든...) - 여러 채용 공고에서 MSA 기반 개발 경험을 요구했다.
- 회사에서 MSA 관련 얘기가 아주 희미하게나마 나왔었다.
배민 서비스의 역사
배달의민족이 마이크로서비스, AWS이전을 결정하게된 배경을 연도별로 설명했다.
2015년
하루 주문수는 5만건 이하였고, MSSQL과 PHP로 시스템이 개발되어있었다.
대부분의 서비스 로직은 Stored Procedure를 통해 구현되어있었고, 각각의 서비스와 배포가 별도로 구성되어도 데이터베이스는 '루비'라고 불리는 통합 DB를 사용했다.
때문에, DB 장애 시 전체 서비스에 장애가 발생했다.
2016년
하루 주문수가 10만건을 돌파했고, 대용량 트래픽 처리와 개발 인력 수급을 위해 시스템을 Java로 전환했다.
2015년의 문제점을 해결하기 위해 마이크로서비스에 도전하기로 의사 결정이 되었다. 결제 시스템, 주문중계 시스템을 시작으로 서비스가 독립되었고 데이터베이스 또한 IDC에서 AWS 클라우드 인프라로 이전을 시작했다.
마이크로서비스는 기술적인 고민이나 선택이 아닌, 생존의 문제였다.
2017년
하루 주문수가 20만건을 돌파하면서 대장애의 시대가 열렸다. 트래픽은 점점 늘고, 시스템은 레거시였기 때문에 스케일 아웃이 불가능했다.
대장애의 시대를 겪으며 마이크로서비스의 필요성을 더 체감하게 되었고, 가게목록 검색/메뉴/정산 시스템을 분리해냈다.
2018년
대장애의 시대를 겪고, 전사 1순위 과제는 시스템 안정성이었다.
시스템 안정화 작업을 수익 창출을 위한 개발과 함께 병행해야하는, 말그대로 달리는 마차의 바퀴를 갈아끼워야하는 상황이었지만 전사적인 의사결정을 통해 개발팀을 최대한 지원하게 되었고 이는 프로젝트 먼데이로 성공적으로 이어졌다.
레거시 3대장 중 하나인 주문 시스템을 분리해냈고, 다음과 같은 변경이 있었다.
기존 | 변경 | |
방식 | API 기반 데이터 전달 | 이벤트 기반 데이터 전달 - 주문 시 이벤트 발행(생성/접수/배달완료/취소) 후 연계 시스템에서 이벤트를 구독해 각 로직 수행 |
결과 | 하나의 시스템에 장애가 발생하면 연관 시스템 모두 장애가 발생했다. | 1. 연계 시스템이 장애 후 재기동되면 메시지 큐에 담긴 데이터들을 구독해 로직을 수행해 데이터가 유실되지 않는다. 2. 추가적인 연계가 발생해도 주문 시스템은 추가 작업 없이 연계 시스템에서 SQS를 추가해 로직을 구현하면됨! |
마이크로서비스 아키텍쳐 변화
CQRS
- 핵심 비즈니스 명령(Command) 시스템과
- 조회(Query) 중심의 사용자 서비스
- 둘을 철저하게 분리
- Command and Query Responsibility Segregation (CQRS)
이벤트 전파와 동기화
- Eventually Consistency (최종적 일관성)
- 데이터는 언젠가는 다 맞추어진다.
- 데이터 싱크 1~3초 소요
- 문제 발생 시 해당 시스템이 이벤트만 재발행
- 대부분 Zero-Payload 방식 사용
- 이벤트에 식별자(ex: 가게ID)와 최소한의 정보만 발행
- 이벤트를 받은 시점에 조회 api로 필요한 데이터를 조회해서 저장
- 각 이벤트 수신 시스템마다 필요한 데이터가 다르고
- 이벤트의 순서를 고민하게 되기 때문에(A, B 순으로 이벤트가 발생해도 B, A 순으로 구독할 수도 있기 때문에) 모든 이벤트는 최신의 이벤트라고 생각하고 식별자를 통해 api로 조회
장애 격리
- 각 시스템이 내부에 필요한 데이터 보관
- 내부 서비스의 모든 변경 내역이 이벤트로 전달
- 장애시 데이터 싱크가 늦어져도 고객 서비스 가능
데이터 싱크 장애 대응
- 이벤트 재발행
- 큐 장애 발생 시
- 전체 import api 제공
- 부분 import api 제공
최근 업데이트 데이터를 분 단위로 부분 제공
기타
- 적극적인 캐시 사용
- 서킷 브레이커
- 비동기 non-blocking 시스템 적용
- 스프링 Web Flux, Reactor
- 가게노출, 광고리스팅, 검색
정리
- 배달의민족 시스템은 거대한 CQRS
- 성능이 중요한 외부 시스템과 비즈니스 명령이 많은 내부 시스템으로 분리
- 이벤트 발행을 통한 Eventually Consistency
- 각 시스템은 API 또는 이벤트 방식으로 연동
마이크로서비스를 꼭 해야하나요?
규모의 경제가 되야 할 수 있다. 시스템 규모, 트래픽, 인력이 많아야 할 수 있음!
조인으로 끝낼 일을 비용이 10배 정도되는 공수가 발생할 수 있기 때문에, 그 비용을 상쇄하고도 남을만한 가치가 있을 때 적용하도록 하자.
이 세션을 듣고나서 마이크로서비스에 대한 생각이 바뀌었다. 그동안은 좀더 진보하고 더 난이도있는 기술을 사용하기 때문에 이전의 모놀로식 아키텍쳐의 프로젝트보다 한 단계 위에 있다고 생각했었는데, 그렇지 않았다.
마이크로서비스에는 많은 비용이 필요하다. 실제로 지금 진행중인 사이드 프로젝트도 만약 모놀로식 아키텍쳐였다면 진작에 개발이 끝났을 것이다. 김영한님 말씀대로, 마이크로 서비스는 추가로 요구되는 비용을 상쇄하고도 이윤이 있을 때 적용이 가능한 것 같다.
결국에는 프로젝트가 기술을 따라 가는 것이 아니고, 프로젝트에 필요하면서 적절한 비용의 기술을 사용하도록 하는 것이 맞는것이다.
지금까지 기술적인 호기심이 이를 역전시켜 마이크로서비스에 프로젝트를 우겨넣을 궁리만 하고 있었는데, 이번 기회로 이를 깨닫고 반성하게 되었다.
'📦 ETC > 그냥 쓰고 싶어서요' 카테고리의 다른 글
읽기 좋은 코드가 좋은 코드다 (0) | 2021.05.02 |
---|---|
주니어 개발자의 2020년 회고 (0) | 2021.01.01 |
[if(kakao) 2020] JUnit5를 시작하며 (0) | 2020.12.25 |
[Github] 할로윈에는 Contribution 색상이 바뀐다 (0) | 2020.10.31 |
[Naver Developer Open Class] 립스탑 백을 받았다 (0) | 2020.09.13 |