[Spring] MSA와 Spring Cloud
본문 바로가기

Development/Spring

[Spring] MSA와 Spring Cloud

현대의 소프트웨어 개발은 급변하는 요구사항과 복잡한 시스템 구조로 인해 기존의 모놀리식 아키텍처로는 대응하기 어려운 상황에 직면해 있습니다. 이러한 문제를 해결하기 위해 등장한 개념이 바로 마이크로서비스 아키텍처(MSA, Microservices Architecture)입니다.

MSA는 애플리케이션을 작은 독립적인 서비스로 분리하여 개발, 배포, 확장이 용이하게 합니다. 이를 통해 개발팀은 민첩성을 높이고, 시스템의 안정성과 유연성을 확보할 수 있습니다.

 

하지만 MSA의 도입은 단순히 아키텍처를 나누는 것만으로는 충분하지 않습니다. 각 마이크로서비스 간의 통신, 구성 관리, 서비스 디스커버리 등 다양한 운영 문제를 효율적으로 해결하기 위한 툴과 프레임워크가 필요합니다.

Spring에서 Spring Cloud는 MSA의 구현을 위한 다양한 도구와 서비스를 제공하여, 개발자들이 복잡한 분산 시스템을 보다 쉽게 구축하고 관리할 수 있도록 도와줍니다.

 

이 글에서는 MSA가 왜 필요하게 되었는지, 그리고 Spring Cloud가 MSA를 구현하는 데 있어 어떤 역할을 하는지에 대해 살펴보겠습니다.

MSA

과거의 모놀리틱 아키텍처

 

모놀리틱 아키텍처는 소프트웨어 개발 초기부터 널리 사용되어 온 아키텍처 패턴으로, 하나의 큰 코드베이스로 구성된 애플리케이션을 의미한다. 이 아키텍처는 모든 기능이 하나의 애플리케이션 내에 포함되며, 단일 실행 파일로 컴파일되고 배포된다.


모놀리틱 아키텍처의 장단점은 다음과 같다:

 

장점

  • 간단한 배포: 모든 코드가 하나의 코드베이스에 포함되어 있어 배포가 단순하다. 한 번의 빌드와 배포로 전체 애플리케이션을 배포할 수 있다.
  • 데이터의 일관성: 하나의 데이터베이스를 사용하여 데이터 일관성을 쉽게 유지할 수 있다. 모든 데이터가 한 곳에 모여 있어 데이터 관리가 용이하다.

단점

  • 확장성 부족: 특정 기능을 확장하려면 전체 애플리케이션을 확장해야 한다. 예를 들어, 트래픽이 특정 기능에 집중될 때 해당 기능만 확장할 수 없고, 전체 애플리케이션을 확장해야 하므로 비효율적이다.
  • 긴 개발 주기: 작은 변경 사항도 전체 애플리케이션을 다시 배포해야 한다. 이는 개발과 배포 주기를 길게 만들어 빠른 피드백과 대응이 어렵게 한다.
  • 유연성 부족: 새로운 기술 도입이 어렵고, 특정 모듈에 종속적이다. 모놀리틱 구조에서는 새로운 프레임워크나 언어를 도입하려면 전체 애플리케이션을 재작성해야 할 수도 있다.
  • 높은 리스크: 많은 트래픽이 발생하거나 배포 시 문제가 생기면 서비스 전체가 영향을 받아 운용이 불가능해질 수 있다. 하나의 작은 버그가 전체 시스템의 다운타임을 초래할 수 있다.
  • 복잡성 증가: 애플리케이션이 커지면 코드베이스가 복잡해지고, 관리가 어려워진다. 개발자들은 코드의 특정 부분을 이해하고 수정하기 위해 전체 코드베이스를 파악해야 할 수 있다.
  • 지속적인 통합 문제: 다양한 팀이 동시에 작업할 경우, 각 팀의 변경 사항을 통합하고 테스트하는 과정에서 충돌과 문제가 발생할 수 있다.

모놀리틱 아키텍처는 초기 개발과 작은 규모의 애플리케이션에는 적합할 수 있지만, 애플리케이션이 커지고 복잡해짐에 따라 여러 가지 한계와 문제점이 드러난다. 이러한 문제를 해결하기 위해 등장한 개념이 바로 마이크로서비스 아키텍처(MSA)이다. MSA는 애플리케이션을 작은 독립적인 서비스로 나누어 개발, 배포, 확장을 용이하게 함으로써 모놀리틱 아키텍처의 한계를 극복한다.

Microservices Architecture (MSA)

마이크로서비스 아키텍처(MSA)는 하나의 애플리케이션을 여러 개의 독립적인 서비스로 분리하여 개발, 배포, 유지보수를 용이하게 하는 소프트웨어 아키텍처 스타일이다. 각 서비스는 특정 비즈니스 기능을 수행하며, 서로 독립적으로 배포되고 확장될 수 있다.

서비스 간의 통신은 주로 HTTP/HTTPS, 메시지 큐 등을 통해 이루어진다.

 

주요 특징

  1. 독립적인 배포 가능성: 각 서비스는 독립적으로 배포할 수 있으며, 다른 서비스에 영향을 주지 않고 업데이트할 수 있다.
  2. 작은 팀 구성: 각 서비스는 작은 팀이 독립적으로 개발하고 관리할 수 있다.
  3. 기술 스택의 다양성: 각 서비스는 적절한 기술 스택을 자유롭게 선택할 수 있다.

MSA의 장단점은 다음과 같다:

 

장점

  1. 확장성: 특정 서비스만 확장하여 성능을 최적화할 수 있다. 이는 리소스를 효율적으로 사용하고, 필요에 따라 특정 기능의 성능을 높일 수 있게 한다.
  2. 독립적 배포: 개별 서비스의 변경 사항을 독립적으로 배포할 수 있다. 이를 통해 배포 주기를 단축하고, 빠르게 변경 사항을 반영할 수 있다.
  3. 유연성: 서비스별로 적합한 기술 스택을 선택할 수 있다. 이는 각 서비스가 최적의 성능을 발휘할 수 있도록 다양한 기술을 도입할 수 있게 한다.
  4. 작은 팀 구성: 서비스별로 작은 팀이 독립적으로 개발하고 운영할 수 있어, 민첩한 개발과 신속한 문제 해결이 가능하다.

단점

  1. 복잡성 증가: 서비스 간 통신, 데이터 일관성 유지 등의 복잡성이 증가한다. 이는 설계의 복잡성을 높이고, 전체 시스템의 관리와 유지보수를 어렵게 만들 수 있다.
  2. 운영비용 증가: 각 서비스의 모니터링, 로깅 등을 개별적으로 관리해야 하므로 운영 비용이 증가한다. 서비스의 개별 관리가 필요하기 때문에 운영 인프라가 복잡해질 수 있다.
  3. 데이터 관리: 분산된 데이터베이스로 인해 데이터 일관성 유지가 어려울 수 있다. 각 서비스가 독립적인 데이터베이스를 사용하기 때문에, 데이터의 일관성을 유지하는 것이 과제이다.
  4. 네트워크 지연: 서비스 간의 통신이 네트워크를 통해 이루어지므로 지연 시간이 발생할 수 있다. 이는 성능 저하를 초래할 수 있으며, 특히 트랜잭션이 여러 서비스에 걸쳐 있는 경우 문제가 될 수 있다.

초기에 신규 서비스를 개발할 때는 모놀리틱 아키텍처로 시작하는 것이 좋다. 이는 빠른 프로토타이핑과 초기 개발을 용이하게 한다.

서비스가 충분히 검증되고 안정화된 후, 점진적으로 MSA로 전환하는 전략이 바람직하다.

Spring Cloud

Spring Cloud란?

Spring Cloud는 마이크로서비스 개발을 위해 다양한 도구와 서비스를 제공하는 스프링 프레임워크의 Extension 이다. 이를 통해 마이크로서비스 아키텍처를 쉽게 구현하고 운영할 수 있도록 돕는다. Spring Cloud는 마이크로서비스 아키텍처의 복잡성을 줄이고, 개발자가 분산 시스템을 효율적으로 관리할 수 있게 하는 다양한 솔루션을 제공한다.

주요 기능

  1. 서비스 등록 및 디스커버리
    • Eureka: 넷플릭스가 개발한 서비스 디스커버리 서버로, 마이크로서비스 아키텍처에서 각 서비스의 위치를 동적으로 관리한다.
      • 주요 특징:
        • 서비스 레지스트리: 모든 서비스 인스턴스의 위치를 저장하는 중앙 저장소이다.
        • 헬스 체크(Health check): 서비스 인스턴스의 상태를 주기적으로 확인하여 가용성을 보장한다.
    • ConsulZookeeper: 유사한 기능을 제공하는 서비스 디스커버리 도구이다.
  2. 로드 밸런싱
    • Ribbon: 넷플릭스가 개발한 클라이언트 사이드 로드 밸런서로, 서비스 인스턴스 간의 부하를 분산시킨다.
      • 주요 특징:
        • 서버 리스트 제공자: Eureka로부터 서비스 인스턴스 리스트를 제공받아 로드 밸런싱에 사용한다.
        • 로드밸런싱 알고리즘: 라운드 로빈, 가중치 기반 등 다양한 로드 밸런싱 알고리즘을 지원한다.
        • Failover: 요청 실패 시 다른 인스턴스로 자동 전환된다.
    • Spring Cloud LoadBalancer: Spring Cloud의 새로운 로드 밸런싱 솔루션이다.
  3. 서킷 브레이커
    • Hystrix: 넷플릭스가 개발한 서킷 브레이커 라이브러리로, 서비스 간의 호출 실패를 감지하고 시스템의 전체적인 안정성을 유지한다.
      • 주요 특징:
        • 서킷 브레이커 상태: closed, open, half-open 상태를 통해 호출 실패를 관리한다.
        • Failback: 호출 실패 시 대체 로직을 제공하여 시스템 안정성을 확보한다.
        • 모니터링: Hystrix Dashboard를 통해 서킷 브레이커 상태를 모니터링한다.
    • Resilience4j: 자바 기반의 경량 서킷 브레이커 라이브러리로, 넷플릭스 Hystrix의 대안으로 개발되었다.
      • 주요 특징:
        • 서킷 브레이커: 호출 실패를 감지하고 서킷을 열어 추가적인 호출을 차단하여 시스템의 부하를 줄인다.
        • Failback: 호출 실패 시 대체 로직을 실행하여 시스템의 안정성을 유지한다.
        • 타임아웃 설정: 호출의 응답 시간을 설정하여 느린 서비스 호출에 대응할 수 있다.
        • 재시도: 재시도 기능을 지원하여 일시적인 네트워크 문제 등에 대응할 수 있다.
  4. API 게이트웨이
    • Zuul: 넷플릭스가 개발한 API 게이트웨이로, 모든 서비스 요청을 중앙에서 관리한다.
      • 주요 특징:
        • 라우팅: 요청 URL에 따라 적절한 서비스로 요청을 전달한다.
        • 필터: 요청 전후에 다양한 작업을 수행할 수 있는 필터 체인을 제공한다.
        • 모니터링: 요청 로그 및 메트릭을 통해 서비스 상태를 모니터링할 수 있다.
    • Spring Cloud Gateway: 스프링 클라우드에서 제공하는 API 게이트웨이로, 마이크로서비스 아키텍처에서 필수적인 역할을 한다.
      • 주요 특징:
        • 루팅 및 필터링: 요청을 받아 특정 서비스로 라우팅하고 필요한 인증 및 권한 부여를 수행한다.
        • 보안: 외부 요청으로부터 애플리케이션을 보호하고, 보안 정책을 적용한다.
        • 효율성: 마이크로서비스 아키텍처에서 필요한 요청 처리 및 분산 환경의 관리를 효율적으로 수행한다.
  5. 구성 관리
    • Spring Cloud Config: 분산된 환경에서 중앙 집중식 설정 관리를 제공한다.
      • 주요 특징:
        • Config 서버: 중앙에서 설정 파일을 관리하고 각 서비스에 제공한다.
        • Config 클라이언트: Config 서버에서 설정을 받아서 사용하는 서비스이다.
        • 설정갱신: 설정 변경 시 서비스 재시작 없이 실시간으로 반영한다.
  6. 분산 추적
    • Spring Cloud Sleuth: 분산 추적을 위한 라이브러리로, 각 서비스 간의 호출 관계를 추적할 수 있게 한다.
    • Zipkin: 분산 추적 시스템으로, Sleuth와 함께 사용되어 트랜잭션의 흐름을 시각화한다.
  7. 메시징
    • Spring Cloud Stream: 메시징 미들웨어와의 통합을 지원하여, 이벤트 기반의 마이크로서비스를 쉽게 개발할 수 있게 한다.

소프트웨어는 지속적으로 업데이트되지만, Spring Cloud의 다양한 도구와 라이브러리는 버전 호환성을 고려하여 신중하게 업그레이드해야 한다. 각 모듈은 독립적으로 업데이트될 수 있지만, 전체 시스템의 안정성을 위해 각 모듈 간의 호환성을 유지하는 것이 중요하다.

Spring Cloud의 적용 사례

Netflix

Netflix의 MSA. 녹색 부분이 애플리케이션

  • 배경
    • 넷플릭스는 2000년대 후반 데이터 베이스 장애를 통해 심각한 서비스 장애를 겪게 된다.
    • 사용자가 급격히 증가 함에 따라 기존 모놀리틱 아키텍처로는 빠르게 증가하는 트래픽과 사용자 요구를 감당하기 어려워졌다.
    • 또한 신뢰성 높고 수평 확장이 가능한 클라우드 시스템으로 이전할 필요성을 느꼈다.
    • 폭발적인 사용자 증가, 빈번한 서비스 장애, 인프라 확장의 어려움, 빠른 기능 배포의 필요성, 클라우드 전환 등의 계기로 인해 MSA 전환이 시작되었다.
  • MSA로의 전환 이유
    • 확장성(Scalability): 넷플릭스는 글로벌 서비스를 제공하며, 수백만 명의 사용자가 동시 접속할 수 있는 인프라가 필요했다.
    • 신뢰성(Reliability): 한 부분의 장애가 전체 시스템에 영향을 미치지 않도록 해야 했다.
    • 개발 속도(Speed of Development): 새로운 기능을 빠르게 배포하고, 독립적인 팀이 동시에 작업할 수 있는 환경이 필요했다.
  • 전환 과정
    • 서비스 분리: 넷플릭스는 기존 모놀리식 애플리케이션을 여러 개의 독립적인 마이크로서비스로 분리했다.
    • 자동화 도구 도입: CI/CD 파이프라인을 구축하여 코드의 빌드, 테스트, 배포 과정을 자동화했습니다. 이를 통해 개발 속도를 크게 향상시켰다.
    • 자체 도구 개발: 넷플릭스는 Hystrix, Eureka, Ribbon 등의 도구를 개발하여 서비스 간 통신, 장애 복구, 로드 밸런싱 등을 효율적으로 처리했다.
    • 클라우드 인프라 활용: AWS와 같은 클라우드 인프라를 활용하여 서비스 확장성을 높였다.
  • 결과
    • 향상된 확장성: 넷플릭스는 MSA 전환 이후 수천 개의 마이크로서비스를 운영하며, 글로벌 사용자 증가에 유연하게 대응할 수 있었다.
    • 높은 가용성: 서비스 장애 시 다른 서비스에 영향을 미치지 않고 독립적으로 복구할 수 있어, 사용자에게 지속적인 서비스를 제공할 수 있었다.
    • 빠른 배포 주기: 새로운 기능을 신속하게 개발하고 배포할 수 있어, 사용자 요구에 빠르게 대응할 수 있었다.

프로젝트에서 MSA를 적용하는 과정 

예를 들어, 주문 처리 시스템이 있다. 이 시스템에서는 주문 확인, 상품 확인, 유저 확인 등 여러 과정이 필요하다.

이를 위해 Order application, Product application, User application과 같은 개별 서비스를 구성할 수 있다.

서비스 간 통신

주문 처리를 예로 들면, Order 서비스는 Product 서비스와 User 서비스와 통신해야 한다. 이러한 통신은 HTTP/HTTPS를 통해 이루어지며, 요청이 증가할 경우 단일 애플리케이션으로는 감당할 수 없게 되므로 여러 인스턴스로 나누어 운영하게 된다.

로드 밸런싱

여러 인스턴스 중 어느 인스턴스에 요청을 보낼 것인지는 Ribbon과 같은 로드 밸런서가 담당한다. Ribbon은 FeignClient와 함께 사용되어, 클라이언트 사이드에서 요청을 적절하게 분배한다.

서비스 등록 및 디스커버리

다른 서비스의 호스트 정보를 관리하기 위해 Eureka Server를 사용한다. Eureka Server는 중앙에서 모든 호스트와 연결되어 요청을 중재하며, 각 애플리케이션은 Eureka Client가 되어 Eureka Server와 통신한다. 이를 통해 서비스 간 동적 디스커버리가 가능해진다.

API 게이트웨이

클라이언트의 요청은 API Gateway를 통해 처리된다. API Gateway는 필터 기능을 수행하여, 예를 들어 사용자가 로그인을 했는지 확인할 수 있다. 또한, API Gateway는 각 서비스로의 요청을 라우팅하는 역할을 한다.

서킷 브레이커

서비스 호출 중 한 곳에서 에러가 발생하면 다른 곳을 호출할 필요가 없다. 이를 처리하는 것이 서킷 브레이커이다. HystrixResilience4j와 같은 서킷 브레이커 라이브러리는 FailOver를 처리하며, 요청 실패 시 대체 로직을 제공하여 시스템 안정성을 유지한다.

구성 관리

각 애플리케이션마다 설정 파일이 필요하다. 이를 중앙에서 통합 관리하기 위해 Spring Cloud Config Server를 사용할 수 있다. Config Server에 YML 파일을 저장하여 각 애플리케이션이 필요할 때 설정을 가져가도록 한다. 이를 통해 설정 변경 시 서비스 재시작 없이 실시간으로 반영할 수 있다.

분산 추적

상품 주문 요청이 들어오는 경우, Order 서비스는 Product 서비스와 User 서비스를 호출하게 된다. 내부적으로 어떤 함수가 호출되며, 어떤 순서로 호출되는지를 파악하기 위해 분산 추적이 필요하다. ZipkinSpring Cloud Sleuth를 사용하여 각 서비스 간의 호출 관계를 추적하고, 트랜잭션의 흐름을 시각화할 수 있다.

마치며

  • MSA를 구성하기 위해 많은 요소들이 필요하다.
  • 초기에 설계가 복잡할 수 있어도, 장기적으로 보았을 때 기존 모놀리틱 아키텍처보다 더 많은 이점을 가질 수 있다고 생각했다.

참조

  • 팀스파르타코딩클럽 MSA 강의 자료