새소식

반응형
Architecture

2025년에 꼭 알아야 할 5가지 마이크로서비스 디자인 패턴 (Python FastAPI 예시 포함)

  • -
반응형

마이크로서비스 디자인 패턴

 

마이크로서비스의 복잡성을 해결하는 필수 디자인 패턴

마이크로서비스는 현대 소프트웨어 개발의 핵심으로 자리 잡았습니다. 하나의 거대한 애플리케이션 대신 작고 독립적인 서비스들로 시스템을 구성하면 유연성과 확장성을 극대화할 수 있죠. 하지만 이런 장점에는 대가가 따릅니다. 서비스 간 통신, 데이터 관리, 장애 처리 등 복잡성이 증가하기 때문입니다. 이때 디자인 패턴이 구세주처럼 나타납니다. 자주 발생하는 문제를 해결하는 검증된 설계 패턴으로, 개발자들이 시간과 고민을 덜 수 있도록 도와줍니다.

 

이 글에서는 2025년에 주목해야 할 5가지 마이크로서비스 디자인 패턴을 소개합니다. 단순한 개념 설명에 그치지 않고, Python FastAPI를 활용한 실제 예제와 모범 사례까지 함께 제공하니 실무에서도 바로 적용할 수 있을 것입니다. 초보 개발자든, 경험 많은 개발자든 이 패턴들이 여러분의 프로젝트를 한 단계 발전시키는 데 도움이 될 거라 확신합니다. 자, 시작해볼까요?

반응형

1. API 게이트웨이 패턴 (API Gateway Pattern)

✨ 개념

마이크로서비스 아키텍처에서는 하나의 기능을 수행하기 위해 여러 서비스가 협력해야 합니다. 예를 들어, 온라인 쇼핑몰에서 주문을 조회하려면 사용자 서비스, 주문 서비스, 결제 서비스 등 여러 백엔드와 통신해야 합니다. 만약 클라이언트가 이 모든 서비스에 직접 접근한다면, 요청이 복잡해지고 성능 저하가 발생하며 관리도 어려워집니다.

API 게이트웨이 패턴은 이런 혼란을 해결하기 위해 모든 클라이언트 요청이 통과하는 단일 진입점을 제공합니다. API 게이트웨이가 각 요청을 분석하고 적절한 서비스로 전달한 뒤, 여러 서비스의 응답을 조합하여 클라이언트에게 반환하는 방식입니다.

🌐 동작 방식

  1. 클라이언트가 API 게이트웨이에 요청을 보냅니다. (예: /orders)
  2. API 게이트웨이가 요청을 분석하고 필요한 서비스로 전달합니다.
  3. 여러 서비스의 응답을 하나로 합쳐 클라이언트에 반환합니다.

📝 실전 예제 (FastAPI 활용)

from fastapi import FastAPI, APIRouter
import requests

app = FastAPI()
user_router = APIRouter()
order_router = APIRouter()

@user_router.get("/users/{user_id}")
async def get_user(user_id: str):
    response = requests.get(f"http://user-service/users/{user_id}")
    return response.json()

@order_router.get("/orders/{order_id}")
async def get_order(order_id: str):
    response = requests.get(f"http://order-service/orders/{order_id}")
    return response.json()

app.include_router(user_router, prefix="/users")
app.include_router(order_router, prefix="/orders")

이 코드에서는 API 게이트웨이가 /users 요청을 사용자 서비스로, /orders 요청을 주문 서비스로 라우팅합니다. 클라이언트는 내부 서비스를 몰라도 게이트웨이를 통해 접근할 수 있습니다.

💡 모범 사례

  • 캐싱 적용: 자주 요청되는 데이터는 캐싱하여 성능을 개선하세요.
  • 보안 강화: OAuth2나 JWT를 활용해 인증과 인가를 추가하세요.
  • 장애 대비: 다음에 소개할 서킷 브레이커 패턴을 결합하여 안정성을 높이세요.

2. 사가 패턴 (Saga Pattern)

✨ 개념

마이크로서비스 환경에서는 하나의 작업을 여러 서비스가 함께 처리하는 경우가 많습니다. 예를 들어, 주문을 처리할 때 다음과 같은 단계를 거쳐야 합니다:

  1. 결제 서비스에서 금액을 차감
  2. 재고 서비스에서 물품을 차감
  3. 주문 서비스에서 주문을 생성

하지만 중간에 한 서비스가 실패하면? 데이터 불일치 문제가 발생할 수 있습니다. 사가 패턴은 분산 트랜잭션을 안전하게 관리하는 기법으로, 각 서비스가 독립적으로 단계를 처리하고, 실패 시 롤백(보상 트랜잭션)을 수행할 수 있도록 합니다.

📝 실전 예제 (FastAPI 활용, 안무 기반 사가)

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class OrderCreatedEvent(BaseModel):
    order_id: str
    user_id: str
    items: list[str]

@app.post("/orders")
async def create_order(order: OrderCreatedEvent):
    publish_event("order_created", order.dict())
    return {"message": "Order created"}

def handle_order_created_event(event):
    payment_request = {"order_id": event["order_id"], "amount": calculate_amount(event["items"])}
    payment_service.process_payment(payment_request)

이 코드에서는 주문이 생성되면 order_created 이벤트를 발행하고, 이를 감지한 결제 서비스가 결제를 처리합니다. 실패 시 주문을 취소하는 트랜잭션을 실행할 수도 있습니다.

💡 모범 사례

  • 재시도 로직 추가: 네트워크 오류 발생 시 재시도를 시도하세요.
  • 로깅 필수: 각 단계의 진행 상태를 철저히 로깅하여 문제 발생 시 추적할 수 있도록 합니다.
  • 테스트 강화: 다양한 장애 상황을 시뮬레이션하여 데이터 불일치가 발생하지 않도록 합니다.

3. 서킷 브레이커 패턴 (Circuit Breaker Pattern)

✨ 개념

마이크로서비스는 서로 의존적이므로, 한 서비스가 장애를 일으키면 전체 시스템이 영향을 받을 수 있습니다. 예를 들어, 결제 서비스가 다운되면 주문 시스템까지 멈추는 상황이 발생할 수 있습니다.

서킷 브레이커 패턴은 이런 장애 확산을 방지하기 위해 특정 서비스가 일정 횟수 이상 실패하면 추가 요청을 차단하고, 일정 시간이 지난 후 다시 정상 요청을 시도하는 방식으로 동작합니다.

📝 실전 예제 (FastAPI + circuitbreaker 활용)

from fastapi import FastAPI, HTTPException
from circuitbreaker import circuit, CircuitBreakerError
import requests

app = FastAPI()

@circuit(failure_threshold=5, recovery_timeout=30)
def get_user(user_id: str):
    response = requests.get(f"http://user-service/users/{user_id}")
    if response.status_code != 200:
        raise HTTPException(status_code=503, detail="Service Unavailable")
    return response.json()

@app.get("/users/{user_id}")
async def read_user(user_id: str):
    try:
        return get_user(user_id)
    except CircuitBreakerError:
        return {"user": "default", "name": "Guest"}

이 코드에서는 사용자 서비스가 일정 횟수 이상 실패하면 기본 사용자 정보를 반환하여 장애가 확산되지 않도록 합니다.


4. 이벤트 소싱 패턴 (Event Sourcing Pattern)

일반적인 시스템은 현재 상태만 저장합니다. 예를 들어, 계좌 잔고가 10만 원이라면 그게 전부죠. 하지만 잔고가 어떻게 변했는지 알고 싶다면?

**이벤트 소싱 패턴(Event Sourcing Pattern)**은 상태 변화를 이벤트로 기록하여 과거 이력을 완벽히 재구성할 수 있도록 해줍니다.

🎯 이벤트 소싱 패턴이란?

데이터를 덮어쓰지 않고, 모든 변화를 이벤트로 저장합니다. 이후 이벤트를 순서대로 재생하면 현재 상태를 도출할 수 있습니다.

🚀 실전 예제: FastAPI로 이벤트 저장

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class OrderCreatedEvent(BaseModel):
    order_id: str
    user_id: str
    items: list[str]

# 간단한 이벤트 저장소
event_store = []

# 주문 생성 엔드포인트
@app.post("/orders")
async def create_order(order: OrderCreatedEvent):
    event_store.append(order.dict())
    return {"message": "Order created"}

# 현재 상태 재구성 함수
def get_current_state():
    state = {}
    for event in event_store:
        # 이벤트 적용 로직 (예: state 업데이트)
        pass
    return state

✅ 주문 이벤트를 저장하고, 나중에 이벤트를 재생하여 주문 상태를 확인할 수 있습니다.

🏆 모범 사례

이벤트 저장소: Apache Kafka나 EventStoreDB 같은 도구를 활용하세요.

스냅샷 사용: 긴 이벤트 목록을 빠르게 재구성하려면 주기적으로 스냅샷을 저장하세요.

불변성 유지: 이벤트는 수정하지 말고, 철저히 문서화하세요.


5. 스트랭글러 피그 패턴 (Strangler Fig Pattern)

오래된 모놀리식 시스템을 유지보수하기 어렵지만, 한 번에 마이크로서비스로 전환하는 것은 위험 부담이 큽니다. **스트랭글러 피그 패턴(Strangler Fig Pattern)**은 레거시 시스템을 점진적으로 교체하는 전략입니다.

🎯 스트랭글러 피그 패턴이란?

모놀리스의 기능을 하나씩 마이크로서비스로 옮깁니다. 마치 나무를 감싸며 자라는 **스트랭글러 피그(Strangler Fig)**처럼, 새로운 시스템이 점점 커지면서 기존 시스템을 대체합니다.

🛠️ 적용 방법

1️⃣ 교체할 기능(예: 사용자 관리)을 선정합니다.

2️⃣ 해당 기능을 새로운 마이크로서비스로 개발합니다.

3️⃣ API 게이트웨이를 통해 요청을 새 서비스로 라우팅합니다.

🚀 실전 예제: FastAPI로 점진적 전환

from fastapi import FastAPI

app = FastAPI()

# 기존 모놀리스 엔드포인트
@app.get("/users/{user_id}")
async def get_user_old(user_id: str):
    return {"user": user_id, "source": "monolith"}

# 새로운 마이크로서비스 엔드포인트
@app.get("/new/users/{user_id}")
async def get_user_new(user_id: str):
    return {"user": user_id, "source": "microservice"}

✅ 처음에는 /users를 사용하다가 점차 /new/users로 전환하며 모놀리스를 줄여나갑니다.


🏆 모범 사례

작은 시작: 위험도가 낮은 기능부터 옮기세요.

모니터링 강화: 마이그레이션 중 문제를 파악하려면 메트릭을 적극 활용하세요.

문서화: 팀원들이 진행 상황을 쉽게 이해할 수 있도록 기록을 남기세요.


🎯 마무리

이 5가지 패턴은 마이크로서비스의 복잡성을 줄이고, 확장 가능하며 안정적인 시스템을 만드는 데 큰 도움이 됩니다.

API 게이트웨이로 요청을 단순화하고

사가 패턴으로 트랜잭션을 관리하며

서킷 브레이커로 장애를 방지하고

이벤트 소싱으로 이력을 추적하며

스트랭글러 피그로 레거시를 현대화해보세요!

 

 

 

함께보면 좋은글

[Code Smell] 흠흠 코드에서 냄새나는데? 개발자라면 반드시 알아야 할 코드 스멜

 

[Code Smell] 흠흠 코드에서 냄새나는데? 개발자라면 반드시 알아야 할 코드 스멜

소프트웨어 개발에서 깨끗하고 유지보수하기 쉬운 코드를 작성하는 것은 견고하고 확장 가능한 애플리케이션을 만드는 데 필수적입니다. 하지만 경험이 많은 개발자조차도 무심코 "코드 스멜(

intelloper.tistory.com

[SW Architecture] 소프트웨어 아키텍처 패턴들을 탐구해보자

 

[SW Architecture] 소프트웨어 아키텍처 패턴들을 탐구해보자

소프트웨어 아키텍처 패턴에 대하여..소프트웨어 아키텍처는 단순히 코드를 작성하는 것을 넘어, 시스템의 구조와 설계를 결정하는 중요한 작업입니다. 올바른 아키텍처는 애플리케이션의 유

intelloper.tistory.com

[Backend 면접 질문 시리즈] 마이크로서비스 아키텍처: 현대 소프트웨어 개발의 핵심 트렌드

 

[Backend 면접 질문 시리즈] 마이크로서비스 아키텍처: 현대 소프트웨어 개발의 핵심 트렌드

Intro. 면접에서 나오는 질문은 보편적으로 중요한 개념이며 하루 아침에 이해되고 외워 지는게 아닙니다. 평소에 꾸준히 지식을 습득하고 이해하는것이 중요합니다.  마이크로서비스 아키텍처

intelloper.tistory.com

 

반응형
Contents

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

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