새소식

Welcome to the tech blog of Junior Backend Developer Seulbin Kang!

Project

[Sansam E-commerce] 12. 리팩토링 그 이후의 회고 : Monolithic에서 MSA로...

  • -

👀 들어가기 전에

리팩토링을 진행하며 단일 서버 환경에서 할 수 있는 최선의 선택들을 거의 모두 시도해보았다.

적어도 지금의 서버는 내가 설계하고 운영할 수 있는 범위 내에서는 단일 서버가 감당할 수 있는 최대치에 도달한 상태라고 생각한다.

 

그렇다면 다음 단계는 무엇일까?

이미 단일 서버의 한계를 체감한 상태에서 그 이후의 성장 구간에 놓인 스타트업들은 어떤 선택을 하게 될까?

바로 확장성을 확보하기 위해 자원을 투입하는 단계로 넘어가는 것이다.

물론 지금은 현실적인 제약으로 직접 하나하나 체험해보지는 못하기에...

(AWS 서버비가 만만치 않아,,,,이 이상을 직접 실험해보지는 못했다🥲)

그래서 이번 글에서는 

 

만약 이 서비스가 실제로 더 성장한다면
나는 어떤 선택을 했을까?

 

라는 질문을 기준으로 단일 서버 이후의 확장 전략을 기술적으로 정리해보려 한다.


👀 본론

서버 분리의 시작 : 트래픽이 몰리는 곳부터

실제 서비스가 배포되어 실사용 트래픽이 발생하는 상황이라면 가장 먼저 해야 할 일은 트래픽 분석이다.

  • 어떤 도메인(API)이 가장 많은 요청을 받는지
  • 응답 시간의 병목은 어디에서 발생하는지
  • DB 접근 비율은 어떤지 

이 지점에서 해당 도메인만 우선적으로 서버를 분리하는 선택을 하게 될 것이다.

도메인 하나만 분리해도 처리량은 체감될 정도로 늘어난다.

이 과정을 직관적으로 이해하기 위해 학교 앞 맛집으로 비유하며 설명해보겠다.

(아무래도 이렇게 이해하면 이해가 한 번에 간다..맛있는거 짱😭)


학교 앞 맛집으로 알아보는 서버 확장

처음엔 손님이 하루에 1~2명 오던 작은 가게라고 생각해보자.

그러다 학교 앞 맛집으로 소문이 나기 시작한다.

줄은 조금 생기지만 그래도 기다릴 만한 수준이다.

가게가 유명해져 대기를 하게 된다.
트래픽은 증가하지만, 아직 정상 처리 가능하다.

 

이 시점의 가게는 지금 우리의 서버와 상당히 유사하다.

요청은 많아졌지만 Connection Pool에서 잠시 대기하면 충분히 응답을 제공할 수 있는 상태이다.

즉, 약간의 기다림은 존재하지만 서비스는 정상적으로 돌아가는 구조다.


하지만 어느 순간부터 상황이 달라진다.

옆동네에서도 손님이 오기 시작한다.

주말이면 줄이 가게 밖까지 늘어선다.

이때 가게 사장이라면 어떤 선택을 할까?

분점을 낸다. 

분점을 낸 사장님

서버도 똑같다. 서버를 하나 더 띄워 트래픽을 분산시키는 선택을 하게 된다.

이떄 부터가 Scale-Out의 시작이다.

 

다만 처음부터 모든 메뉴 (모든 도메인)를 분점으로 그대로 옮기지는 않는다. 

실제로 이제 막 분점이 생기는 맛집들을 보면 살짝 메뉴가 다르다. 😉

가장 잘 팔리는 주력 메뉴 몇 개만 먼저 가져간다.

서버에서도 동일하다.

트래픽이 가장 집중된 핵심 도메인부터 분리한다.

 


그렇게 장사를 이어가는데, 이번엔 그 분점마저 또 유명해진다.

주력 메뉴 주문이 폭증한다. 그러면 어떻게 될까?

분점을 하나 더 낸다.

즉, 도메인 서버를 한 대 더 늘리는 것이다.

도메인 서버까지 늘렸지만 일할 사람이 부족하다

그런데 어느 순간 이상한 상황이 벌어진다.

가게 공간은 충분한데, 주문을 처리할 직원이 부족하다.

DB에 병목이 생겨 응답이 지연된다.

 

이때 가게 대표는 지점장을 시켜 사람을 더 뽑는다.

서버로 치면, DB를 하나 더 둬야만 하는 단계에 도달한 것이다.


 

그렇게 운영하던 중 이번에는 방송을 타서 손님이 폭발적으로 몰린다.

그런데 알고 보니 한 사람이 주문도 받고, 서빙도 하고, 요리까지 다 하고 있었다.

이 상태로는 더 이상 버티기가 불가하다.

그래서 사람을 뽑아 역할을 나눈다.

  • 한 명은 주문
  • 한 명은 서빙
  • 한 명은 주방

DB도 동일하다.

  • 읽기 전용 DB
  • 쓰기 전용 DB

역할에 따라 분리한다.

역할에 따라 DB도 분리하게 되는 것이다.

 

만약, 읽기 요청이 압도적으로 많다면 Read Replica를 두는 선택을 한다. 

읽기 요청이 압도적으로 많은 대표적인 서버는 인스타나 페이스북과 같은 서버가 될 것 같다.

(음식점으로 치면, 요리는 충분한데 주문 받는 사람이 부족한 상황이다.)

 

이후에는 장사가 잘 될수록 이 과정을 계속 반복하게 된다. 

결국 서버도 완전히 동일한 흐름을 따른다.


서버도 도메인 분리 이후 다시 병목 지점을 찍어본다.

도메인을 분리하고 다시 트래픽을 받아본다.

  • 서버 단에서는 충분히 버티는지
  • DB는 정상적으로 동작하는지

대부분 이 시점에서는 어플리케이션 서버보다 DB가 먼저 병목이 된다. 

가게 수만 늘리고 일할 사람을 늘리지 않으면 의미가 없는 것과 같다.

그러다가 자연스럽게 CQRS 패턴을 고민하게 되는 것이다.


그렇게 자연스럽게 MSA가 된다.

이 과정을 반복하다 보면 어느 순간 요즘 흔히 말하는 MSA 구조에 도달해 있다.

넷플릭스와 아마존의 MSA 구조

 

그리고 이 시점부터는 선택지가 더 다양해진다.

  • 비동기 처리가 필요해, Kafka를 붙이기도 하고
  • 단순 이벤트 전파는 Redis Pub/Sub이 더 적합할 수도 있고
  • 검색 성능이 중요해지면 Elasticsearch를 도입하고
  • Jaeger를 통해 분산 트랜잭션을 추적하게 된다.

로그 역시도 마찬가지다. 

  • 단일 서버 로그 수집이 한계에 오면
  • Beats → Kafka → Elasticsearch → Kibana 구조로 확장하고
  • 로그 분석 자체를 하나의 독립된 시스템으로 분리한다.

인프라 레벨의 확장

인프라 레벨에서도 변화가 시작된다.

  • EKS를 도입하고 
  • Blue-Green / Rolling 배포를 하게 되고
  • 단일 장애 지점을 제거하게 된다.

이 모든 선택들이 결국 규모가 커졌기 때문에 살아남기 위해 어쩔 수 없이 하게 되는 선택들로 이어지게 되는 것이다.


👀 프로젝트를 마무리하며...

이번 프로젝트에서는 진짜로 스타트업이 처음 시작할 때부터 어떻게 성장해나가는지, 왜 그렇게 해야만 하는지를 생각하고 고민해가며

최대한 단일 서버에서 리소스를 줄여보기도 하고 서버를 분리도 해보면서 단기간에 많은 성장을 이룩할 수 있었던 것 같다.

  • 서버를 분리하면 비용은 즉시 기하 급수적으로 증가하고
  • 잘못 분리하면 오히려 적자가 날 수 있으며
  • 반대로 다시 서버를 합치는 경험도 해보며 "단일 서버가 생각보다 훨씬 많은 요청을 처리할 수 있구나"라는 것도 느끼게 된 것 같다.

이 경험 덕분에 이제는 코드 하나를 작성할 때도 자연스럽게 이런 질문을 하게 된다.

  • 지금 이 선택이 정말 필요한가?
  • 미래의 확장을 고려했을 때 감당 가능한가?
  • 단순히 유행하는 기술이라서 쓰는 것은 아닌가?

무턱대고 기술을 도입하고 보는 것이 아니라, 이유와 정확한 근거를 가지고 선택하는 개발이 얼마나 중요한지도 깨닫게 된 프로젝트였다.

아쉬움은 많이 남지만, 서버 비용과 테스트 비용을 생각하면 여기까지가 현실적인 지금에서의 마무리인 것 같다.

 

그래도 단일 서버에서 시작해 성장하는 서비스의 다음 단계들을 계속해서 고민해볼 수 있었던 것만으로도 충분히 값진 경험이었다고 생각한다. 앞으로 이번 프로젝트를 진행한 경험을 토대로 더욱이 열심히 해보겠다.

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.