MSA 패턴 유형별 비교

MSA 패턴 유형별 비교 https://microservices.io/patterns/ 아래 표는 MSA의 주요 패턴 유형들을 체계적으로 정리한 것이다. 기본 인프라 관련 패턴 패턴 유형 목적 특징 장점 단점 주요 패턴 예시 Cross-cutting Concern Patterns 여러 서비스에 공통적으로 적용되는 기능을 분리하여 관리 인프라 수준에서 공통 관심사 처리 • 코드 중복 감소 • 일관성 있는 처리 • 유지보수 용이 • 추가적인 인프라 필요 • 복잡도 증가 • Service Mesh • Sidecar • Ambassador Configuration Management Patterns 서비스 구성 정보를 외부화하여 중앙 관리 환경별 설정 분리 및 동적 구성 지원 • 유연한 설정 변경 • 환경별 구성 용이 • 구성 정보 관리 복잡 • 보안 고려 필요 • External Configuration • Config Server • Environment Variables Service Registry Patterns 서비스 위치 정보를 동적으로 관리 서비스 등록 및 발견 자동화 • 동적 확장 용이 • 자동 장애 감지 • 추가 인프라 필요 • 의존성 증가 • Service Discovery • Service Registry • Client-side Discovery 데이터 관련 패턴 패턴 유형 목적 특징 장점 단점 주요 패턴 예시 Database Patterns 데이터 저장소 설계 및 관리 전략 서비스별 독립적 데이터 관리 • 데이터 독립성 • 확장성 향상 • 데이터 일관성 관리 어려움 • 복잡도 증가 • Database per Service • CQRS • Saga Data Management Patterns 데이터 처리 및 동기화 전략 분산 데이터 관리 • 데이터 일관성 보장 • 효율적 처리 • 구현 복잡도 • 성능 오버헤드 • Event Sourcing • Materialized View • Shared Data State Management Patterns 서비스 상태 관리 전략 상태 정보의 일관성 유지 • 상태 추적 용이 • 복구 용이 • 구현 복잡도 • 성능 영향 • Stateless Service • Session State • Distributed Cache 서비스 구조 및 통신 관련 패턴 패턴 유형 목적 특징 장점 단점 주요 패턴 예시 Decomposition Patterns 서비스 분할 전략 비즈니스 기능 기반 분할 • 독립적 개발/배포 • 확장성 향상 • 서비스 경계 설정 어려움 • 통신 복잡도 증가 • Business Capability • Domain-Driven • Strangler Communication Patterns 서비스 간 통신 방식 정의 동기/비동기 통신 지원 • 유연한 통신 • 느슨한 결합 • 메시지 관리 복잡 • 디버깅 어려움 • Synchronous RPC • Event-Driven • Message Queue Integration Patterns 서비스 통합 전략 다양한 통합 방식 제공 • 유연한 통합 • 재사용성 • 구현 복잡도 • 관리 어려움 • API Gateway • BFF • Aggregator 운영 및 품질 관련 패턴 패턴 유형 목적 특징 장점 단점 주요 패턴 예시 Deployment Patterns 서비스 배포 전략 무중단 배포 지원 • 안정적 배포 • 위험 감소 • 인프라 비용 • 복잡도 증가 • Blue-Green • Canary • Rolling Update Testing Patterns 서비스 테스트 전략 다양한 수준의 테스트 지원 • 품질 보장 • 신뢰성 향상 • 테스트 환경 구축 비용 • 실행 시간 증가 • Consumer-Driven • Contract Test • End-to-End Test Observability Patterns 서비스 모니터링 전략 시스템 상태 가시화 • 문제 감지 용이 • 분석 용이 • 데이터 양 증가 • 저장/분석 비용 • Distributed Tracing • Log Aggregation • Health Check 성능 및 보안 관련 패턴 패턴 유형 목적 특징 장점 단점 주요 패턴 예시 Scalability Patterns 서비스 확장성 확보 동적 확장/축소 지원 • 자원 효율성 • 비용 최적화 • 구현 복잡도 • 관리 어려움 • Horizontal Scaling • Sharding • Load Balancer Performance Patterns 성능 최적화 전략 응답 시간 및 처리량 개선 • 사용자 경험 향상 • 자원 효율성 • 구현 복잡도 • 유지보수 어려움 • Caching • Async Processing • Throttling Versioning Patterns API 버전 관리 전략 하위 호환성 보장 • 안정적 변경 • 클라이언트 독립성 • 관리 복잡도 • 테스트 부담 • URI Versioning • Header Versioning • Content Negotiation Resilience Patterns 장애 대응 전략 시스템 복원력 향상 • 안정성 향상 • 가용성 보장 • 구현 복잡도 • 성능 영향 • Circuit Breaker • Bulkhead • Retry Security Patterns 보안 통제 전략 다층적 보안 구현 • 보안성 향상 • 규정 준수 • 구현 복잡도 • 성능 영향 • OAuth/OIDC • API Security • Zero Trust 패턴 선택 시 고려사항 실제 구현 시에는 비즈니스 요구사항, 기술적 제약사항, 팀의 역량 등을 고려하여 적절한 패턴을 선택하고 조합해야 한다. 또한, 각 패턴은 독립적으로 사용될 수도 있지만, 대부분의 경우 여러 패턴을 함께 사용하여 시너지를 얻을 수 있다. ...

November 19, 2024 · 4 min · Me

Publisher-Subscriber Pattern

Publisher-Subscriber Pattern Publisher-Subscriber Pattern(게시자-구독자 패턴)은 소프트웨어 아키텍처에서 중요한 디자인 패턴 중 하나로, 분산 시스템에서 비동기 통신을 구현하는 데 널리 사용된다. 이 패턴은 메시지를 보내는 발행자(Publisher)와 메시지를 받는 구독자(Subscriber) 사이의 느슨한 결합(Loose Coupling)을 제공하는 메시징 패턴으로, 발행자는 메시지를 특정 주제(Topic)나 채널로 발행하고, 해당 주제를 구독하는 모든 구독자들이 그 메시지를 받게 된다. 이 패턴은 컴포넌트 간의 느슨한 결합을 제공하여 확장성과 유연성을 높이는 데 기여한다. https://learn.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber 기본 개념 Publisher-Subscriber 패턴의 핵심 개념은 다음과 같다: ...

September 27, 2024 · 3 min · Me

Retry Pattern

Retry Pattern Retry Pattern은 분산 시스템이나 마이크로서비스 아키텍처에서 일시적인 오류(Transient Failure)를 처리하기 위한 핵심 설계 패턴이다. 네트워크 불안정, 일시적인 서비스 중단 등 일시적인 실패 상황에서 시스템의 복원력(Resilience)을 강화하는 데 목적을 둔다. 이 패턴은 분산 시스템의 안정성을 높이는 필수 도구이지만, 남용할 경우 역효과를 낼 수 있으므로 신중한 정책 수립이 필요하다. Retry Pattern의 핵심 개념 작동 원리 실패한 작업 자동 재시도: API 호출, 데이터베이스 접근 등 실패 가능성이 있는 작업을 정의된 정책에 따라 재시도한다. 일시적 오류 감지: 네트워크 타임아웃, HTTP 5xx 에러, 데이터베이스 연결 실패 등 일시적인 오류만 대상으로 한다. 주요 구성 요소 ...

September 27, 2024 · 3 min · Me

Master-Slave

Master-Slave Pattern 마스터-슬레이브 패턴(Master-Slave Pattern)은 분산 시스템에서 널리 사용되는 소프트웨어 아키텍처 패턴. 이 패턴은 하나의 마스터 컴포넌트와 여러 슬레이브 컴포넌트로 구성되어 있으며, 작업을 효율적으로 분배하고 관리하는 데 사용된다. 주요 구성요소 마스터(Master): 작업 분배와 조정을 담당합니다 슬레이브들의 상태를 관리합니다 작업의 완료 여부를 추적합니다 결과를 취합하고 클라이언트에게 전달합니다 슬레이브(Slave): 마스터로부터 할당받은 작업을 처리합니다 독립적으로 동작합니다 처리 결과를 마스터에게 반환합니다 자신의 상태(사용 가능/처리 중)를 관리합니다 작업(Task): 처리해야 할 작업의 단위입니다 작업에 필요한 데이터와 결과를 포함합니다 고유한 식별자를 가집니다 작동 방식 마스터는 전체 작업을 여러 개의 하위 작업으로 분할합니다. 분할된 작업을 슬레이브들에게 분배합니다. 슬레이브들은 할당받은 작업을 독립적으로 수행합니다. 작업 완료 후, 슬레이브들은 결과를 마스터에게 보고합니다. 마스터는 모든 결과를 취합하여 최종 결과를 생성합니다. 장점 병렬 처리: 여러 슬레이브가 동시에 작업을 수행하여 전체 처리 속도를 향상시킵니다. 확장성: 슬레이브의 수를 늘리거나 줄여 시스템의 처리 능력을 조절할 수 있습니다. 부하 분산: 마스터가 작업을 효율적으로 분배하여 시스템 자원을 최적화할 수 있습니다. fault tolerance: 일부 슬레이브가 실패해도 마스터가 작업을 재분배하여 시스템이 계속 작동할 수 있습니다. 단점 단일 장애점: 마스터 노드가 실패하면 전체 시스템이 중단될 수 있습니다. 복잡성: 여러 노드 간의 통신과 동기화를 관리해야 하므로 시스템이 복잡해질 수 있습니다. 불균형한 작업 크기: 작업의 크기가 불균형할 경우 일부 슬레이브가 과부하될 수 있습니다. 적용 분야 데이터베이스 복제: 마스터 데이터베이스가 쓰기 작업을 처리하고, 슬레이브 데이터베이스들이 읽기 작업을 분산 처리합니다. 분산 컴퓨팅: 대규모 계산 작업을 여러 노드에 분산하여 처리합니다. 데이터 처리: 빅데이터 처리 시스템에서 마스터 노드가 작업을 관리하고 슬레이브 노드들이 실제 데이터 처리를 수행합니다. 임베디드 시스템: 여러 센서나 액추에이터를 제어하는 데 사용됩니다. 구현 예시 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 import threading from abc import ABC, abstractmethod from queue import Queue from typing import List import time import random # 작업을 정의하는 기본 클래스 class Task: def __init__(self, task_id: int, data: List[int]): self.task_id = task_id self.data = data self.result = None # 슬레이브의 추상 클래스 class Slave(ABC): def __init__(self, slave_id: int): self.slave_id = slave_id self.is_busy = False @abstractmethod def process_task(self, task: Task) -> None: pass # 구체적인 슬레이브 구현 - 숫자 배열의 합을 계산 class SumCalculatorSlave(Slave): def process_task(self, task: Task) -> None: print(f"Slave {self.slave_id} starting task {task.task_id}") # 실제 작업 처리를 시뮬레이션하기 위한 지연 time.sleep(random.uniform(0.5, 2.0)) task.result = sum(task.data) print(f"Slave {self.slave_id} completed task {task.task_id}, result: {task.result}") # 마스터 클래스 class Master: def __init__(self, num_slaves: int): # 슬레이브 풀 초기화 self.slaves = [SumCalculatorSlave(i) for i in range(num_slaves)] # 작업 큐 self.task_queue = Queue() # 완료된 작업 저장 self.completed_tasks = {} # 작업 분배를 위한 쓰레드 self.distribution_thread = threading.Thread(target=self._distribute_tasks) self.is_running = True def start(self): """마스터 시작""" print("Master starting…") self.distribution_thread.start() def stop(self): """마스터 종료""" print("Master stopping…") self.is_running = False self.distribution_thread.join() def submit_task(self, task: Task): """새로운 작업 제출""" print(f"Submitting task {task.task_id}") self.task_queue.put(task) def get_result(self, task_id: int) -> int: """작업 결과 조회""" while task_id not in self.completed_tasks: time.sleep(0.1) # 결과가 준비될 때까지 대기 return self.completed_tasks[task_id] def _distribute_tasks(self): """작업 분배 로직""" while self.is_running: try: # 대기 중인 작업이 있는지 확인 task = self.task_queue.get(timeout=1.0) # 사용 가능한 슬레이브 찾기 slave = self._get_available_slave() if slave: # 작업 처리를 위한 새 쓰레드 시작 threading.Thread( target=self._process_task_with_slave, args=(slave, task) ).start() except Queue.Empty: continue def _get_available_slave(self) -> Slave: """사용 가능한 슬레이브 찾기""" for slave in self.slaves: if not slave.is_busy: return slave return None def _process_task_with_slave(self, slave: Slave, task: Task): """슬레이브를 사용하여 작업 처리""" try: slave.is_busy = True slave.process_task(task) self.completed_tasks[task.task_id] = task.result finally: slave.is_busy = False # 사용 예시 def main(): # 3개의 슬레이브로 마스터 생성 master = Master(num_slaves=3) master.start() try: # 여러 작업 제출 tasks = [ Task(1, [1, 2, 3, 4, 5]), Task(2, [10, 20, 30, 40, 50]), Task(3, [100, 200, 300, 400, 500]), Task(4, [1000, 2000, 3000, 4000, 5000]) ] # 작업 제출 for task in tasks: master.submit_task(task) # 결과 수집 for task in tasks: result = master.get_result(task.task_id) print(f"Final result for task {task.task_id}: {result}") # 잠시 대기 후 종료 time.sleep(5) finally: master.stop() if __name__ == "__main__": main() 용어 정리 용어 설명 참고 및 출처

September 27, 2024 · 4 min · Me

Pipe-Filter Pattern

Pipe-Filter Pattern 파이프-필터 패턴(Pipe-Filter Pattern)은 데이터 스트림을 처리하는 시스템에서 사용되는 소프트웨어 아키텍처 패턴. 이 패턴은 복잡한 처리 과정을 독립적인 단계로 나누어 모듈화하고, 이들을 순차적으로 연결하여 데이터를 처리한다. 주요 구성 요소 필터(Filter): 단일 작업을 수행하는 처리 컴포넌트입니다 입력을 받아 처리하고 출력을 생성합니다 독립적으로 동작하며 다른 필터에 대해 알지 못합니다 재사용이 가능하고 조합할 수 있어야 합니다 파이프(Pipe): 필터 간의 데이터 전달을 담당합니다 데이터 버퍼링과 동기화를 처리합니다 필터들을 느슨하게 결합시킵니다 대개 큐나 스트림으로 구현됩니다 파이프라인(Pipeline): ...

September 27, 2024 · 4 min · Me

Producer-Consumer Pattern

Producer-Consumer Pattern Producer-Consumer Pattern은 소프트웨어 아키텍처에서 중요한 디자인 패턴 중 하나로, 주로 동시성 프로그래밍과 분산 시스템에서 사용된다. 이 패턴은 데이터를 생성하는 프로듀서(Producer)와 데이터를 소비하는 컨슈머(Consumer) 사이의 작업을 분리하여 효율적인 데이터 처리를 가능하게 한다. https://jenkov.com/tutorials/java-concurrency/producer-consumer.html 주요 구성 요소 프로듀서 (Producer): 데이터나 작업을 생성하는 엔티티. 컨슈머 (Consumer): 프로듀서가 생성한 데이터나 작업을 처리하는 엔티티. 버퍼 (Buffer): 프로듀서와 컨슈머 사이에서 데이터를 임시 저장하는 공유 자원. 주로 큐(Queue)의 형태로 구현된다. 작동 방식 프로듀서는 데이터나 작업을 생성하여 버퍼에 추가한다. 컨슈머는 버퍼에서 데이터나 작업을 가져와 처리한다. 버퍼는 프로듀서와 컨슈머 사이의 중간 저장소 역할을 하며, 동기화를 관리한다. 주요 특징 비동기 처리: 프로듀서와 컨슈머가 독립적으로 작동하여 비동기 처리가 가능하다. 버퍼링: 버퍼를 통해 생산과 소비 속도의 차이를 조절할 수 있다. 병렬 처리: 여러 프로듀서와 컨슈머가 동시에 작업할 수 있어 병렬 처리가 가능하다. 느슨한 결합: 프로듀서와 컨슈머는 서로에 대해 직접적인 의존성이 없다. 장점 처리량 향상: 생산과 소비를 병렬로 수행하여 전체 시스템의 처리량을 높일 수 있다. 유연성: 프로듀서와 컨슈머를 독립적으로 확장할 수 있다. 부하 분산: 버퍼를 통해 작업 부하를 균등하게 분산시킬 수 있다. 피크 부하 관리: 일시적인 부하 증가를 버퍼를 통해 완화할 수 있다. 단점 복잡성: 동기화와 버퍼 관리로 인해 시스템 복잡도가 증가할 수 있다. 메모리 사용: 버퍼가 큰 경우 메모리 사용량이 증가할 수 있다. 지연 가능성: 버퍼가 가득 차거나 비어있을 때 지연이 발생할 수 있다. 적용 사례 작업 큐 시스템: 백그라운드 작업 처리, 이메일 발송 등의 비동기 작업 관리 로그 처리 시스템: 대량의 로그 데이터를 효율적으로 수집하고 분석 스트리밍 데이터 처리: 실시간 데이터 스트림의 처리 및 분석 멀티스레드 애플리케이션: 스레드 간 작업 분배 및 동기화 구현 시 고려사항 동기화 메커니즘: 버퍼 접근 시 적절한 동기화 방법(예: 세마포어, 뮤텍스) 사용 버퍼 크기 조정: 시스템 요구사항에 맞는 적절한 버퍼 크기 설정 예외 처리: 버퍼 오버플로우, 언더플로우 등의 예외 상황 관리 종료 조건: 프로듀서와 컨슈머의 적절한 종료 시점 및 방법 정의 참고 및 출처

September 27, 2024 · 2 min · Me

Event-Bus Pattern

Event-Bus Pattern 소프트웨어 시스템의 컴포넌트 간 통신을 단순화하고 유연성을 높이는 아키텍처 패턴이다. 이 패턴은 발행-구독(Publish-Subscribe) 모델을 기반으로 하며, 컴포넌트 간의 느슨한 결합을 촉진한다. 장점 느슨한 결합: 컴포넌트 간 직접적인 의존성이 줄어들어 시스템의 유연성이 향상된다. 확장성: 새로운 컴포넌트를 쉽게 추가하거나 제거할 수 있어 시스템 확장이 용이한다. 비동기 통신: 이벤트 기반의 비동기 통신으로 시스템의 반응성과 성능이 향상된다. 단순화된 통신: 복잡한 컴포넌트 간 통신 로직을 단순화할 수 있다. 단점 복잡성 증가: 시스템 전체의 흐름을 파악하기 어려울 수 있다. 메모리 사용 증가: 모든 구독자에게 이벤트가 전달되므로 메모리 사용량이 증가할 수 있다. 디버깅의 어려움: 비동기적 특성으로 인해 문제 추적이 어려울 수 있다. 핵심 구성요소 https://medium.com/elixirlabs/event-bus-implementation-s-d2854a9fafd5 Event Bus with multiple subscribers(green arrows) and notifiers(red arrows) ...

September 26, 2024 · 4 min · Me