다음을 통해 공유


컨테이너화된 마이크로 서비스

이 콘텐츠는 ‘.NET MAUI를 사용하는 엔터프라이즈 애플리케이션 패턴’ eBook에서 발췌한 것으로, .NET Docs에서 제공되거나 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공됩니다.

‘.NET MAUI를 사용하는 엔터프라이즈 애플리케이션 패턴’ 전자책 표지 썸네일

클라이언트 서버 애플리케이션을 개발한 결과, 각 계층에서 특정 기술을 사용하는 계층화된 애플리케이션을 빌드하는 데 중점을 두게 되었습니다. 이러한 애플리케이션은 종종 모놀리식이라고 하며 최대 부하를 위해 미리 크기가 조정된 하드웨어에 패키지됩니다. 이 개발 방법의 주요 단점은 개별 구성 요소를 쉽게 확장할 수 없는 각 계층 내의 구성 요소와 테스트 비용 간 긴밀한 결합입니다. 간단한 업데이트는 계층의 나머지 부분에 예기치 않은 영향을 미칠 수 있으므로 애플리케이션 구성 요소를 변경하려면 전체 계층을 다시 테스트하고 다시 배포해야 합니다.

특히 클라우드 시대에 개별 구성 요소의 크기를 쉽게 조정할 수 없다는 것입니다. 모놀리식 애플리케이션은 도메인별 기능을 포함하며 일반적으로 프런트 엔드, 비즈니스 논리 및 데이터 스토리지와 같은 기능 계층으로 나뉩니다. 아래 이미지는 전체 애플리케이션을 여러 컴퓨터에 복제하여 모놀리식 애플리케이션의 크기를 조정하는 것을 보여줍니다.

모놀리식 애플리케이션 크기 조정 방법.

마이크로 서비스

마이크로 서비스는 최신 클라우드 애플리케이션의 민첩성, 규모 및 안정성 요구 사항에 적합한 접근 방식인 애플리케이션 개발 및 배포에 대한 다른 접근 방식을 제공합니다. 마이크로 서비스 애플리케이션은 애플리케이션의 전반적인 기능을 제공하기 위해 함께 작동하는 독립적인 구성 요소로 분할됩니다. 마이크로 서비스라는 용어는 애플리케이션이 특정 문제를 반영할 수 있을 만큼 작은 서비스로 구성되어야 함을 강조하므로 각 마이크로 서비스는 단일 함수를 구현합니다. 또한 각 마이크로 서비스에는 다른 마이크로 서비스가 통신을 수행하고 데이터를 공유하는 조건으로서 잘 정의된 계약이 있습니다. 마이크로 서비스의 일반적인 예로는 쇼핑 카트, 재고 처리, 구매 하위 시스템 및 결제 처리가 있습니다.

마이크로 서비스는 함께 스케일링되는 거대한 모놀리식 애플리케이션에 비해 독립적으로 확장할 수 있습니다. 즉, 수요를 지원하기 위해 더 많은 처리 능력 또는 네트워크 대역폭이 필요한 특정 기능 영역은 다른 애플리케이션 영역을 불필요하게 확장하지 않고 확장할 수 있습니다. 아래의 이미지에서는 이러한 방법을 보여주고 있는데, 마이크로 서비스가 독립적으로 배포 및 크기 조정되어 컴퓨터 간에 서비스 인스턴스를 만드는 것을 알 수 있습니다.

마이크로 서비스 애플리케이션 크기 조정 방법.

마이크로 서비스 스케일 아웃은 거의 즉각적일 수 있으므로 변화하는 부하에 따라 애플리케이션을 조정할 수 있습니다. 예를 들어 애플리케이션의 웹 연결 기능에서 단일 마이크로 서비스는 들어오는 추가 트래픽을 처리하기 위해 스케일 아웃해야 하는 유일한 마이크로 서비스일 수 있습니다.

애플리케이션 확장성을 위한 클래식 모델은 영구 데이터를 저장할 공유 외부 데이터 저장소가 있는 부하 분산 상태 비저장 계층을 사용하는 것입니다. 상태 저장 마이크로 서비스는 네트워크 액세스의 오버헤드와 서비스 간 작업의 복잡성을 방지하기 위해 자체 영구 데이터를 관리하며, 일반적으로 서비스가 배치된 서버에 그 데이터를 로컬로 저장합니다. 이렇게 하면 데이터를 가장 빠르게 처리할 수 있으며 캐싱 시스템이 필요하지 않습니다. 또한 확장 가능한 상태 저장 마이크로 서비스는 일반적으로 단일 서버가 지원할 수 있는 데이터 크기를 관리하고 처리량을 전송하기 위해 인스턴스 간에 데이터를 분할합니다.

마이크로 서비스는 독립적인 업데이트도 지원합니다. 마이크로 서비스 간의 이러한 느슨한 결합은 빠르고 안정적인 애플리케이션 진화를 제공합니다. 독립적이고 분산된 특성은 단일 마이크로 서비스의 인스턴스 하위 집합만 지정된 시간에 업데이트되는 롤링 업데이트에 도움이 됩니다. 따라서 어떤 문제가 감지되면 모든 인스턴스가 잘못된 코드 또는 구성으로 업데이트되기 전에 버그 업데이트를 롤백할 수 있습니다. 마찬가지로, 마이크로 서비스는 일반적으로 스키마 버전 관리를 사용하므로 어떤 마이크로 서비스 인스턴스와 통신하든 관계없이 업데이트가 적용될 때 클라이언트에서 일관된 버전을 볼 수 있습니다.

따라서 마이크로 서비스 애플리케이션은 모놀리식 애플리케이션에 비해 다음과 같은 많은 이점이 있습니다.

  • 각 마이크로 서비스는 비교적 규모가 작으며 쉽게 관리하고 수정할 수 있습니다.
  • 각 마이크로 서비스는 다른 서비스와 상관없이 배포하고 업데이트할 수 있습니다.
  • 각 마이크로 서비스는 독립적으로 스케일 아웃할 수 있습니다. 예를 들어, 카탈로그 서비스 또는 장바구니 서비스는 오더링 서비스보다 더 스케일 아웃해야 할 수 있습니다. 따라서 결과 인프라는 스케일 아웃할 때 리소스를 더 효율적으로 사용합니다.
  • 각 마이크로 서비스는 모든 문제를 격리합니다. 예를 들어 서비스에 문제가 있다면 해당 서비스에만 영향을 미칩니다. 다른 서비스는 요청을 계속 처리할 수 있습니다.
  • 각 마이크로 서비스는 최신 기술을 활용할 수 있습니다. 마이크로 서비스는 자율적이고 병렬로 실행되므로 모놀리식 애플리케이션에서 사용할 수 있는 이전 프레임워크를 사용하도록 강제하는 대신 최신 기술과 프레임워크를 사용할 수 있습니다.

그러나 마이크로 서비스 기반 솔루션에는 다음과 같은 잠재적인 단점이 있습니다.

  • 각 마이크로 서비스는 데이터 원본에 대한 책임을 포함하여 완전히 자율적인 엔드투엔드 서비스여야 하므로 애플리케이션을 마이크로 서비스로 분할하는 방법을 선택하는 것은 어려울 수 있습니다.
  • 개발자는 애플리케이션에 복잡성과 대기 시간을 추가하는 서비스 간 통신을 구현해야 합니다.
  • 여러 마이크로 서비스 간 원자성 트랜잭션은 일반적으로 가능하지 않습니다. 따라서 비즈니스 요구 사항은 마이크로 서비스 간의 최종 일관성을 수용해야 합니다.
  • 프로덕션 환경에서는 많은 독립 서비스의 손상된 시스템을 배포하고 관리하는 데 있어 운영상의 복잡성이 있습니다.
  • 클라이언트-마이크로 서비스 간 직접 통신으로 인해 마이크로 서비스 계약을 리팩터링하기가 어려울 수 있습니다. 예를 들어 시간이 지남에 따라 시스템이 서비스로 분할되는 방식을 변경해야 할 수 있습니다. 단일 서비스는 둘 이상의 서비스로 분할될 수 있으며 두 개의 서비스가 병합될 수 있습니다. 클라이언트가 마이크로 서비스와 직접 통신하는 경우 이 리팩터링 작업은 클라이언트 앱과의 호환성을 중단할 수 있습니다.

컨테이너화

컨테이너화는 애플리케이션과 버전이 지정된 그 종속성 집합과 배포 매니페스트 파일로 추상화된 환경 구성이 컨테이너 이미지로 함께 패키지되고, 단위로 테스트되며, 호스트 운영 체제에 배포되는 소프트웨어 개발에 대한 접근 방식입니다.

컨테이너는 격리된 리소스 제어 및 이식 가능한 운영 환경에 속하며, 여기서는 다른 컨테이너 또는 호스트의 리소스를 건드리지 않고 애플리케이션을 실행할 수 있습니다. 따라서 컨테이너는 새로 설치된 물리적 컴퓨터 또는 가상 머신처럼 보이고 작동합니다.

아래 그림과 같이 컨테이너와 가상 머신 간에는 많은 유사점이 있습니다.

가상 머신과 컨테이너 비교.

컨테이너는 운영 체제를 실행하며, 파일 시스템을 보유하고, 마치 물리적 컴퓨터 또는 가상 머신인 것처럼 네트워크에서 액세스할 수 있습니다. 하지만 컨테이너에서 사용하는 기술과 개념은 가상 머신과는 상당한 차이가 있습니다. 가상 머신에는 애플리케이션, 필수 라이브러리 및 전체 게스트 운영 체제가 포함됩니다. 컨테이너에는 애플리케이션과 그 종속성이 포함되지만 호스트 운영 체제에서 격리된 프로세스로 실행되는 다른 컨테이너와 운영 체제를 공유합니다(컨테이너당 특수 가상 머신 내에서 실행되는 Hyper-V 컨테이너 제외). 따라서 컨테이너는 리소스를 공유하며 일반적으로 가상 머신보다 적은 리소스가 필요합니다.

컨테이너 지향 개발과 배포 접근 방식의 장점은 일관되지 않은 환경 설정 및 그와 함께 나타나는 문제에서 발생하는 대부분의 이슈를 없애준다는 점입니다. 또한 컨테이너는 필요에 따라 새 컨테이너를 인스턴스화하여 빠른 애플리케이션 확장 기능을 허용합니다.

컨테이너를 만들고 작업할 때의 주요 개념은 다음과 같습니다.

개념 설명
컨테이너 호스트 컨테이너를 호스트하도록 구성된 물리적 컴퓨터 또는 가상 머신. 컨테이너 호스트는 하나 이상의 컨테이너를 실행합니다.
컨테이너 이미지 이미지는 서로 위에 쌓인 계층화된 파일 시스템의 공용 구조체로 구성되며 컨테이너의 기초가 됩니다. 이미지는 상태가 없으며 상이한 환경에 배포될 때에는 변경되지 않습니다.
컨테이너 컨테이너는 이미지의 런타임 인스턴스입니다.
컨테이너 OS 이미지 컨테이너는 이미지에서 배포됩니다. 컨테이너 OS 이미지는 컨테이너를 구성하는 잠재적으로 많은 이미지 계층에서 첫 번째 계층에 해당됩니다. 컨테이너 운영 체제는 변경할 수 없으며 수정할 수 없습니다.
컨테이너 리포지토리 컨테이너 이미지가 생성될 때마다 그 이미지와 종속성이 로컬 리포지토리에 저장됩니다. 이러한 이미지는 컨테이너 호스트에서 여러 번 다시 사용할 수 있습니다. 컨테이너 이미지를 퍼블릭 또는 프라이빗 레지스트리(예: Docker Hub)에 저장하여 여러 다른 컨테이너 호스트에서 사용할 수도 있습니다.

기업은 마이크로 서비스 기반 애플리케이션을 구현할 때 컨테이너를 점점 더 많이 채택하고 있으며 Docker는 대부분의 소프트웨어 플랫폼 및 클라우드 공급업체에서 채택한 표준 컨테이너 구현이 되었습니다.

eShop 참조 애플리케이션은 아래 다이어그램과 같이 Docker를 사용하여 컨테이너화된 백 엔드 마이크로 서비스를 4개 호스팅합니다.

eShop 참조 애플리케이션 백 엔드 마이크로 서비스.

참조 애플리케이션의 백 엔드 서비스 아키텍처는 마이크로 서비스 및 컨테이너를 공동 작업하는 형태로 여러 자율 하위 시스템으로 분해됩니다. 각 마이크로 서비스는 ID 서비스, 카탈로그 서비스, 오더링 서비스 및 장바구니 서비스의 단일 기능 영역을 제공합니다.

각 마이크로 서비스에는 자체 데이터베이스가 있어 다른 마이크로 서비스에서 완전히 분리할 수 있습니다. 필요하다면 애플리케이션 수준 이벤트를 사용하여 서로 다른 마이크로 서비스의 데이터베이스 간에 일관성을 유지합니다. 자세한 내용은 마이크로 서비스 간 통신을 참조하세요.

클라이언트와 마이크로 서비스 간 통신

eShop 다중 플랫폼 앱은 아래와 같이 직접 클라이언트-마이크로 서비스 통신을 사용하여 컨테이너화된 백 엔드 마이크로 서비스와 통신합니다.

클라이언트-마이크로 서비스 간 직접 통신.

다중 플랫폼 앱은 클라이언트-마이크로 서비스 간 직접 통신을 통해 마이크로 서비스별로 다른 TCP 포트를 사용하여 퍼블릭 엔드포인트를 통해 각 마이크로 서비스에 직접 요청합니다. 프로덕션 환경에서 엔드포인트는 마이크로 서비스의 부하 분산 장치로 매핑되어 사용 가능한 여러 인스턴스에 걸쳐 요청을 분산합니다.

API 게이트웨이 통신을 사용하는 것이 좋습니다.

클라이언트-마이크로 서비스 간 직접 통신은 크고 복잡한 마이크로 서비스 기반 애플리케이션을 빌드할 때 단점이 있을 수 있지만 작은 애플리케이션에 매우 적합합니다. 수십 개의 마이크로 서비스가 있는 대규모 마이크로 서비스 기반 애플리케이션을 설계할 때 API 게이트웨이 통신을 사용하는 것이 좋습니다.

마이크로 서비스 간 통신

마이크로 서비스 기반 애플리케이션은 여러 컴퓨터에서 실행할 수 있는 분산 시스템입니다. 각 서비스 인스턴스는 일반적으로 프로세스입니다. 따라서 서비스는 각 서비스의 성격에 따라 HTTP, TCP, AMQP(고급 메시지 큐 프로토콜) 또는 이진 프로토콜과 같은 프로세스 내 통신 프로토콜을 사용하여 상호 작용해야 합니다.

마이크로 서비스 간 통신에 대한 두 가지 일반적인 접근 방식으로는 데이터를 쿼리할 때 HTTP 기반 REST 통신이 있으며, 여러 마이크로 서비스에서 업데이트를 통신할 때 간단한 비동기 메시징도 있습니다.

비동기 메시징 기반 이벤트 기반 통신은 여러 마이크로 서비스에서 변경 내용을 전파할 때 중요합니다. 이 방법을 사용하면 마이크로 서비스는 비즈니스 엔터티를 업데이트할 때와 같이 주목할 만한 일이 발생할 때 이벤트를 게시합니다. 다른 마이크로 서비스는 해당 이벤트를 구독합니다. 마이크로 서비스가 이벤트를 수신하면 자체 비즈니스 엔터티를 업데이트하며 더 많은 이벤트가 게시되도록 할 수 있습니다. 이 게시-구독 기능은 대체로 이벤트 버스에서 수행합니다.

이벤트 버스는 아래에서 보는 것처럼 구성 요소를 서로 명확히 인식할 필요 없이 마이크로 서비스 간의 게시-구독 통신을 허용합니다.

이벤트 버스를 사용한 게시-구독.

애플리케이션 관점에서 볼 때 이벤트 버스는 인터페이스를 통해 노출되는 게시-구독 채널에 불과합니다. 그러나 이벤트 버스가 구현되는 방식은 다를 수 있습니다. 예를 들어 이벤트 버스 구현에서는 RabbitMQ, Azure Service Bus 또는 기타 서비스 버스(예: NServiceBus 및 MassTransit)를 사용할 수 있습니다. 아래 다이어그램은 eShop 참조 애플리케이션에서 이벤트 버스가 사용되는 방법을 보여줍니다.

참조 애플리케이션의 비동기 이벤트 기반 통신.

RabbitMQ를 사용하여 구현된 eShop 이벤트 버스는 일대다 비동기 게시-구독 기능을 제공합니다. 즉, 이벤트를 게시한 후 동일한 이벤트를 수신 대기하는 구독자가 여러 명 있을 수 있습니다. 이러한 관계를 다이어그램으로 나타내면 아래와 같습니다.

일대다 통신

이 일대다 통신 접근 방식은 이벤트를 사용하여 여러 서비스에 걸쳐 있는 비즈니스 트랜잭션을 구현하여 서비스 간의 최종 일관성을 보장합니다. 최종의 일관된 트랜잭션은 일련의 배포된 단계로 구성되어 있습니다. 따라서 사용자 프로필 마이크로 서비스가 UpdateUser 명령을 받으면 데이터베이스에서 사용자의 세부 정보를 업데이트하고 UserUpdated 이벤트를 이벤트 버스에 게시합니다. 장바구니 마이크로 서비스와 오더링 마이크로 서비스가 모두 이 이벤트를 수신하도록 구독했으며 이에 대한 응답으로 해당 데이터베이스에서 구매자 정보를 업데이트합니다.

요약

마이크로 서비스는 애플리케이션 개발 및 배포에 대한 접근 방식을 제공하는데, 이 접근 방식은 최신 클라우드 애플리케이션의 민첩성, 규모 및 안정성 요구 사항에 적합합니다. 마이크로 서비스의 주요 이점 중 하나는 독립적으로 스케일 아웃할 수 있다는 것입니다. 즉, 수요가 증가하지 않는 애플리케이션의 영역을 불필요하게 확장하지 않고 수요를 지원하기 위해 더 많은 처리 능력 또는 네트워크 대역폭이 필요한 특정 기능 영역을 확장할 수 있습니다.

컨테이너는 격리된 리소스 제어 및 이식 가능한 운영 환경에 속하며, 여기서는 다른 컨테이너 또는 호스트의 리소스를 건드리지 않고 애플리케이션을 실행할 수 있습니다. 기업은 마이크로 서비스 기반 애플리케이션을 구현할 때 컨테이너를 점점 더 많이 채택하고 있으며 Docker는 대부분의 소프트웨어 플랫폼 및 클라우드 공급업체에서 채택한 표준 컨테이너 구현이 되었습니다.