Skip to main content

Command Palette

Search for a command to run...

마이크로 서비스 아키텍처(msa) 고려사항

MSA(MicroServices Architecture)를 나눌 때 고려해야할 점은 무엇인지에 대하여 다룬다.

Updated
•4 min read•View as Markdown
마이크로 서비스 아키텍처(msa) 고려사항

마이크로 서비스 아키텍처란?


마이크로 서비스 아키텍처를 이해하기 위해서는 모놀리식(Monolithic)을 이해해야 한다. 위에 나와있는대로, 한 프로그램을 제공하는데 있어서 모든 로직과 수행 과정을 한 덩어리로 실행하느냐, 여러 조그만 덩어리로 나누어 실행하느냐에 따라서 두 방식이 나뉘어진다.

MSA에서 각 서비스끼리 통신할 수 있도록 하는 규약은 IPC(Inter Process Communication)이라고 하며, 동기적 IPC로는 HTTP, gRPC로 구분한다. 또한, 비동기적 IPC로는 AMQP, Kafka로 나뉜다. 자세한 설명은 밑에서 이어 하도록 하겠다.

마이크로 서비스를 어떻게 통신하게 할 것인가?


마이크로 서비스를 나누기 위해서는 먼저 프로그램이 어떻게 구동하는지 이해하고 나누어야 한다. 각 서비스들이 어떻게 통신하는지, 그리고 얼마나 통신하는지 먼저 생각해보자.

각 서비스들이 통신하는 방법은 아래의 표를 참고하여 설명한다.

one to one (일대일, 1:1)one to many (일대다, 1:N)
동기적 (Synchronous)1. 요청/응답3. -
비동기적 (Asynchronous)2. 비동기적 요청/응답, 단방향 알림4. 발행, 구독, 비동기적 응답

동기적이냐 비동기적이냐를 나누는 기준은 호출자가 응답을 기다리는가의 여부에 달려있다. 전화같은 경우 수신자의 응답(전화를 받는 것)을 기다리기 때문에 동기적이라고 하고, 메일은 즉각적인 응답(데이터의 응답이다. 발신하는 사람이 답장을 기대하고 있는가의 여부는 다루지 않는다.)을 기다리지 않기에 비동기적이라고 한다.

이를 예시를 통해 설명해보자.

  1. 동기적/일대일

    • 클라이언트가 서버에 요청을 보낸 후, 응답이 올 때까지 대기(block)하는 방식이다. 예: REST API 호출 - 주문 생성 요청 후 결과를 받을 때까지 대기

    • 우리가 전화를 하는 것처럼 상대방이 전화를 받아야 상호간의 통신이 가능한 것에 비유할 수 있다.

  2. 비동기적 요청/일대일

    • 클라이언트가 요청을 보낸 후, 응답을 기다리지 않고 다른 작업을 수행할 수 있다.

    • 예: 이메일 발송 - 메일 전송 요청 후 전송 완료를 기다리지 않고 다음 작업 진행

    • 따라서 순서가 중요하며, 동기적으로 진행되지 않는 것이다.

  3. 동기적/일대다

    • 실무에서는 드물게 사용됨

    • 예: 여러 서비스에 동시에 요청하고 모든 응답을 기다리는 경우 (예: 상품 상세 페이지 로딩 시 재고, 가격, 리뷰 서비스에 동시 요청)

  4. 비동기적/일대다

    • 표에 적혀있는 바와 같이 발행이나 구독이 대표적인 예시다. 유튜브에 영상을 올려놓고 시청자들은 시간이 될 때 보는 것에 비유할 수 있다.

통신 방식 (동기적, 비동기적)


우선, 비동기적 방식부터 간단히 설명한다. 비동기적으로 통신할 때는 kafka 혹은 AMQP(대표적으로 Rabbit MQ) 방식을 채택한다. 이는 메시지 큐 아키텍처, 혹은 메시지 대기열 시스템으로, 나중에 이어질 아티클에서 자세히 설명하도록 한다.

이 본문에서는 동기적 방식을 우선적으로 이야기한다.

먼저, 각 서비스끼리 통신할 때는 각 서비스끼리 어떻게 통신할지의 약속을 정해야 한다. 한 사람은 영어로 소통하고, 다른 사람은 한국어로 소통하면 서로의 통신이 불가능하다. 따라서, 어떤 언어 혹은 어떤 방식으로 소통할 지 정하는 것이다.

‘어떤‘ 방식으로 소통하자는 상호간의 약속을 API 라고 한다. 그리고 그 상호간의 약속을 먼저 정의하고 넘어가자는 것을 API first Approach라고 한다. 주고 받는 법을 먼저 생각하자는 것인데, 풀어서 말하면, 먼저 어떤 언어로 소통할 지 정하고 넘어가자는 약속이다.

이를 통해, golang, python, java 등 다양한 언어를 이어줄 수 있게 된다. 만일 한 서비스에서는 python이라는 언어를 쓰고, 반대쪽에서는 java라는 언어를 쓴다면, 중간에서 서로의 언어를 번역하는 역할을 한다. 어떤 언어를 고르든 각 프로그래밍 언어의 호환성이 가장 중요하다. 다시 말해, 파파고나 구글 번역기같은 어플리케이션이고, 어떤 언어가 호환될 수 있는지가 가장 중요하다.

쉽게 설명하다보니 말이 길어졌는데, 이러한 동기적 방식에서는 RPC(Remote Procedure Call)에 속해있는 HTTP와 gRPC라는 방식을 주로 채택한다. 이 두 방식 모두 서로의 언어를 번역하는 역할을 하게 되며, 각각의 특성을 가진다.

RPC는 RPI(Remote Procedure Invocation)이라고도 불리며, 원격 절차 호출이라는 의미를 가진다. 한 서비스에서 다른 서비스를 마치 자기 자신의 기능인 것처럼 실행할 수 있도록 한다.

데이터 포맷(JSON/Binary)


보통, 우리가 자주 접할 수 있는 방식은 문자 기반(Text Based)파일인 Json파일이나 xml파일이다. 이 두개가 그 예시다.

{
  "name": "YOUNG",
  "age": 30,
  "city": "DAEGU"
}
<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>

두 가지 방식 모두 사람이 조금만 공부하면 읽기 쉬운 방식이다. Json파일만 보더라도 이름은 young, 나이는 30, 사는 곳은 대구라는 것을 알 수 있다.

하지만, 이런 파일이 서비스간 통신에 매우 잦은 빈도로 사용되다 보면, 로그에 쌓이는 데이터도 많을 뿐만 아니라 네트워크 대역폭과 저장 공간을 더 많이 사용하게 되어 비용이 증가한다. 사람이 읽기 쉽게 하기 위해 더 많은 텍스트를 사용하기 때문이다.

그래서 이를 해결하기 위해 바이너리 방식의 Protocol Buffers, Avro 등을 사용하기도 한다.

이들은 IDL(Interface Definition Language)을 사용하여 어떤 함수를 제공할지, 어떤 데이터를 주고받을지 미리 정의한다. 예를 들어, 한쪽에서는 Python, 다른 한쪽에서는 Java를 쓴다고 할 때, IDL로 중립적인 형식으로 정의해두면 각 언어에 맞는 코드를 자동 생성할 수 있다.

실제 데이터 전송 시에는 바이너리 형태로 변환된다:

Python의 User 객체 → 바이너리로 직렬화 → 네트워크 전송 → Java의 User 객체로 역직렬화

이후 gRPC의 장점을 설명하면서 말하겠지만, 이 방식은 매우 압축적이고 빠르고 간편하기에 주고받는데 필요한 데이터의 양을 줄이면서 비용도 줄일 수 있다.

결론


마이크로 서비스 아키텍처를 사용하는 방법에는 여러가지가 있다. 주로 비동기적 방식에서는 kafka, rabbitMQ 등이 사용되며, 동기적 방식에서는 HTTP, gRPC가 사용된다. 동기적 방식에서는 기존의 구조화된 데이터 통신의 불필요한 정보들을 압축하여 바이너리 형식으로 바꾸었다가 다시 다른 언어에서 사용할 수 있도록 구조화된 데이터를 만들어 통신한다.

MSA

Part 2 of 2

This series will adress about MSA(Micro Service Architecter)

Start from the beginning

gRPC란?

gRPC의 원리와 개념에 대하여