我一直在使用.NET客户端测试RabbitMQ 3.5.5,并且看到了一些我不理解的行为。具体来说,我有一个生产者,它使用特定的路由密钥将10,000条消息写入exchange
。有一个队列映射到具有相同路由密钥的交换。
如果我然后创建两个频道(IModel
),每个频道都有一个EventingBasicConsumer
并告诉他们从direct
交换机上的同一队列中消费,我似乎得到了超过10,000条消息。
鉴于交换是一个direct
交换,我本来期望在消费者中进行轮询。我注意到如果我在单独的线程中创建使用者,那么我就不会看到这种行为。
以下示例代码:
static void Main(string[] args)
{
//set up the exchange and queue
string exchangeName = "testexchange";
string queueName = "testqueue";
ConnectionFactory connectionFactory = new ConnectionFactory() { HostName = "localhost" };
IConnection connection = connectionFactory.CreateConnection();
IModel producerChannel = connection.CreateModel();
producerChannel.ExchangeDeclare(exchangeName, "direct", false);
//consumer 1
IModel consumerChannel1 = connection.CreateModel();
consumerChannel1.QueueDeclare(queueName, false, false, false, null);
consumerChannel1.QueueBind(queueName, exchangeName, string.Empty);
//consumer 2
IModel consumerChannel2 = connection.CreateModel();
consumerChannel2.QueueDeclare(queueName, false, false, false, null);
consumerChannel2.QueueBind(queueName, exchangeName, string.Empty);
int publishCount = 10000;
int receivedCount = 0;
//publish to the exchange
for (int i = 0; i < publishCount; i++)
producerChannel.BasicPublish(exchangeName, string.Empty, null, Encoding.UTF8.GetBytes(i.ToString()));
//set up the consumers to consume
EventingBasicConsumer consumer1 = new EventingBasicConsumer(consumerChannel1);
consumer1.Received += (sender, eventArgs) =>
{
Interlocked.Increment(ref receivedCount);
};
consumerChannel1.BasicConsume(queueName, true, consumer1);
EventingBasicConsumer consumer2 = new EventingBasicConsumer(consumerChannel2);
consumer1.Received += (sender, eventArgs) =>
{
Interlocked.Increment(ref receivedCount);
};
consumerChannel2.BasicConsume(queueName, true, consumer2);
//wait a bit
DateTime waitStart = DateTime.UtcNow;
while (DateTime.UtcNow.Subtract(waitStart).TotalSeconds < 10 && receivedCount < publishCount)
Thread.Sleep(100);
Console.WriteLine("Total received: {0}", receivedCount); //usually has a number more than 10,000
Console.ReadLine();
producerChannel.ExchangeDelete(exchangeName);
consumerChannel1.QueueDelete(queueName);
producerChannel.Dispose();
consumerChannel1.Dispose();
consumerChannel2.Dispose();
connection.Dispose();
}