Microservices architecture design

2025. 2. 26. 12:27Spring Microservice

마이크로서비스는 탄력적이고, 고도로 확장 가능하며, 독립적으로 배포할 수 있고, 빠르게 발전할 수 있는 애플리케이션을 구축하는 데 인기 있는 아키텍처 스타일입니다. 하지만 성공적인 마이크로서비스 아키텍처를 구축하려면 애플리케이션을 설계하고 개발하는 방식이 달라야 합니다.

마이크로서비스 아키텍처는 작은 독립적인 서비스들의 모음으로 구성됩니다. 각 서비스는 자체적으로 완결성을 가지며, 단일 비즈니스 기능을 경계(bounded context) 내에서 구현해야 합니다. 경계(bounded context)는 비즈니스 내에서 자연스러운 구획을 의미하며, 도메인 모델이 존재하는 명확한 경계를 제공합니다.

마이크로서비스란 무엇인가?

마이크로서비스는 작고 독립적이며 느슨하게 결합된 아키텍처 스타일입니다. 하나의 작은 개발팀이 단일 서비스를 개발하고 유지보수할 수 있습니다.

  • 각 서비스는 독립적인 코드베이스를 가지며, 소규모 개발팀이 관리할 수 있습니다.
  • 서비스는 독립적으로 배포할 수 있습니다. 따라서 한 팀이 기존 서비스를 업데이트할 때 전체 애플리케이션을 다시 빌드하고 배포할 필요가 없습니다.
  • 서비스는 자체적으로 데이터를 저장하거나 외부 상태를 관리합니다. 이는 전통적인 데이터 계층이 별도로 존재하는 방식과는 다릅니다.
  • 서비스 간에는 잘 정의된 API를 통해 통신하며, 각 서비스의 내부 구현 세부 사항은 다른 서비스에서 숨겨집니다.
  • 폴리글랏(polyglot) 프로그래밍을 지원합니다. 즉, 각 서비스는 동일한 기술 스택, 라이브러리 또는 프레임워크를 공유할 필요가 없습니다.

마이크로서비스 아키텍처에서 서비스 외의 주요 구성 요소

마이크로서비스 아키텍처에는 개별 서비스 외에도 몇 가지 중요한 구성 요소가 포함됩니다.

관리/오케스트레이션 (Management/Orchestration)

이 구성 요소는 서비스의 배치를 조정하고, 장애를 감지하며, 노드 간의 서비스 재배치 등의 작업을 수행합니다. 일반적으로 Kubernetes와 같은 기성 기술을 사용하며, 직접 구현하는 경우는 드뭅니다.

API 게이트웨이 (API Gateway)

API 게이트웨이는 클라이언트가 서비스를 호출할 때 거치는 진입점 역할을 합니다. 클라이언트는 개별 서비스를 직접 호출하는 대신 API 게이트웨이를 통해 요청을 보내며, 게이트웨이는 이를 적절한 백엔드 서비스로 전달합니다.

API 게이트웨이의 장점

  • 클라이언트와 서비스를 분리 (Decoupling)
    서비스의 버전 변경이나 리팩토링이 발생해도 클라이언트 애플리케이션을 수정할 필요가 없습니다.
  • 웹 친화적이지 않은 프로토콜 지원
    서비스가 AMQP와 같은 웹과 친화적이지 않은 메시징 프로토콜을 사용할 수 있습니다.
  • 공통 기능 처리
    API 게이트웨이는 인증, 로깅, SSL 종료(SSL Termination), 로드 밸런싱 등의 교차 기능을 수행할 수 있습니다.
  • 기본 제공 정책 지원
    제한(Throttling), 캐싱(Caching), 데이터 변환(Transformation), 유효성 검사(Validation) 등의 기능을 정책 기반으로 쉽게 적용할 수 있습니다.

마이크로서비스의 장점

1. 민첩성 (Agility)

마이크로서비스는 독립적으로 배포할 수 있기 때문에 버그 수정과 기능 출시를 더 쉽게 관리할 수 있습니다.

  • 특정 서비스만 업데이트할 수 있으며, 전체 애플리케이션을 다시 배포할 필요가 없습니다.
  • 문제가 발생하면 개별 서비스 수준에서 롤백이 가능하여 위험을 최소화할 수 있습니다.
  • 전통적인 모놀리식 애플리케이션에서는 한 부분에서 버그가 발생하면 전체 릴리스 프로세스가 차단될 수 있습니다.
  • 새로운 기능이 버그 수정이 완료될 때까지 지연되는 문제를 방지할 수 있습니다.

2. 소규모, 집중된 팀 (Small, Focused Teams)

마이크로서비스는 하나의 기능팀(Feature Team)이 직접 구축, 테스트, 배포할 수 있을 만큼 작아야 합니다.

  • 소규모 팀은 높은 민첩성을 유지할 수 있습니다.
  • 대규모 팀은 커뮤니케이션이 느려지고 관리 부담이 증가하여 생산성이 저하될 가능성이 큽니다.

3. 작은 코드베이스 (Small Code Base)

모놀리식 애플리케이션에서는 시간이 지나면서 코드 종속성이 복잡하게 얽히는 경향이 있습니다.

  • 새로운 기능을 추가하려면 여러 부분의 코드를 수정해야 하는 경우가 많습니다.
  • 마이크로서비스 아키텍처에서는 코드나 데이터 저장소를 공유하지 않음으로써 종속성을 최소화할 수 있습니다.
  • 그 결과, 새로운 기능을 추가하는 것이 더 쉬워집니다.

4. 다양한 기술 스택 사용 가능 (Mix of Technologies)

  • 각 팀은 해당 서비스에 가장 적합한 기술을 자유롭게 선택할 수 있습니다.
  • 필요에 따라 서로 다른 기술 스택을 조합하여 사용할 수 있습니다.

5. 장애 격리 (Fault Isolation)

  • 특정 마이크로서비스가 다운되더라도, 다른 서비스가 정상적으로 작동하면 전체 애플리케이션이 중단되지 않습니다.
  • 상위 서비스(Upstream Services)가 장애를 적절히 처리하도록 설계하면, 장애 영향 범위를 최소화할 수 있습니다.
  • 예를 들어 Circuit Breaker 패턴을 적용하거나, 마이크로서비스 간 비동기 메시징 패턴을 사용하면 장애 발생 시 복원력을 높일 수 있습니다.

6. 확장성 (Scalability)

  • 각 서비스를 독립적으로 확장할 수 있어, 더 많은 리소스가 필요한 부분만 효율적으로 확장할 수 있습니다.
  • Kubernetes와 같은 오케스트레이션 도구를 사용하면 하나의 호스트에서 더 높은 밀도로 서비스를 배치할 수 있습니다.
  • 이를 통해 자원을 더욱 효율적으로 활용할 수 있습니다.

7. 데이터 격리 (Data Isolation)

  • 특정 마이크로서비스만 데이터 스키마를 업데이트하면 되므로, 스키마 변경이 훨씬 쉬워집니다.
  • 반면 모놀리식 애플리케이션에서는 여러 부분이 동일한 데이터에 접근하기 때문에, 스키마 변경이 매우 어렵고 위험할 수 있습니다.

마이크로서비스의 도전 과제

마이크로서비스의 장점은 그냥 얻어지는 것이 아닙니다. 마이크로서비스 아키텍처를 도입하기 전에 고려해야 할 몇 가지 도전 과제가 있습니다.

1. 복잡성 (Complexity)

  • 마이크로서비스 애플리케이션은 모놀리식 애플리케이션보다 더 많은 구성 요소를 포함합니다.
  • 개별 서비스는 단순하지만, 전체 시스템은 더 복잡해질 수 있습니다.

2. 개발 및 테스트 (Development and Testing)

  • 마이크로서비스는 서로 의존하는 여러 서비스가 있기 때문에 전통적인 모놀리식 또는 계층형 애플리케이션과는 다른 개발 방식이 필요합니다.
  • 기존 도구들이 서비스 간의 종속성을 다루도록 설계되지 않은 경우가 많습니다.
  • 서비스 간 경계를 넘어서 리팩토링하는 것이 어려울 수 있습니다.
  • 애플리케이션이 빠르게 변화할 때, 서비스 간의 종속성을 테스트하는 것이 더욱 어려워집니다.

3. 거버넌스 부족 (Lack of Governance)

  • 마이크로서비스는 분산된 방식으로 개발되므로, 관리가 제대로 이루어지지 않으면 다양한 언어와 프레임워크가 난립할 수 있습니다.
  • 결과적으로 유지보수가 어려워질 수 있습니다.
  • 프로젝트 전반에서 최소한의 표준을 수립하는 것이 중요하지만, 팀의 유연성을 과도하게 제한하지 않는 균형이 필요합니다.
  • 특히 로깅과 같은 공통 기능에 대한 표준이 필요합니다.

4. 네트워크 혼잡 및 지연 (Network Congestion and Latency)

  • 서비스가 세분화될수록 서비스 간의 통신량이 증가할 수 있습니다.
  • 서비스 간 호출이 길어질 경우(예: 서비스 A가 B를 호출하고, B가 C를 호출하는 경우), 추가적인 네트워크 지연(latency)이 문제가 될 수 있습니다.
  • 이를 방지하려면 API 설계를 신중하게 해야 하며,
    • 과도하게 빈번한 API 호출(chattiness)을 피하고,
    • 적절한 직렬화(serialization) 포맷을 선택하며,
    • 큐 기반 부하 분산(Queue-Based Load Leveling)과 같은 비동기 통신 패턴을 활용해야 합니다.

5. 데이터 무결성 (Data Integrity)

  • 마이크로서비스는 각자 독립적으로 데이터를 저장하므로, 여러 서비스 간의 데이터 일관성을 유지하는 것이 어려울 수 있습니다.
  • 각 서비스가 서로 다른 시점에, 서로 다른 방식으로 데이터를 저장할 수 있습니다.
  • 여러 서비스가 동일한 데이터를 변경하는 경우, ACID(원자성, 일관성, 격리성, 지속성) 트랜잭션을 보장하기 어렵습니다.
  • 대신 BASE(Basically Available, Soft state, Eventually consistent) 모델을 적용하여, 가능한 경우 최종적 일관성(Eventual Consistency) 을 수용하는 것이 필요합니다.

6. 관리 (Management)

  • 마이크로서비스를 성공적으로 운영하려면 성숙한 DevOps 문화가 필요합니다.
  • 서비스 간의 호출을 추적하고 연관된 로그를 수집하는 것이 어렵습니다.
  • 일반적으로 하나의 사용자 요청이 여러 서비스 호출로 연결되기 때문에, 관련된 로그를 효과적으로 관리해야 합니다.

7. 버전 관리 (Versioning)

  • 특정 서비스를 업데이트할 때, 해당 서비스에 의존하는 다른 서비스가 영향을 받지 않도록 해야 합니다.
  • 여러 서비스가 동시에 업데이트될 수 있기 때문에, 하위 호환성과 상위 호환성을 고려한 설계가 필요합니다.
  • API 버전 관리를 신중하게 수행해야 합니다.

8. 팀의 기술 역량 (Skill Set)

  • 마이크로서비스는 고도로 분산된 시스템이므로, 팀의 기술 역량이 매우 중요합니다.
  • 팀이 분산 시스템, API 설계, DevOps, 네트워크 통신, 데이터 일관성 관리에 대한 충분한 경험과 역량을 갖추고 있는지 신중하게 평가해야 합니다.

마이크로서비스 아키텍처 구축 프로세스

아래의 과정은 마이크로서비스 아키텍처를 설계, 개발, 운영하는 체계적인 접근 방식을 제공합니다.

1. 도메인 분석 (Domain Analysis)

마이크로서비스 설계 시 발생할 수 있는 일반적인 문제를 피하려면, 도메인 분석을 통해 마이크로서비스의 경계를 정의해야 합니다.
다음 단계를 따르세요:

2. 서비스 설계 (Design the Services)

마이크로서비스는 기존 애플리케이션과는 다른 방식으로 설계 및 구축해야 합니다.

3. 운영 및 배포 (Operate in Production)

마이크로서비스 아키텍처는 분산된 환경에서 운영되므로,

  • 배포 및 모니터링을 위한 강력한 운영 체계를 구축하는 것이 필수적입니다.

4. 마이크로서비스를 위한 CI/CD (CI/CD for Microservices Architectures)

  • Kubernetes 환경에서 마이크로서비스를 위한 CI/CD 파이프라인을 구축합니다.
  • 지속적 통합(Continuous Integration) 및 지속적 배포(Continuous Deployment)를 통해 안정적인 운영을 보장합니다.

출처 : https://learn.microsoft.com/en-us/azure/architecture/microservices/