팁 (조언)
이 콘텐츠는 .NET Docs 또는 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공되는 컨테이너화된 .NET 애플리케이션용 .NET 마이크로 서비스 아키텍처인 eBook에서 발췌한 내용입니다.
먼저 컨테이너에서 실행되는 RabbitMQ 를 기반으로 사용자 지정 이벤트 버스를 만드는 경우 eShopOnContainers 애플리케이션과 마찬가지로 개발 및 테스트 환경에만 사용해야 합니다. 아래의 추가 리소스 섹션에 설명된 대로 프로덕션 준비 서비스 버스의 일부로 빌드하지 않는 한 프로덕션 환경에 사용하지 마세요. 간단한 사용자 지정 이벤트 버스에는 상용 서비스 버스에 있는 많은 프로덕션 준비 중요 기능이 누락될 수 있습니다.
eShopOnContainers의 이벤트 버스 사용자 지정 구현 중 하나는 기본적으로 RabbitMQ API를 사용하는 라이브러리입니다. (Azure Service Bus를 기반으로 하는 또 다른 구현이 있습니다.)
RabbitMQ를 사용한 이벤트 버스 구현을 통해 마이크로 서비스는 그림 6-21과 같이 이벤트를 구독하고, 이벤트를 게시하고, 이벤트를 수신할 수 있습니다.
그림 6-21. 이벤트 버스의 RabbitMQ 구현
RabbitMQ는 메시지 게시자와 구독자 간의 중개자로 작동하여 배포를 처리합니다. 코드에서 EventBusRabbitMQ 클래스는 제네릭 IEventBus 인터페이스를 구현합니다. 이 구현은 종속성 주입을 기반으로 하므로 이 개발/테스트 버전에서 프로덕션 버전으로 교환할 수 있습니다.
public class EventBusRabbitMQ : IEventBus, IDisposable
{
// Implementation using RabbitMQ API
//...
}
샘플 개발/테스트 이벤트 버스의 RabbitMQ 구현은 상용구 코드입니다. RabbitMQ 서버에 대한 연결을 처리하고 큐에 메시지 이벤트를 게시하기 위한 코드를 제공해야 합니다. 또한 각 이벤트 유형에 대한 통합 이벤트 처리기 컬렉션의 사전을 구현해야 합니다. 그림 6-21에 표시된 것처럼 이러한 이벤트 유형은 각 수신기 마이크로 서비스에 대해 다른 인스턴스화 및 서로 다른 구독을 가질 수 있습니다.
RabbitMQ를 사용하여 간단한 게시 메서드 구현
다음 코드는 전체 시나리오를 소개하기 위해 RabbitMQ에 대한 이벤트 버스 구현의 간소화된 버전입니다. 이러한 방식으로 연결을 실제로 처리하지는 않습니다. 전체 구현을 보려면 dotnet-architecture/eShopOnContainers 리포지토리의 실제 코드를 참조하세요.
public class EventBusRabbitMQ : IEventBus, IDisposable
{
// Member objects and other methods ...
// ...
public void Publish(IntegrationEvent @event)
{
var eventName = @event.GetType().Name;
var factory = new ConnectionFactory() { HostName = _connectionString };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: _brokerName,
type: "direct");
string message = JsonConvert.SerializeObject(@event);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: _brokerName,
routingKey: eventName,
basicProperties: null,
body: body);
}
}
}
RabbitMQ 컨테이너가 준비되지 않은 경우 작업을 몇 번 다시 시도하는 Polly 재시도 정책을 사용하여 eShopOnContainers 애플리케이션의 Publish 메서드의 실제 코드가 향상됩니다. 이 시나리오는 docker-compose가 컨테이너를 시작할 때 발생할 수 있습니다. 예를 들어 RabbitMQ 컨테이너는 다른 컨테이너보다 더 느리게 시작될 수 있습니다.
앞에서 설명한 것처럼 RabbitMQ에는 가능한 많은 구성이 있으므로 이 코드는 개발/테스트 환경에만 사용해야 합니다.
RabbitMQ API를 사용하여 구독 코드 구현
게시 코드와 마찬가지로 다음 코드는 RabbitMQ에 대한 이벤트 버스 구현의 일부를 단순화한 것입니다. 다시 말하지만, 일반적으로 개선하지 않는 한 변경할 필요가 없습니다.
public class EventBusRabbitMQ : IEventBus, IDisposable
{
// Member objects and other methods ...
// ...
public void Subscribe<T, TH>()
where T : IntegrationEvent
where TH : IIntegrationEventHandler<T>
{
var eventName = _subsManager.GetEventKey<T>();
var containsKey = _subsManager.HasSubscriptionsForEvent(eventName);
if (!containsKey)
{
if (!_persistentConnection.IsConnected)
{
_persistentConnection.TryConnect();
}
using (var channel = _persistentConnection.CreateModel())
{
channel.QueueBind(queue: _queueName,
exchange: BROKER_NAME,
routingKey: eventName);
}
}
_subsManager.AddSubscription<T, TH>();
}
}
각 이벤트 유형에는 RabbitMQ에서 이벤트를 가져오는 관련 채널이 있습니다. 그런 다음 채널 및 이벤트 유형당 필요한 만큼 이벤트 처리기를 가질 수 있습니다.
Subscribe 메서드는 현재 마이크로 서비스의 콜백 메서드와 같은 IIntegrationEventHandler 개체와 관련된 IntegrationEvent 개체를 허용합니다. 그런 다음, 각 통합 이벤트 유형이 클라이언트 마이크로 서비스당 가질 수 있는 이벤트 처리기 목록에 해당 이벤트 처리기를 추가합니다. 클라이언트 코드가 아직 이벤트를 구독하지 않은 경우 코드는 이벤트 유형에 대한 채널을 만들어 해당 이벤트가 다른 서비스에서 게시될 때 RabbitMQ에서 푸시 스타일로 이벤트를 수신할 수 있도록 합니다.
위에서 설명한 것처럼 eShopOnContainers에서 구현된 이벤트 버스는 주요 시나리오만 처리하므로 프로덕션에 사용할 준비가 되지 않았기 때문에 교육 목적만 있습니다.
프로덕션 시나리오의 경우 RabbitMQ에 특정한 아래의 추가 리소스와 마이크로 서비스 간 이벤트 기반 통신 구현 섹션을 확인합니다 .
추가 리소스
RabbitMQ를 지원하는 프로덕션 지원 솔루션입니다.
Peregrine Connect - 앱, API 및 워크플로의 효율적인 디자인, 배포 및 관리로 통합 간소화
https://www.peregrineconnect.com/why-peregrine/rabbitmq-integrationNServiceBus - .NET용 고급 관리 및 모니터링 도구를 사용하는 완전히 지원되는 상용 서비스 버스
https://particular.net/EasyNetQ - RabbitMQ 용 오픈 소스 .NET API 클라이언트
https://easynetq.com/MassTransit - .NET용 무료 오픈 소스 분산 애플리케이션 프레임워크
https://masstransit-project.com/Rebus - 오픈 소스 .NET Service Bus
https://github.com/rebus-org/Rebus
.NET