消息代理 - .NET Core 中的多供应商架构
Message Broker - Multivendor Architecture in .NET Core
我目前正在按照 .Net Core 中的 "competing consumer pattern" 构建一个系统。因此,我将 JobRequest-Message 放在一个队列上,多个消费者(工作者)订阅了该队列。其中一位消费者收到消息并实际处理作业。
我也有搭建系统的需求"vendor independent"。这意味着我需要以某种方式实现系统,使我能够轻松地在消息代理供应商之间切换,例如:RabbitMq、Azure Service Bus、Amazon SQS、(Kafka)。
我们目前正在讨论实现这一目标的最佳选择,并提出了以下备选方案:
- 每个供应商的接口和不同的实现
我为系统所需的各种功能创建接口,并使用供应商的客户端库来实现该接口。缺点当然是,我需要为每个供应商编写一个实现。
- 使用 AMQP 1.0 标准客户端库
我坚持使用 AMQP 标准并使用 AMQP 标准库 (https://github.com/Azure/amqpnetlite) 来实现。所有基于 AMQP 的消息代理都应该只使用一种实现。缺点是,我依赖于 AMQP 和 AMQP 版本(RabbitMQ 目前使用 0.9,Kafka 没有使用 AMQP)。
- 在已经支持不同代理的顶部使用服务总线
比如 NServiceBus 或 MassTransit(开源)。这将为我的系统增加额外的依赖性并增加其占用空间。 NServiceBus 也不是免费的,它会以某种方式将 "vendor depencency" 转移到服务总线。
第一个质量目标是建立一个可靠且有弹性的系统(每天 > 100.000 个 Jobrequests)。
请分享您的想法:)
我必须承认我有偏见,因为我是Rebus的作者。不过,这是我的建议:
选择选项 3!
所有提到的服务总线库都是相当非侵入性的,这意味着您最终编写的大部分代码将采用如下形式(示例来自 Rebus,但其他两个提到的库是非常相似):
await bus.Send(command);
用于发送命令,或
await bus.Publish(evt);
用于发布一个事件,其中bus
是一个接口(在本例中是IBus
),像这样:
public class MyCommandHandler : IHandleMessages<MyCommand>
{
public async Task Handle(MyCommand command)
{
// do stuff with the command here
}
}
用于处理消息(无论是发送还是发布)。
这意味着您将获得库提供的代码可移植性和独立于供应商的所有好处,对代码布局的影响非常小。
如果您决定实现自己的消息传递代码,用您自己的消息传递代码替换服务总线库的使用应该不会花费太多工作:创建您自己的 IBus
接口和您自己的在这种情况下,IHandleMessages<TMessage>
接口足以完全删除依赖项。
只是我的两分钱。
我目前正在按照 .Net Core 中的 "competing consumer pattern" 构建一个系统。因此,我将 JobRequest-Message 放在一个队列上,多个消费者(工作者)订阅了该队列。其中一位消费者收到消息并实际处理作业。
我也有搭建系统的需求"vendor independent"。这意味着我需要以某种方式实现系统,使我能够轻松地在消息代理供应商之间切换,例如:RabbitMq、Azure Service Bus、Amazon SQS、(Kafka)。
我们目前正在讨论实现这一目标的最佳选择,并提出了以下备选方案:
- 每个供应商的接口和不同的实现
我为系统所需的各种功能创建接口,并使用供应商的客户端库来实现该接口。缺点当然是,我需要为每个供应商编写一个实现。
- 使用 AMQP 1.0 标准客户端库
我坚持使用 AMQP 标准并使用 AMQP 标准库 (https://github.com/Azure/amqpnetlite) 来实现。所有基于 AMQP 的消息代理都应该只使用一种实现。缺点是,我依赖于 AMQP 和 AMQP 版本(RabbitMQ 目前使用 0.9,Kafka 没有使用 AMQP)。
- 在已经支持不同代理的顶部使用服务总线
比如 NServiceBus 或 MassTransit(开源)。这将为我的系统增加额外的依赖性并增加其占用空间。 NServiceBus 也不是免费的,它会以某种方式将 "vendor depencency" 转移到服务总线。
第一个质量目标是建立一个可靠且有弹性的系统(每天 > 100.000 个 Jobrequests)。
请分享您的想法:)
我必须承认我有偏见,因为我是Rebus的作者。不过,这是我的建议:
选择选项 3!
所有提到的服务总线库都是相当非侵入性的,这意味着您最终编写的大部分代码将采用如下形式(示例来自 Rebus,但其他两个提到的库是非常相似):
await bus.Send(command);
用于发送命令,或
await bus.Publish(evt);
用于发布一个事件,其中bus
是一个接口(在本例中是IBus
),像这样:
public class MyCommandHandler : IHandleMessages<MyCommand>
{
public async Task Handle(MyCommand command)
{
// do stuff with the command here
}
}
用于处理消息(无论是发送还是发布)。
这意味着您将获得库提供的代码可移植性和独立于供应商的所有好处,对代码布局的影响非常小。
如果您决定实现自己的消息传递代码,用您自己的消息传递代码替换服务总线库的使用应该不会花费太多工作:创建您自己的 IBus
接口和您自己的在这种情况下,IHandleMessages<TMessage>
接口足以完全删除依赖项。
只是我的两分钱。