관리 메뉴

피터의 개발이야기

[MSA] 마이크로서비스란? - 배민 마이크로서비스 여행기를 보고... 본문

Kubernetes/기초공부

[MSA] 마이크로서비스란? - 배민 마이크로서비스 여행기를 보고...

기록하는 백앤드개발자 2024. 2. 29. 02:34
반응형

ㅁ 관련 글

ㅇ [MSA] 12가지 마이크로서비스 패턴

[MSA] 마이크로서비스 - 분산 트랜잭션 처리를 위한 Saga 패턴

 

ㅁ 들어가며

 마이크로서비스의 패턴 중 CQRS에 관한 글을 작성하면서 [우아콘2020] 배달의민족 마이크로서비스 여행기 유튜브 동영상을 다시 보게 되었다. MSA에 대해 고민하면서 많이 공감이 되고 도움이 되는 동영상이다. 이번에 이 동영상을 다시 보면서 마이크로서비스를 구축하는 좋은 경험들을 글로 정리를 해 보았다.

 

주의: 동영상을 보면서 마이크로서비스를 공부하는 상황이라 동영상의 내용과 나의 생각이 혼합되어 있다.

 

ㅁ 마이크로서비스 이해를 위한 핵심 질문들

동영상을 통해 마이크로서비스를 이해하는 핵심적 내용은 다음 질문으로 귀속된다.

 

왜 나누어야 하고, 나누었을 때 상호 통신과 데이터 일관성은 어떻게?

ㅇ 분해

- 왜 기존 서비스를 마이크로서비스로 전환해야 할까요?

   ㄴ 늘어나는 트래픽을 어떻게 소화해야할까?

   ㄴ 어떻게 커져만 가는 모노리틱 서비스에서 MSA 전환으로 설득하지?

- 기존에 하나였던 모노리틱 아키텍처에서 서비스를 어떻게 분해할까?

   ㄴ 핵심키워드:  도메인 주도 패턴(DDD)

ㅇ 통신

- 분해된 서비스들 간 통신은 어떻게 진행해야할까?

   ㄴ Sync(Http): 모듈간 API - 데이터 분리는 되었지만 API가 죽으면...

   ㄴ Async(AWS SNS): 배민은 AWS SNS를 사용했지만, rabbitmq나 kafka

 트랜잭션

- 분산된 데이터의 트랜잭션은 어떻게 할까?

   ㄴ 2PC(Two-Phase Commit)보상 트랜잭션(Compensae Transaction)

   ㄴ SAGA 패턴: 코레오그래피(서비스 중심), 오케스트레이션(중앙 집중)

   ㄴ 이벤트 소싱 + EDA

   ㄴ MSA와 데이터 일관성의 딜레마에서 결단은 최종적 일관성(Eventually Consistency)

데이터 쿼리

- 모듈별 분산된 데이터는 어떻게 쿼리할까?

  ㄴ AWS DynamoDB 등 Multi Datasource를 활용한 CQRS

      ㄴ Write와 Read 분리

          :- 비지니스 로직이 포함된 복잡한 데이터 쿼리와 단순 View를 위한 조회 쿼리의 분리

          :- 서비스 포퍼먼스를 위해 비정규화를 통해 일부 중복된 데이터를 허용

            => 데이터 동기화 문제, 분산 트렌젝션 문제 발생

      ㄴ 조회 쿼리: CQRS View Dynamo DB 서비스로 구현

 

아래는 동영상을 보면서 캡처하고 내용과 생각을 정리한 부분이다.

 

ㅁ 왜 나누어야 하는가? - 급성장하는 서비스

 ㅇ 기존 서비스는 모노리틱 아키텍처로 디비를 중심으로 여러 Application이 "통짜"로 구축되어 있었다. 

 ㅇ 주문이 년간 8만건 정도이면 문제가 되지 않지만 사용자가 늘어나면 지연 및 부하로 인한 장애가 발생하게 된다.

 

 ㅇ 개인적인 생각으로 서비스 확장 정도에 따라서 단계가 있다고 생각한다. 

   1단계: DB 스팩을 최대한 올린다.

     ㄴ 모노리틱의 가장 확실한 대처는 스케일업이다.

         모노리틱 구조에서는 디비를 스케일아웃하기는 어렵다.

 

   2단계: 대용량, 고트래픽으로 인해 DB 병목 발생

     ㄴ 1단계의 한계점에 도달했다.

          DB의 성능을 최대치로 올려도,

          내부적인 테이블의 구조나 기타 네트워크 IO 혹은 디비락 등의 문제로 장애가 자주 발생하게 된다.

          마이크로서비스의 필요성이 대두된다.

동영상 캡처

  3단계로 부하 분산을 위한 마이크로서비스 구축:

     ㄴ 부하 분산을 위해 Cloud인 AWS를 사용하기 시작

     ㄴ 마이크로서비스를 구축을 위한 설계 검토

 

  4단계 장애의 연속

     ㄴ 처음부터 MSA를 잘하는 사람은 없다. 

     ㄴ 사업과 마케팅은 안정성과 이윤창출을  원하지만, 개발자는 핵폭탄이 보인다.

 

ㅁ 장애의 연속

ㄴ 프론트가 죽어서 서버 늘렸더니, 주문이 죽고, 나중에 PG사가 죽더라...

ㄴ 김영한님 왈: 진짜 생존을 위해서 우리는 마이크로서비스를 해야하는 구나...

 

ㅁ 트래픽 분산을 위한 NoSQL 사용 및 희미한 CQRS 패턴  적용

 ㅇ Write와 Read 역할을 구분하여 디비 부하를 줄이자

   ㄴ루비DB는 Write, update 및 관계형 디비 비지니스 로직 수행(무거운 조인쿼리 구동)

   ㄴAWS 다이나모DB를 통해 단순 select를 빠르게 대응

      ㄴ 일종의 NoSQL은 Read Insert는 빠르지만, 관계형 SQL은 구조상 조화하기 어려움.

 

ㅁ 달리는 마차의 바뀌를 바꾸어라!!

 ㅇ 회사의 이윤창출은 곧 트래픽과 연관된다. 지속적인 성장은 이윤을 남기지만, 반대로 시스템의 불안정을 만들게 된다.

 ㅇ 통으로 된 레거시 시스템을 모듈화하고 새로운 시스템으로 도약하는 과정을 설명함.

 

ㅁ 서비스간 통신은? - Event Driven Architecture

Sync 기본 API 기반 데이터 전달

     ㄴ50X 에러가 나면... 다른 연동 API가 장애가 나면 요청들은 유실된다. 

ㅇ 이벤트 기반으로 데이터를 전달하면,

  - 연동 시스템 간의 느슨한 결합

     ㄴ 이벤트를 발생할테니 다른 부서는 참조해서 처리해... 

  - 요청 데이터 유실 방지

     ㄴ 장애가 나도 다시 하면 된다.

  - 성능 업이나 시스템 업그레이드 용이함.

     ㄴ 배포 전략에 따라 순단이 발생하겠지만, 유실된 정보는 없다.

ㅇ 동영상: EDA설명 링크

 

ㅁ MSA 구조로의 전환

 ㅇ 결합도를 낮추기 위해 서로 API로 조회...

     ㄴ 어느 하나가 장애가 발생하면, 응답을 기다린다고 홀딩... => 전체 장애

 ㅇ MSA 구조로 변경하지만 성능, 장애 격리, 데이터 동기화를 고려해야 한다.

 

ㅁ 성능, 장애 격리

 ㅇ 점심, 저녁, 이벤트 시 버스트 트래픽 발생

 

ㅁ 데이터 동기화 해결책 = CQRS + EDA

ㅇ CQRS 패턴을 적용하여, DB 부하는 분산

  - 명령(Command): 핵심 비즈니스 영역, Creat, Update, Delete

  - 조회(Query): 사용자 서비스 중심, Select Join

  - 장점: 명령 혹은 조회에 특화된 DB 혹은 NoSQL을 선택할 수 있다.

 


ㅇ 이벤트 전파와 동기화

  - Eventually Consistency(최종적 일관성)

    ㄴ 나는 결과론적 일관성이고 표현함.

    ㄴ 데이터베이스의 일관성과 MSA의 격리성에 따른 딜레마가 발생.

  - 데이터는 언젠가는 다 맞추어진다.

  - 데이터 싱크 1~3초

  - 문제 발생 시 해당 시스템의 이벤트 재발행

  - 대부분 Zero-Payload 

     ㄴ 누가, 어떤 이벤트 인지만 전달.

     ㄴ 업데이트 시 상세조회로 세부정보 요청.

      - 장점: 명령 혹은 조회에 특화된 DB 혹은 NoSQL을 선택할 수 있다.

 

 ㅇ 광고리스팅, 검색, 찜 시스템의 모듈들에서 가게ID만 받아 자체 DB에서 정보를 조회

 ㅇ 비동기 작업을 통해 동시에 일을 처리하여 속도 개선

 

ㅁ CQRS 성능 및 장애 격리

 ㅇ 트래픽이 발생하여도 내부 DB에서 조회하여 뒷단의 메인 디비에는 영향이 전파되지 않음.

 ㅇ 장애격리

   ㄴ 각 시스템이 내부에 필요한 데이터 보관

   ㄴ 내부 서비스의 변경 내역은 이벤트로 동기화

   ㄴ 장애 시 데이터 싱크가 늦어져도 고객서비스는 가능

 

ㅁ 데이터 싱크 장애 대응

 ㅇ 원천 모듈에서 이벤트 재발행

 ㅇ 큐 장애 발생 시

     ㄴ 전체 IMPORT API를 통해 배치로 동기화

     ㄴ 부분 IMPORT API를 통해 동기화

         - 최근 명분간의 데이터를 조회 및 동기화 처리

ㅇ 서킷 브레이커 패턴(Circuit Breaker Pattern) 적용
   ㄴ 장애가 발생했다면 지속적인 요청을 장애를 악화 시킴.

   ㄴ 장애 시 요청을 보내지 않도록 차단시켜 실패할 수 있는 작업을 계속 시도하지 않도록 방지한다.

 

ㅁ 정리

 ㅇ 배달의 민족에서 수행한 거대한 CQRS 패턴을 공부하게 됨.

 ㅇ 성능이 중요한 외부 시스템과 비즈니스 명령이 많은 내부 시스템으로 분리

 ㅇ 이벤트 발행을 통해 Eventually Consistency(최종적 일관성)을 유지

 ㅇ 각 시스템은 API 또는 이벤트 방식으로 연동

 ㅇ 마이크로서비스는

    데이터의 비정규화 방식을 고수하고 번거로운 수작업이 많지만,

   그래도 성능과 장애격리 및 데이터 동기화를 위해 어쩔 수 없이 꼭! 필요하다.

ㅁ 마이크로서비스 꼭 해야되나?

 ㅇ 규모의 경제가 되어야 한다.  시스템 규모, 트래픽, 사람...

     ㄴ 테이블 조인으로 해결될 일을 10배 힘들게 MSA로 구성해야 한다. 

 

ㅁ 내가 경험한 마이크로 서비스란?

마이크로서비스는 정말 어쩔 수 없어서 쓰는 것이지, 편안해서 쓰는게 절대 아니다.
고객에겐 우리의 장애를 알리지 말라!!

 

 마이크로서비스 결과적으로 안정된 서비스를 위해 더 많은 고군분투가 필요하다.

 

ㅁ 함께 보면 좋은 사이트

https://youtu.be/BnS6343GTkY?si=MR23eIAub90Ej5o9

반응형
Comments