Self-contained Service

Self-contained Service 마이크로서비스 아키텍처(MSA)에서 “self-contained service” 패턴은 서비스의 자율성과 독립성을 극대화하는 중요한 개념이다. Self-contained Service는 단일 비즈니스 기능을 완전히 독립적으로 구현한 서비스를 의미한다. 이 서비스는 자체적으로 데이터를 저장하고, 비즈니스 로직을 처리하며, 사용자 인터페이스를 제공할 수 있다. Self-contained Service 패턴은 MSA의 핵심 원칙을 구현하는 방법 중 하나로, 서비스의 자율성과 독립성을 극대화하여 시스템의 유연성과 확장성을 높이는 데 기여한다. 하지만 이 패턴을 적용할 때는 시스템의 복잡성 증가와 데이터 일관성 관리 등의 도전 과제를 고려해야 한다. ...

November 13, 2024 · 2 min · Me

Service per team

Service per Team Service per team 패턴은 각 마이크로서비스를 개별 팀이 소유하고 관리하는 방식이다. 이 패턴에서는 각 팀이 특정 비즈니스 기능을 담당하며, 해당 기능의 코드베이스를 소유한다. Service per team 패턴은 팀의 자율성과 책임감을 높이는 동시에 마이크로서비스 아키텍처의 이점을 최대화할 수 있는 효과적인 접근 방식이다. 그러나 이 패턴을 성공적으로 구현하기 위해서는 조직 문화, 팀 구조, 그리고 기술적 인프라 등 여러 측면에서의 신중한 고려가 필요하다. 주요 특징 팀 자율성: 각 팀은 자신의 서비스를 독립적으로 개발, 테스트, 배포, 확장할 수 있다. API 중심 협업: 팀들은 주로 API를 통해 상호작용하며, 다른 팀과의 협업을 최소화한다. 소규모 팀: 일반적으로 “two-pizza team” 크기의 소규모 팀이 각 서비스를 담당한다. 인지 부하 감소: 팀원들이 전체 시스템이 아닌 특정 서비스에만 집중할 수 있어 인지 부하가 감소한다. 장점 팀 자율성 강화: 각 팀이 독립적으로 의사 결정을 내릴 수 있다. 느슨한 결합: 팀 간의 의존성이 줄어들어 더 유연한 개발이 가능하다. 코드 품질 향상: 장기적인 코드 소유권으로 인해 코드 품질이 개선된다. 빠른 개발 및 배포: 작은 팀이 독립적으로 개발하고 배포할 수 있어 시장 변화에 빠르게 대응할 수 있다. 단점 복잡한 프로젝트 조정: 여러 서비스에 걸친 복잡한 프로젝트의 경우 팀 간 조정이 어려워질 수 있다. 높은 WIP (Work in Progress): 각 팀이 항상 바쁘게 유지되어야 하므로 진행 중인 작업이 많아질 수 있다. 좁은 가치 흐름: 이상적인 구현에서는 팀들이 완전히 분리되어 있어, 조직 전체의 가치 흐름이 좁아질 수 있다. 최적화되지 않은 우선순위 지정: 팀의 가용성이 프로젝트 우선순위 결정의 주요 요인이 될 수 있다. 구현 시 고려사항 팀 구성: 각 서비스를 담당할 수 있는 cross-functional 팀을 구성해야 한다. 서비스 경계 정의: 비즈니스 기능과 하위 도메인을 기반으로 서비스 경계를 명확히 정의해야 한다. 팀 간 커뮤니케이션: API 설계와 변경에 대한 팀 간 효과적인 커뮤니케이션 채널을 구축해야 한다. 확장성 고려: 새로운 팀을 추가하거나 기존 서비스를 분할할 때의 전략을 미리 수립해야 한다. 예시: 대규모 전자상거래 플랫폼을 운영하는 기업을 예로 들어보자. 이 기업은 다음과 같은 주요 비즈니스 기능을 가지고 있다: ...

November 13, 2024 · 2 min · Me

Decompose by Business Capability

Decompose by Business Capability “Decompose by Business Capability” 패턴은 마이크로서비스 아키텍처(MSA)에서 중요한 분해 패턴이다. 이 패턴은 비즈니스 능력을 기반으로 애플리케이션을 마이크로서비스로 분해하는 방법을 제시한다. 이 패턴은 조직의 비즈니스 능력을 기반으로 마이크로서비스를 정의한다. 비즈니스 능력은 조직이 가치를 창출하기 위해 수행하는 특정 기능이나 프로세스를 의미한다. 주요 목적은 다음과 같다: 비즈니스 목표와 소프트웨어 개발의 정렬 독립적으로 개발 및 유지보수 가능한 서비스 생성 조직 구조와 시스템 아키텍처의 일치 이 패턴을 효과적으로 적용하려면 조직의 비즈니스 도메인에 대한 깊은 이해가 필요하며, 지속적인 비즈니스 분석과 서비스 경계의 조정이 필요하다. ...

November 13, 2024 · 3 min · Me

Decompose by Subdomain

Decompose by Subdomain “Decompose by Subdomain” 패턴은 마이크로서비스 아키텍처(MSA)에서 중요한 분해 패턴 중 하나이다. 이 패턴은 도메인 주도 설계(DDD)의 개념을 기반으로 하며, 비즈니스 도메인을 여러 하위 도메인으로 나누어 마이크로서비스를 설계하는 방법이다. 이 패턴을 효과적으로 적용하려면 비즈니스 도메인에 대한 깊은 이해와 지속적인 분석이 필요하다. 또한, 하위 도메인 간의 상호작용을 고려하여 서비스 간 통신을 설계해야 한다. 주요 특징 비즈니스 중심 접근: 기술적 세부사항보다 비즈니스 기능에 초점을 맞춘다. 하위 도메인 분류: 핵심(Core): 비즈니스의 핵심 차별화 요소 지원(Supporting): 비즈니스 관련이지만 차별화 요소는 아님 일반(Generic): 비즈니스 특화되지 않은 일반적 기능 경계 설정: 각 하위 도메인은 명확한 경계(Bounded Context)를 가진다. ...

November 13, 2024 · 2 min · Me

Externalized configuration

Externalized Configuration Externalized Configuration 패턴은 마이크로서비스 아키텍처(MSA)에서 디자인 패턴 중 하나이다. 이 패턴은 애플리케이션의 구성 정보를 코드와 분리하여 외부에서 관리하는 방식을 말한다. 이 패턴은 애플리케이션의 구성 정보를 외부 저장소에 보관하고, 런타임에 이를 읽어오는 방식으로 동작한다. 구성 정보는 데이터베이스, 파일 시스템, 환경 변수 등 다양한 외부 저장소에 보관될 수 있다. 이를 통해 각 환경(개발, 테스트, 운영 등)에 따라 다른 설정을 적용할 수 있으며, 설정 변경 시 애플리케이션을 재배포하지 않아도 된다. Externalized Configuration 패턴은 마이크로서비스 아키텍처에서 구성 관리의 복잡성을 줄이고, 시스템의 유연성과 확장성을 높이는 데 크게 기여한다. 이 패턴을 효과적으로 사용하면 다양한 환경에서 애플리케이션을 쉽게 배포하고 관리할 수 있다. ...

November 12, 2024 · 2 min · Me

Database per Service Pattern

Database per Service Pattern “Database per Service Pattern"은 마이크로서비스 아키텍처에서 중요한 디자인 패턴 중 하나이다. Database per Service Pattern은 각 마이크로서비스가 자체적인 독립된 데이터베이스를 가지는 구조를 말한다. 이는 서비스 간의 느슨한 결합을 촉진하고, 각 서비스의 자율성을 높이는 것을 목표로 한다. 주요 특징: 각 서비스는 자신만의 전용 데이터베이스를 가짐 서비스 간 데이터 접근은 API를 통해서만 가능 각 서비스는 자신의 요구사항에 가장 적합한 데이터베이스 기술을 선택할 수 있음 Database per Service Pattern은 마이크로서비스 아키텍처에서 서비스 간 독립성과 확장성을 높인다. 하지만 이를 효과적으로 구현하기 위해서는 신중한 설계와 다양한 기술적 도전을 해결해야 한다. 각 서비스의 특성과 전체 시스템의 요구사항을 고려하여 이 패턴의 적용 여부를 결정해야 하며, 필요에 따라 다른 패턴들과 조합하여 사용하는 것이 좋다. ...

November 12, 2024 · 2 min · Me

Shared Database

Shared Database 마이크로서비스 아키텍처(MSA)에서 “Shared Database” 패턴은 여러 마이크로서비스가 단일 데이터베이스를 공유하는 접근 방식이다. Shared Database 패턴은 여러 마이크로서비스가 동일한 데이터베이스 인스턴스를 사용하여 데이터를 저장하고 접근하는 방식이다. 각 서비스는 자유롭게 다른 서비스가 소유한 데이터에 접근할 수 있으며, 로컬 ACID 트랜잭션을 사용하여 데이터 일관성을 유지한다. Shared Database 패턴은 마이크로서비스 아키텍처의 일반적인 원칙과는 다소 배치되지만, 특정 상황에서는 유용할 수 있다. 그러나 장기적으로는 서비스 간 결합도를 낮추고 확장성을 높이기 위해 Database per Service 패턴으로의 전환을 고려해야 할 수 있다. ...

November 12, 2024 · 2 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