다음을 통해 공유


마이크로 서비스 간의 이벤트 기반 통신 구현(통합 이벤트)

팁 (조언)

이 콘텐츠는 .NET Docs 또는 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공되는 컨테이너화된 .NET 애플리케이션용 .NET 마이크로 서비스 아키텍처인 eBook에서 발췌한 내용입니다.

컨테이너화된 .NET 애플리케이션을 위한 .NET 마이크로서비스 아키텍처 eBook의 표지 썸네일.

앞에서 설명한 대로 이벤트 기반 통신을 사용하는 경우 마이크로 서비스는 비즈니스 엔터티를 업데이트하는 경우와 같이 주목할 만한 일이 발생할 때 이벤트를 게시합니다. 다른 마이크로 서비스는 해당 이벤트를 구독합니다. 마이크로 서비스가 이벤트를 수신하면 자체 비즈니스 엔터티를 업데이트할 수 있으며, 이로 인해 더 많은 이벤트가 게시될 수 있습니다. 이것이 최종 일관성 개념의 본질입니다. 이 게시/구독 시스템은 일반적으로 이벤트 버스의 구현을 사용하여 수행됩니다. 이벤트 버스는 이벤트를 구독 및 구독 취소하고 이벤트를 게시하는 데 필요한 API를 사용하여 인터페이스로 설계할 수 있습니다. 또한 비동기 통신 및 게시/구독 모델을 지원하는 메시징 큐 또는 서비스 버스와 같은 모든 프로세스 간 또는 메시징 통신을 기반으로 하나 이상의 구현을 가질 수 있습니다.

이벤트를 사용하여 여러 서비스에 걸쳐 있는 비즈니스 트랜잭션을 구현하여 해당 서비스 간에 최종 일관성을 제공할 수 있습니다. 결과적으로 일관된 트랜잭션은 일련의 분산 작업으로 구성됩니다. 각 작업에서 마이크로 서비스는 비즈니스 엔터티를 업데이트하고 다음 작업을 트리거하는 이벤트를 게시합니다. 트랜잭션은 기본 지속성과 이벤트 버스를 포함하지 않으므로 idem-potence를 처리해야 합니다. 아래 그림 6-18에서는 이벤트 버스를 통해 게시된 PriceUpdated 이벤트를 보여 주므로 가격 업데이트가 장바구니 및 기타 마이크로 서비스로 전파됩니다.

이벤트 버스와의 비동기 이벤트 기반 통신 다이어그램.

그림 6-18. 이벤트 버스 기반 이벤트 기반 통신

이 섹션에서는 그림 6-18과 같이 제네릭 이벤트 버스 인터페이스를 사용하여 .NET과 이러한 유형의 통신을 구현하는 방법을 설명합니다. RabbitMQ, Azure Service Bus 또는 다른 타사 오픈 소스 또는 상업용 서비스 버스와 같은 다른 기술 또는 인프라를 사용하는 여러 잠재적 구현이 있습니다.

프로덕션 시스템에 메시지 브로커 및 서비스 버스 사용

아키텍처 섹션에서 설명한 것처럼 추상 이벤트 버스를 구현하기 위한 여러 메시징 기술 중에서 선택할 수 있습니다. 그러나 이러한 기술은 서로 다른 수준에 있습니다. 예를 들어 메시징 브로커 전송인 RabbitMQ는 Azure Service Bus, NServiceBus, MassTransit 또는 Brighter와 같은 상용 제품보다 낮은 수준입니다. 대부분의 제품은 RabbitMQ 또는 Azure Service Bus에서 작동할 수 있습니다. 제품 선택은 애플리케이션에 필요한 기능 수와 기본 제공 확장성에 따라 달라집니다.

eShopOnContainers 샘플에서처럼 개발 환경에 대한 이벤트 버스 개념 증명만 구현하는 경우 컨테이너로 실행되는 RabbitMQ 를 기반으로 하는 간단한 구현으로 충분할 수 있습니다. 하지만 높은 확장성이 필요한 중요 업무용 및 프로덕션 시스템의 경우 Azure Service Bus를 평가하고 사용할 수 있습니다.

분산 개발을 더 쉽게 만드는 장기 실행 프로세스에 대해 사가와 같은 고급 추상화 및 풍부한 기능이 필요한 경우 NServiceBus, MassTransitBrighter 와 같은 다른 상용 및 오픈 소스 서비스 버스는 평가할 가치가 있습니다. 이 경우 사용할 추상화 및 API는 일반적으로 사용자 고유의 추상화( 예: eShopOnContainers에서 제공되는 간단한 이벤트 버스 추상화)가 아닌 상위 수준 서비스 버스에서 제공하는 추상화와 API입니다. 이 문제에 대해 NServiceBus(특정 소프트웨어에서 구현한 추가 파생 샘플)를 사용하여 포크된 eShopOnContainers 를 연구할 수 있습니다.

물론 RabbitMQ 및 Docker와 같은 하위 수준의 기술을 기반으로 항상 고유한 서비스 버스 기능을 빌드할 수 있지만 사용자 지정 엔터프라이즈 애플리케이션에 대해 "휠을 재창조"하는 데 필요한 작업은 비용이 너무 많이 들 수 있습니다.

다시 말해 eShopOnContainers 샘플에 표시된 샘플 이벤트 버스 추상화 및 구현은 개념 증명으로만 사용됩니다. 현재 섹션에서 설명한 대로 비동기 및 이벤트 기반 통신을 하기로 결정한 후에는 프로덕션 요구 사항에 가장 적합한 Service Bus 제품을 선택해야 합니다.

통합 이벤트

통합 이벤트는 여러 마이크로 서비스 또는 외부 시스템에서 도메인 상태를 동기화하는 데 사용됩니다. 이 기능은 마이크로 서비스 외부에 통합 이벤트를 게시하여 수행됩니다. 이벤트가 여러 수신기 마이크로 서비스에 게시되면(통합 이벤트를 구독하는 만큼의 마이크로 서비스에) 각 수신기 마이크로 서비스의 적절한 이벤트 처리기가 이벤트를 처리합니다.

통합 이벤트는 기본적으로 다음 예제와 같이 데이터 보유 클래스입니다.

public class ProductPriceChangedIntegrationEvent : IntegrationEvent
{
    public int ProductId { get; private set; }
    public decimal NewPrice { get; private set; }
    public decimal OldPrice { get; private set; }

    public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice,
        decimal oldPrice)
    {
        ProductId = productId;
        NewPrice = newPrice;
        OldPrice = oldPrice;
    }
}

통합 이벤트는 각 마이크로 서비스의 애플리케이션 수준에서 정의될 수 있으므로 ViewModels가 서버 및 클라이언트에서 정의되는 방식과 비슷한 방식으로 다른 마이크로 서비스에서 분리됩니다. 권장되지 않는 것은 여러 마이크로 서비스에서 공통 통합 이벤트 라이브러리를 공유하는 것입니다. 이렇게 하면 이러한 마이크로 서비스를 단일 이벤트 정의 데이터 라이브러리와 결합할 수 있습니다. 여러 마이크로 서비스에서 공통 도메인 모델을 공유하지 않으려는 동일한 이유로 그렇게 하고 싶지 않습니다. 마이크로 서비스는 완전히 자율적이어야 합니다. 자세한 내용은 이벤트에 넣을 데이터의 양에 대한 이 블로그 게시물을 참조하세요. 이 다른 블로그 게시물은 데이터 결핍 메시지가 생성할 수 있는 문제를 설명하므로 너무 멀리 가지 않도록 주의하세요. 이벤트의 디자인은 소비자의 요구에 "옳은" 것을 목표로 해야 합니다.

마이크로 서비스에서 공유해야 하는 라이브러리는 몇 가지 종류에 불과합니다. 하나는 eShopOnContainers에서와 같이 Event Bus 클라이언트 API와 같은 최종 애플리케이션 블록인 라이브러리입니다. 또 다른 라이브러리는 JSON serializer와 같은 NuGet 구성 요소로 공유할 수 있는 도구를 구성합니다.

이벤트 버스

이벤트 버스는 그림 6-19와 같이 구성 요소가 서로를 명시적으로 인식할 필요 없이 마이크로 서비스 간의 게시/구독 스타일 통신을 허용합니다.

기본 게시/구독 패턴을 보여 주는 다이어그램입니다.

그림 6-19. 이벤트 버스를 사용하여 기본 사항 게시/구독

위의 다이어그램은 게시자가 구독자를 알 필요 없이 마이크로 서비스 B 및 C를 구독하는 데 배포하는 Event Bus에 마이크로 서비스 A가 게시되는 것을 보여 줍니다. 이벤트 버스는 관찰자 패턴 및 게시-구독 패턴과 관련이 있습니다.

관찰자 패턴

관찰자 패턴에서 기본 개체(관찰 가능 개체라고 함)는 관련 정보(이벤트)를 사용하여 다른 관심 있는 개체(관찰자라고 함)에게 알깁니다.

게시/구독(Pub/Sub) 패턴

게시/구독 패턴의 목적은 관찰자 패턴과 동일합니다. 특정 이벤트가 발생할 때 다른 서비스에 알리려고 합니다. 그러나 관찰자 패턴과 퍼블리시/구독 패턴 사이에는 중요한 차이점이 있습니다. 관찰자 패턴에서 브로드캐스트는 관찰 가능한 개체에서 관찰자로 직접 수행되므로 서로를 "알"수 있습니다. 그러나 Pub/Sub 패턴을 사용하는 경우 broker 또는 메시지 브로커 또는 이벤트 버스라는 세 번째 구성 요소가 있습니다. 이 구성 요소는 게시자와 구독자 모두에서 알려져 있습니다. 따라서 Pub/Sub 패턴을 사용하는 경우 게시된 이벤트 버스 또는 메시지 브로커 덕분에 게시자와 구독자가 정확하게 분리됩니다.

미들맨 또는 이벤트 버스

게시자와 구독자 간의 익명성을 달성하려면 어떻게 해야 할까요? 쉬운 방법은 중개인이 모든 의사 소통을 처리하도록하는 것입니다. 이벤트 버스는 그러한 중개인 중 하나입니다.

이벤트 버스는 일반적으로 다음 두 부분으로 구성됩니다.

  • 추상화 또는 인터페이스입니다.

  • 하나 또는 그 이상의 구현.

그림 6-19에서는 애플리케이션 관점에서 이벤트 버스가 Pub/Sub 채널에 지나지 않는 방법을 확인할 수 있습니다. 이 비동기 통신을 구현하는 방법은 다를 수 있습니다. 환경 요구 사항(예: 프로덕션 및 개발 환경)에 따라 구현 간에 교환할 수 있도록 여러 구현을 포함할 수 있습니다.

그림 6-20에서는 RabbitMQ, Azure Service Bus 또는 다른 이벤트/메시지 브로커와 같은 인프라 메시징 기술을 기반으로 여러 구현이 포함된 이벤트 버스의 추상화가 표시됩니다.

이벤트 버스 추상화 계층의 추가를 보여 주는 다이어그램

그림 6- 20. 이벤트 버스의 여러 구현

RabbitMQ, Azure Service Bus 등의 여러 기술로 구현할 수 있도록 인터페이스를 통해 이벤트 버스를 정의하는 것이 좋습니다. 그러나 앞에서 설명한 것처럼 추상화에서 지원하는 기본 이벤트 버스 기능이 필요한 경우에만 사용자 고유의 추상화(이벤트 버스 인터페이스)를 사용하는 것이 좋습니다. 더 풍부한 서비스 버스 기능이 필요한 경우 사용자 고유의 추상화 대신 선호하는 상용 서비스 버스에서 제공하는 API 및 추상화를 사용해야 합니다.

이벤트 버스 인터페이스 정의

이벤트 버스 인터페이스에 대한 몇 가지 구현 코드와 탐색을 위해 가능한 구현으로 시작해 보겠습니다. 인터페이스는 다음 인터페이스와 같이 일반적이고 간단해야 합니다.

public interface IEventBus
{
    void Publish(IntegrationEvent @event);

    void Subscribe<T, TH>()
        where T : IntegrationEvent
        where TH : IIntegrationEventHandler<T>;

    void SubscribeDynamic<TH>(string eventName)
        where TH : IDynamicIntegrationEventHandler;

    void UnsubscribeDynamic<TH>(string eventName)
        where TH : IDynamicIntegrationEventHandler;

    void Unsubscribe<T, TH>()
        where TH : IIntegrationEventHandler<T>
        where T : IntegrationEvent;
}

Publish 메서드는 간단합니다. 이벤트 버스는 해당 이벤트를 구독하는 모든 마이크로 서비스 또는 외부 애플리케이션에 전달된 통합 이벤트를 브로드캐스트합니다. 이 메서드는 이벤트를 게시하는 마이크로 서비스에서 사용됩니다.

Subscribe 메서드(인수에 따라 여러 구현이 있을 수 있습니다)는 이벤트를 수신하려는 마이크로 서비스에서 사용됩니다. 이 메서드에는 두 개의 인수가 있습니다. 첫 번째는 (IntegrationEvent)를 구독할 통합 이벤트입니다. 두 번째 인수는 수신기 마이크로 서비스가 해당 통합 이벤트 메시지를 받을 때 실행할 통합 이벤트 처리기(또는 콜백 메서드) IIntegrationEventHandler<T>입니다.

추가 리소스

일부 프로덕션 준비 메시징 솔루션: