C# RabbitMQ:使用路由实现消息选择

C# RabbitMQ:使用路由实现消息选择,c#,queue,rabbitmq,C#,Queue,Rabbitmq,我正在尝试使用RabbitMQ实现一个解决方案,以实现类似分布式RPC的功能,只使用一个请求和一个响应队列来处理大量处理器,我已经用ApacheAppollo实现了这样一个解决方案,我希望能够将其迁移到RabbitMQ。以下是要点: 每个服务器都连接到请求队列 每台服务器只处理本应属于他的请求(标题字段) 在我的Apollo实现中,关键点是选择器的使用(如标题字段值的where子句),我认为这是通过路由和路由键在RabbitMQ中实现的,但我一定是错了,因为我看到工作人员接收到的消息不应该是

我正在尝试使用RabbitMQ实现一个解决方案,以实现类似分布式RPC的功能,只使用一个请求和一个响应队列来处理大量处理器,我已经用ApacheAppollo实现了这样一个解决方案,我希望能够将其迁移到RabbitMQ。以下是要点:

  • 每个服务器都连接到请求队列
  • 每台服务器只处理本应属于他的请求(标题字段)
在我的Apollo实现中,关键点是选择器的使用(如标题字段值的where子句),我认为这是通过路由和路由键在RabbitMQ中实现的,但我一定是错了,因为我看到工作人员接收到的消息不应该是他们的

为了复制这个问题,我修改了Routing sample(),我有两个消费者,可以从定义routingKey的不同参数开始,还有一个生产者为其中一个消费者生成消息。我看到的行为是,消息的消费似乎是随机的(消费者第一次处理“John”的消息,消费者第二次处理“Mary”的消息)

是否有人对在RabbitMQ中使用选择器有任何指示或代码片段

下面是我的消费者代码:

public static void Main( String[] args )
{
    var factory = new ConnectionFactory { HostName = "localhost" };
    using ( var connection = factory.CreateConnection() )
        using ( var channel = connection.CreateModel() )
        {
            const String request = "request";
            channel.ExchangeDeclare( request, "direct" );

            channel.QueueDeclare( request, true, false, false, null );

            if ( args.Length < 1 )
            {
                Console.WriteLine( " Press [enter] to exit." );
                Console.ReadLine();
                Environment.ExitCode = 1;
                return;
            }

            var myRoutingKey = args[0];
            channel.QueueBind( request, request, myRoutingKey );

            Console.WriteLine( $" [*] Waiting for messages for {myRoutingKey}." );

            var consumer = new EventingBasicConsumer( channel );
            consumer.Received += ( model, ea ) =>
            {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString( body );
                var routingKey = ea.RoutingKey;
                Console.WriteLine( $" [x] Received '{routingKey}':'{message}'" );
            };
            channel.BasicConsume( request, true, consumer );

            Console.WriteLine( " Press [enter] to exit." );
            Console.ReadLine();
        }
}

提前谢谢。

我能猜出为什么这对你不起作用。关键是消费者的这两条线

channel.QueueDeclare( request, true, false, false, null );
channel.QueueBind( request, request, myRoutingKey );
事实上,“请求”是“所有”消费者的队列名称。如果运行此程序时使用多个路由密钥设置多个绑定,最终结果是名为“request”的队列使用多个路由密钥(例如“John”、“Mary”)绑定到您的exchange。请记住,在执行此绑定时,绑定在RabbitMQ服务器中不是暂时的,它们会一直存在

现在回到如何解决您的问题。有多种选择,但这里是其中之一。首先,我建议你阅读这本书

您可以使用包含以下行的相同教程代码,而不是您的:

 var queueName = channel.QueueDeclare().QueueName;
 channel.QueueBind( queueName, request, myRoutingKey );
但上述情况意味着,每次运行消费者程序时,都会创建一个新队列,并使用所需的路由密钥绑定到exchange。另一种方法是使用与以前相同的代码,但只需适当地选择队列名称,而不是固定的队列名称。例如,每个路由密钥可以有一个队列

var queueName = myRoutingKey ;
channel.QueueDeclare( queueName, true, false, false, null );
channel.QueueBind( queueName, request, myRoutingKey );
或者,您也可以将多个路由密钥分组到一个类似于教程示例的队列中


关键是你需要做的事情不能用一个队列来完成。(而不是在使用消息时过滤掉它们)。但这听起来不像是对你的真正要求。您要求的是,每个消费者服务器只处理您在此模型中可以执行的相关消息。但是制作人只发布到那一个交易所(这是你想要的)。

我可以猜出为什么这对你不起作用。关键是消费者的这两条线

channel.QueueDeclare( request, true, false, false, null );
channel.QueueBind( request, request, myRoutingKey );
事实上,“请求”是“所有”消费者的队列名称。如果运行此程序时使用多个路由密钥设置多个绑定,最终结果是名为“request”的队列使用多个路由密钥(例如“John”、“Mary”)绑定到您的exchange。请记住,在执行此绑定时,绑定在RabbitMQ服务器中不是暂时的,它们会一直存在

现在回到如何解决您的问题。有多种选择,但这里是其中之一。首先,我建议你阅读这本书

您可以使用包含以下行的相同教程代码,而不是您的:

 var queueName = channel.QueueDeclare().QueueName;
 channel.QueueBind( queueName, request, myRoutingKey );
但上述情况意味着,每次运行消费者程序时,都会创建一个新队列,并使用所需的路由密钥绑定到exchange。另一种方法是使用与以前相同的代码,但只需适当地选择队列名称,而不是固定的队列名称。例如,每个路由密钥可以有一个队列

var queueName = myRoutingKey ;
channel.QueueDeclare( queueName, true, false, false, null );
channel.QueueBind( queueName, request, myRoutingKey );
或者,您也可以将多个路由密钥分组到一个类似于教程示例的队列中


关键是你需要做的事情不能用一个队列来完成。(而不是在使用消息时过滤掉它们)。但这听起来不像是对你的真正要求。您要求的是,每个消费者服务器只处理您在此模型中可以执行的相关消息。制作人只发布到那一个交易所(这是你想要的)。

嗨,阿明,谢谢你的回答。我还发现,使用动态生成的队列不会出现问题。无论如何,我一直在寻找一个只包含请求和响应队列的解决方案,这既是出于性能考虑,也是因为我以前用另一个代理实现的另一个解决方案就是这种解决方案。识别出不同的模型后,后者不是问题,只需要重新设计,但我肯定需要验证性能。此外,通过使用动态生成的队列,我释放了在路由使用者未运行时从生产者生成的所有消息。我还尝试将交换声明为持久的,但没有帮助。动态生成的队列对您来说基本上是临时队列,因为您将丢失我假定的队列名称?我不相信动态队列名称对您来说是一个解决方案,只需使用一致的名称(将它们视为您的选择器)。这样做不会影响性能。这就是RabbitMQ的设计目的。嗨,阿明,谢谢你的回答。我还发现,使用动态生成的队列不会出现问题。无论如何,我一直在寻找一个只包含请求和响应队列的解决方案,这既是出于性能考虑,也是因为我以前用另一个代理实现的另一个解决方案就是这种解决方案。识别出一个不同的模型后,后者不是问题,只是需要重新设计,但我肯定不会