배달의 민족 마이크로 서비스 여행기 영상을 보고 다시 생각한 Architecture 설계

dev_will_d·2024년 5월 31일
0
post-thumbnail

현재 필자는 본질적인 실력향상을 목표로 사이드 프로젝트를 진행하고 있다. 현재 우리팀은 선생님 중심의 개발 강의 플랫폼 개발을 진행중이고, 프로젝트의 전체 큰 아키텍처는 MSA로 구성하여 진행하고 있다.

프로젝트에서 필자의 역할은 아키텍처 설계, Common System 개발, Product-service 개발을 담당하고 있다.
오늘은 평소에 필자가 생각한 MSA 아키텍처 구성과 배달의 민족 마이크로 서비스 여행기 영상을 보고 연구 / 분석한 아키텍처 구성에 대해 이야기하는 시간을 가져보도록 하겠다.

Team Lucycato Github

배달의 민족 마이크로 서비스 여행기

Three Tier Architecture

서비스의 가장 큰 아키텍처는 보통 Three-Tier Architecture로 구성이 되어 있다고 할 수 있다. 그리고 백엔드 개발자는 로직을 처리하는 Application Tier와 데이터의 저장 및 공급을 담당하는 Data Tier와 밀접하게 관련이 되어 있다. Application Tier와 Data Tier에 대해 좀더 세부적으로 확장해보자.

하나의 서버, 하나의 DB

서버와 DB를 하나로 구성한 그림은 아래와 같다. 보통 작은 서비스, 초기 스타트업의 구조는 아래와 같은 구조로 되어 있을 확률이 높다. 그러나 이 구조에는 큰 문제가 있다. 서버 or DB가 죽으면 정상적인 서비스 운용을 할 수 없다. 이 문제를 해결하기 위해 좀더 확장해보자.

MSA 단일 DB 서버 구성

하나의 서버로 운용을 했을때 서버가 죽으면 서비스를 정상적으로 운용을 못해 아래와 같은 구조로 확장했다.
관심사 분리의 기준은 각 도메인을 기준으로 Admin 서버와, App 서버로 분리했다. 이렇게 했을때 장점은 권한에 대해 각각의 서버에서 관리할 수 있다는 장점이 있다. 그러나 Admin과 App 각각의 서버를 각각 개발하다 보면 Read, Write에 대한 로직 중복이 많이 발생하여 오버헤드를 발생시키는 단점이 있다. 이 문제를 해결하기 위해 CQRS를 도입하여 Query (Read), Write (Command)를 기준으로 서버를 분리했다. 이렇게 서버를 구성했을때 장점은 2가지 관점의 Applcation을 운용할 수 있어, scale-out에 좀더 유리해지는 것(성능 효율성 향상)과 Command 서버가 죽어도 조회는 가능하다는 장점이 있다. (완전히 서비스가 마비되지는 않는다.) 처음 구조보다 조금더 회복성을 높인 구조라고 할 수 있다.그러나 DB 서버가 죽으면 전체 서비스가 마비되는 문제는 여전이 남아 있다. 이 문제를 해결하기 위해 조금더 확장해보자.

MSA 복합 DB 서버 구성

하나의 DB로 운용을 했을때 DB 서버가 죽으면 서비스를 정상적으로 운용 하지 못하는 문제로 아래와 같은 구조로 확장했다. 이때 DB 서버는 각 서비스의 특징에 맞게 선택한다. 예를 들어 데이터를 입력하는 Command 서버와 통신하는 DB는 데이터의 무결성과 정합성이 중요하므로 엄격한 스키마에 의해 데이터가 관리되는 RDB를 선택한다. Qeury 서버와 통신하는 DB 서버는 정합성이 떨어지더라도 강한 조회 성능을 발휘할 수 있는 NoSQL(Redis, MongoDB, DynamoDB)를 선택하여 조회 성능을 높인다. 이렇게 했을때 장점은 각각의 특성에 맞게 서버를 구성하여 전략적인 (효율적인) scale-out이 가능하다는 장점을 지닌다. 결정적으로 여러 DB 서버를 운용함으로서 회복성이 많이 좋아진다. Command 서버, RDB 서버 및 Command 서버가 죽어도 서비스는 완전히 죽지 않는다. 그러나 이렇게 서버를 구성하면 데이터의 정합성에 대한 문제가 생긴다. 이러한 문제를 해결하기 위한 방법을 살펴보자.
* 중요) 주문과 같은 중요한 사용자와 관련된 Command 서버는 죽는다면, 또는 사용자와 많이 직결된 쿼리 서버가 죽는다면 어떻게 해야 될까? 결론은 주문과 같이 사용자와 관련된 Command 서버와 쿼리 서버는 죽으면 안된다. 배달의 민족 영상에서도 모든 서버가 현실적으로 대용량 트래픽일 수 없다고 한다. 즉, 경중에 따라 서버를 전략적으로 운용하는게 다르다는 뜻이다. 어떤 서버는 자원을 풍부하게 할당하고 철저한 대비를 할 수 있지만 어떤 서버는 상대적으로 그렇지 않다고 할 수 있다. 결론적으로 이러한 구조에서도 Command 서버가 죽거나, 쿼리 서버가 죽으면 치명적이기 때문에 경중이 중한 서버는 상대적으로 철저히 운용할 필요가 있다.

MSA 복합 DB 데이터 정합성

데이터의 정합성을 맞추는 과정은 Kafka와 같은 이벤트 스트리밍 플랫폼으로 해결할 수 있다. 첫번째 사진을 참고해보자. Write 작업을 Command 서버에서 처리를 하고 DB에 데이터를 저장한다. 데이터 저장이 완료 되면 Kafka의 특정 Topic을 기준으로 이벤트를 발행한다. 이 이벤트를 식별할 수 있는 키값만 전달한다. Query 서버에서는 이 키에 대한 정보를 Consume해서 Command 서버에 사전에 정합성을 위해 Fit한 데이터를 주는 API를 키값으로 호출한다 최종적으로 키값을 통해 응답받은 데이터를 자신이 담당하는 DB 서버에 저장한다.

중요하게 언급해야 될 부분중에 하나는 Application 서버의 모델이다. Query 서버는 빠른 검색과 응답이 중요하다 이러한 서버에 어울리는 모델은 Event Loop를 사용하며, Non Blocking I/O 모델을 기반으로 한 WebFlux라고 할 수 있다. MVC에 비해 좀 더 복잡한 프로그래밍 모델이며 개발 검증이 복잡하고 안정성이 떨어질 수 있지만 빠른 응답을 요구하는 Query 서버에 적합다고 할 수 있다. 또한 Command 서버는 기본적으로 MVC를 사용한다. 예를 들어 B2C 서비스라고 가정할때 플렛폼을 사용하는 사용자는 Command 요청 보다 쿼리 요청을 많이 발생시키고, 데이터를 넣어주는 작업 즉, Command는 어드민(Back Office)에서 일어날 확률이 높다. 이러한 상황을 고려했을때 Command 서버는 빠른 응답보다는 안정성이 더 중요하다. 어드민 관리자가 데이터를 넣을때 조금 느리더라도 안전하게 데이터를 넣는것이 서비스 전체적으로 안정적이기 때문이다. 좀더 설명을 하자면 어드민이 서비스 사용자의 100만명, 1000만명의 사람에게 영향을 줄 수 있다는 말이다..!! 이러한 근거로 상대적으로 안정적인 MVC가 더 적합하겠다.

이렇게 구성하면 전략적인 운용이 가능하나, Data Sink 문제가 발생한다 어떻게 해결하면 좋을까 좀더 살펴보자.
* 추가설명) B2C 서비스라고 가정할때 Command가 어드민에서 일어날 확률이 높지만 플렛폼 사용자에 의해 Command가 많이 일어날 수 있는 도메인과 상황이 있다. 이럴때는 속도의 강점을 WebFlux를 고려해 볼 수 있다. 더 나아가 안정성과 속도를 챙겨야 되는 상황이라면 아래에 언급한 Fast Command, Stable Command 구성도 고려해 볼 수 있다.

  • 참고)

MSA 복합 DB Data Sink 문제 해결

Data Sink 문제가 발생한다고 했을때 대략적으로 1초 ~ 3초 정도의 걸린다고 한다. 그런데 만약 사용자가 요청을 보내고 1초 ~ 3초 사이에 쿼리 서버에 데이터를 요청하면 어떻게 될까? 이럴 경우 아직 데이터가 저장이 안된 상태여서 사용자에게 데이터를 로드 할 수 없을것이다. 그러나 정말 중요해서 보여야 된다면 어떻게 해야 할까 필자가 생각한 방법은 Redis를 사용하는 것이다. Command 서버에 값을 저장하면 해당 데이터에 대한 Key값을 Redis에 저장한다. 이렇게 하고 1초 ~ 3초 사이에 데이터를 쿼리 서버에 요청을 하면 쿼리 서버에서는 기존에 약속한 Protocol에 의해 Redis에 키값이 존재하는지 묻는다. 만약 존재한다면 Command 서버에 쿼리를 요청하여 데이터를 받고 만약 존재하지 않는다면 DB에서 데이터를 가지고 온다. 이렇게 함으로써 중요한 데이터에 대한 Data Sink 문제를 해결할 수 있다.

* 추가설명) Redis는 Application 관점에서 봤을때 전역성을 띈다. 즉 Command와 Query간의 변수를 공유하도록 할 수 있다.

* 추가설명) 모든 데이터에 대해서 이러한 과정을 적용해야 할까 모든 데이터에 이러한 방식을 적용하면 안정적이라고 할 수 있으나 상대적으로 Data Sink가 발생해도 서비스에 큰 문제가 없는 데이터의 경우 개발의 효율성을 떨어트릴수 있기 때문에 상황과 맥락에 따라 적용하면 좋을 방법인거 같다.

* 추가설명) 왜 Command 서버에 요청을 하는가? 이유는 원본 데이터를 가지고 있는 서버이기 때문이다.

* 추가설명) Redis에 해당하는 Key는 데이터를 쿼리 서버 DB에 저장을 하면 없애주는 방식으로 개발을 해도 좋고, TTL을 걸어서 자동 소멸 하게 하는 방식 2가지가 있을것이다.

  • 참고)

서버 확장

다시 Three-Tier Architecture를 살펴보자. Three-Tire Architecture에서는 어떻게 서버를 확장 할 수 있는지 방향성을 제시한다. 바로 Application의 확장과 Data Tier의 확장이다. 서버를 Infra Level에서 확장하면 최종적으로 서버 구성의 모습은 아래와 같다고 할 수 있다.

마이크로 서비스 도입


영상에서 마이크로 서비스의 도입은 개발, 시스템의 숙달과 무관하게 서비스 생존을 위해서 도입했다고 나오고 있다. 또한 영상 마지막에서도 마이크로 서비스를 개발하는 것은 기존의 하나의 서비스와 DB를 운용하는 것보다 많은 개발 비용이 든다고 언급한다. 즉, 마이크로 서비스를 도입할때는 각 상황과 맥락을 파악하고 정말 필요에 의한 도입인지를 많이 고민해야 된다는 말이다. 모호한 근거에 도입을 하는것은 옳지 않을것이다.

또한 마이크로 서비스를 구성한다고 했을때 정답은 없다 각 서비스와 시스템의 상황을 고려하여 우리 서비스에 가장 적합한 마이크로 서비스 아키텍처를 구성하는게 가장 중요하다. 그리고 개발자는 이러한 사실을 이해하고 적합한 마이크로 서비스를 개발하기 위한 노력과 생각을 할 수 있어야 한다. 이렇게 할 수 있는 개발자가 진정한 실력있는 개발자라고 생각한다.

주요 주제였던 개발 안정성에 대해

예전에 읽었던 토스의 유난한 도전에서 어떤 개발자가 리팩토링 도입 문제에 대해 이야기한 글을 봤다. '언제 없어질지 모르는 제품인데, 리팩토링은 지옥에서나 하라' 지금 생각해도 직설적인 문장이다. 그러나 개발자로서 생각해볼 가치가 충분한 문장이였다. 필자는 이 문장을 읽고 비지니스와 개발의 안정성에 대해 고민한적이 있었는데, 이번에 더 나은 아키텍처 설계를 위해 참고한 배달의 민족 마이크로 서비스 여행기에서 이 주제에 대해 이야기를 하여 다시 한번 생각을 정리해보고자 한다.

비지니스가 있기에 개발이 존재한다. 또한 개발이 안정적이여야 비지니스가 존재한다. 즉, 비지니스와 개발 안정성은 상호보완적인 관계라고 할 수 있다. 상호보완적인 관계이지만 경중을 따지면 비지니스가 더 중요할 것이다. 비지니스가 없으면 서비스 개발도 없기 때문이다.

'기술만으로는 충분하지 않다. 우리 가슴을 뛰게 하는 것은 인문학과 결합된 기술이다' 같은 말처럼 개발자는 비즈니스와 개발의 교차점을 기억하며 비지니스를 생각하며 개발을 할 수 있어야 한다. 또한 배달의 민족 마이크로 서비스 여행기에서 핵심적으로 이야기하는 점진적 개선의 관점도 탑재해 비지니스의 각 상황과 맥락을 판단해 그에 대응하여 개발할 수 있는 개발자가 되어야 한다.

비지니스의 중요성을 먼저 이해했다면 개발의 안정성과 비지니스의 상호 보완적인 관계를 이해하여 개발의 안정성을 점검하고 검증할 수 있어야 한다. 더 나아가 현재 서비스와 시스템을 지속적으로 이해하여 서비스의 도전적 과제를 점검하고 미래를 대비할 수 있어야 한다. 마지막으로 이 모든것을 하는 행위는 비지니스와 서비스의 성장을 위한 일임을 명심해야 한다.

최종적으로 비지니스와 개발의 안정성을 챙기는 방법에 마법의 요술 램프는 존재하지 않는다는 것을 인정하고 평소 비지니스, 프로젝트 기술의 각 상황과 맥락을 잘 이해하고 이에 대응 할 수 있는 실력과 태도를 갖춰야 한다.

진정으로 실력있는 개발자가 되고 싶어 평소 여러 관점에 대해 많은 생각을 하고있다. 이번 포스트의 핵심 논지인 서비스 성능 및 장애대응과 관련하여 평소 중요하게 생각한 생각을 정리할 수 있어서 기쁘다.

긴 글 읽어주셔서 감사합니다😀

profile
질문의 질이 답의 질을 결정한다.

0개의 댓글