dev-sohee 님의 블로그

MSA: 마이크로서비스 아키텍처의 모든 것 본문

MSA: 마이크로서비스 아키텍처의 모든 것

dev-sohee 2024. 10. 5. 14:25

개발자에게 아키텍처는 추상적인 개념으로 정의를 내리기가 쉽지 않을 수 있습니다. 그래서 아키텍처의 내용을 먼저 설명해보자면, 시스템 구성 및 동작 원리를 나타내고, 구성 요소 간의 관계 및 시스템 외부 환경과의 관계를 묘사하고, 시스템 구성 요소에 대한 설계 및 구현을 기술한 것 정도라고 할 수 있습니다. 즉, 아키텍처란  하나의 서비스가 어떻게 구성되며 어떻게 동작하는지를 표현한 것입니다. 

 

좋지 않은 디자인의 소프트웨어는 추후에 기능을 추가하거나 변경하기가 어렵기때문에 유지보수가 점점 어려워집니다. 반면에 좋은 디자인을 가진 소프트웨어는 기능을 추가하고 관리하기가 수월합니다. 소프트웨어가 잘 컴포넌트화 되어 있기 때문입니다. 이것이 바로 소프트웨어 아키텍처가 중요한 이유입니다.


과거에는 어플리케이션이 상대적으로 단순하고 기능이 제한적이었기 때문에 모놀리식 아키텍처가 많이 사용되었습니다. 하지만 시간이 지나면서 비즈니스 요구사항이 복잡해지고, 어플리케이션의 규모와 기능이 증가함에 따라, 모놀리식 아키텍처의 한계가 드러나기 시작했습니다. 이로 인해 많은 기업들이 마이크로서비스 아키텍처(MSA)와 같은 더 유연하고 확장 가능한 구조로의 전환을 고려하게 됐습니다.

 

출처_ https://velog .io

 

모놀로식 아키텍처란 하나의 단일 코드베이스로 소프트웨어 어플리케이션을 개발하는 방식으로 모든 기능이 하나의 어플리케이션 안에 통합되어 있는 구조를 의미합니다. 모놀로식 아키텍처는 다음과 같은 특징이 있습니다.

 

모놀로식 아키텍처 장점

  • 상태 공유: 어플리케이션의 모든 모듈이 동일한 프로세스와 메모리 공간에서 실행되기 때문에, 상태를 쉽게 공유할 수 있습니다.
  • 개발 용이성: 초기 개발이 간단하고, 개발자들이 하나의 코드베이스에서 작업할 수 있어 협업이 비교적 용이합니다.
  • 성능: 모놀리식 구조는 통신 오버헤드가 적기 때문에 단일 애플리케이션 내에서의 성능이 높을 수 있습니다.

모놀로식 아키텍처 단점

  • 확장성의 한계: 전체 어플리케이션을 확장해야 하므로, 특정 기능만 확장하기 어렵습니다.
  • 유지보수의 어려움: 코드베이스가 커질수록 이해하기 어렵고, 수정이나 추가 작업이 복잡해질 수 있습니다.
  • 배포의 복잡성: 모든 기능이 하나의 패키지로 묶여 배포되므로, 작은 변경 사항에도 전체 애플리케이션을 함께 업데이트해야 하고, 이로 인해 배포 주기가 길어질 수 있습니다.
  • 기술 스택의 제약: 모든 기능이 같은 기술 스택에서 개발되어야 하므로, 최적의 도구를 선택하기 어렵습니다.
from flask import Flask, request, jsonify
app = Flask(__name__)

# 사용자 관리
users = []  # 사용자 정보를 저장하는 리스트

@app.route('/users', methods=['POST'])
def add_user():
    user = request.json  # 사용자 정보를 JSON 형태로 받음
    users.append(user)  # 사용자 정보를 리스트에 추가
    return jsonify(user), 201  # 추가된 사용자 반환

@app.route('/users', methods=['GET'])
def get_users():
    return jsonify(users)  # 모든 사용자 반환

# 상품 관리
products = []  # 상품 정보를 저장하는 리스트

@app.route('/products', methods=['POST'])
def add_product():
    product = request.json  # 상품 정보를 JSON 형태로 받음
    products.append(product)  # 상품 정보를 리스트에 추가
    return jsonify(product), 201  # 추가된 상품 반환

@app.route('/products', methods=['GET'])
def get_products():
    return jsonify(products)  # 모든 상품 반환

# 주문 관리
orders = []  # 주문 정보를 저장하는 리스트

@app.route('/orders', methods=['POST'])
def create_order():
    order = request.json  # 주문 정보를 JSON 형태로 받음
    orders.append(order)  # 주문 정보를 리스트에 추가
    return jsonify(order), 201  # 추가된 주문 반환

@app.route('/orders', methods=['GET'])
def get_orders():
    return jsonify(orders)  # 모든 주문 반환

if __name__ == '__main__':
    app.run(debug=True)

 

위의 예제코드는 모놀로식 아키텍처의 단점을 드러내는 예시입니다. 사용자 관리, 상품 관리, 주문 관리가 모두 하나의 파일에 모여 있어 각 기능이 서로 얽혀 있기 때문에 새로운 기능을 추가하거나 기존 기능을 수정할 때 복잡성이 증가합니다. 만약 'create_order' 함수에 버그가 발생하면, 다른 기능이 모두 정상 작동하더라도 전체 애플리케이션을 재배포해야 합니다. 전체 애플리케이션이 하나의 기술 스택(Flask, Python)에 묶여 있어, 예를 들어 실시간 처리에 적합한 Node.js와 같은 다른 기술을 도입하기 어려워 유연성이 떨어집니다.

 

 

마이크로서비스 아키텍처(MSA)란 소프트웨어 어플리케이션을 작은 독립적인 서비스로 나누어 개발하는 구조입니다. 각 서비스는 특정 비즈니스 기능을 수행하며, 서로 통신하여 전체 시스템을 형성합니다. 마이크로서비스 아키텍처(MSA)에서 서비스 간 통신은 여러 방식으로 이루어질 수 있으면 주요 통신 방식에는 RESTful API가 있습니다(이에 대한 자세한 내용은 'RESTful API 설계를 위한 10가지 가이드'에서 다루겠습니다). MSA의 특징은 다음과 같습니다.

 

마이크로서비스 아키텍처(MSA) 장점

  • 유연한 배포: 각 서비스가 독립적으로 배포될 수 있어, 전체 시스템에 영향을 주지 않고도 기능을 개선하거나 버그를 수정할 수 있습니다.
  • 비동기 통신: 컴포넌트들은 이벤트를 비동기적으로 송수신하며, 각 컴포넌트는 자신의 업무를 계속할 수 있습니다. 이로써 시스템은 높은 확장성과 유연성을 가질 수 있습니다.
  • 확장성: 특정 서비스만 선택적으로 확장할 수 있어, 자원 관리가 효율적입니다. 예를 들어, 사용자 수가 급증하는 서비스만 확장할 수 있습니다.
  • 장애 격리: 한 서비스의 장애가 전체 시스템에 영향을 미치지 않아, 시스템의 안정성이 높아집니다.
  • 기술 다양성: 각 마이크로서비스는 서로 다른 기술 스택이나 프로그래밍 언어를 사용할 수 있어, 팀이 최적의 도구를 선택할 수 있습니다. 
  • 팀의 독립성: 각 팀이 특정 서비스를 맡아 개발할 수 있어, 책임과 소유권이 분명해지고, 개발 속도가 빨라집니다. 

마이크로서비스 아키텍처(MSA) 단점

  • 복잡한 관리: 서비스 간의 통신과 데이터 관리가 복잡해질 수 있으며, 이를 효과적으로 관리하기 위한 추가적인 노력이 필요합니다.
  • 데이터 일관성 문제: 여러 서비스가 각자 데이터베이스를 관리하게 되면 데이터 일관성을 유지하기 어려워질 수 있습니다.
  • 배포의 복잡성: 여러 서비스를 동시에 배포해야 하는 경우, 배포 과정이 복잡해지고 문제가 발생할 수 있습니다.
  • 모니터링과 로깅의 어려움: 각 서비스의 상태와 성능을 모니터링하는 것이 복잡해지며, 효과적인 로깅 전략이 필요합니다.
  • 네트워크 오버헤드: 서비스 간의 통신이 빈번해질 경우, 네트워크 오버헤드가 증가할 수 있습니다. 이는 성능 저하로 이어질 수 있습니다.

 

마이크로서비스 아키텍처(MSA)를 적용하여 개발한 애플리케이션의 간단한 예시로 전자상거래 플랫폼을 들 수 있습니다. 전자상거래 플랫폼의 마이크로서비스는 다음과 같이 구성되어 있으며, 각 서비스는 특정 비즈니스 기능을 담당합니다. 

  • 사용자 서비스: 사용자 등록, 인증 및 프로필 관리 기능을 담당합니다.
  • 상품 서비스: 상품의 등록, 조회, 수정, 삭제 기능을 제공합니다.
  • 주문 서비스: 사용자 주문 생성 및 관리 기능을 제공합니다.
  • 결제 서비스: 결제 처리 및 결제 기록 관리 기능을 담당합니다.
  • 재고 서비스: 상품의 재고 관리 기능을 제공합니다.

동작과정

  1. 사용자 등록: 사용자가 전자상거래 플랫폼에 회원가입을 시도합니다. 클라이언트 어플리케이션(웹 또는 모바일)은 사용자 서비스에 HTTP POST 요청을 보냅니다. 사용자 서비스는 데이터를 처리한 후, 사용자 정보를 데이터베이스에 저장합니다.
  2. 상품 조회: 사용자가 상품 목록을 보려면 클라이언트 애플리케이션에서 상품 서비스에 GET 요청을 보냅니다. 상품 서비스는 데이터베이스에서 상품 정보를 조회하고, 이를 클라이언트에 반환합니다.
  3. 주문 생성: 사용자가 상품을 장바구니에 담고 주문을 완료하면, 클라이언트는 주문 서비스에 POST 요청을 보냅니다. 주문 서비스는 주문 정보를 처리하고, 재고 서비스에 해당 상품의 재고를 확인하기 위한 요청을 보냅니다. 재고 서비스는 재고 상태를 확인하고, 결과를 주문 서비스에 반환합니다. 주문 서비스는 결제 서비스를 호출하여 결제 정보를 생성하고, 최종 주문을 데이터베이스에 저장합니다.
  4. 결제 처리: 주문 서비스는 결제 서비스에 결제 요청을 보냅니다. 결제 서비스는 외부 결제 게이트웨이에 연결되어 결제를 처리합니다. 결제가 성공적으로 완료되면 결제 서비스는 주문 서비스에 성공 응답을 보내고, 결제 정보를 데이터베이스에 기록합니다.
  5. 주문 확인: 클라이언트 애플리케이션은 주문 완료 후 사용자에게 주문 확인 페이지를 표시합니다. 이 과정에서 주문 서비스는 최종 주문 정보를 클라이언트에 반환합니다.
  6. 재고 업데이트: 결제가 완료된 후, 주문 서비스는 재고 서비스에 해당 상품의 재고 수량을 감소시키는 요청을 보냅니다. 재고 서비스는 재고를 업데이트하고, 성공적인 응답을 주문 서비스에 반환합니다.

 

최근 기술의 발전과 비즈니스 환경의 변화로 소프트웨어 어플리케이션의 요구사항이 점점 복잡해지고 있습니다. 이에 대한 대응으로 MSA는 강력한 아키텍처 패턴이지만, 여전히 극복해야할 과제가 많다는 것을 깨닫게 되었습니다. 실제 프로젝트를 통해 이론 지식을 실무에 적용해보고 한계점을 스스로 느끼면서 MSA의 다음 단계인 EDA('EDA(Event-Driven Architecture) 쉽게 이해하기')의 가치와 효용성을 이해하고 싶어졌습니다.