我试图通过RabbitMQ实现混乱。我总是听到它的疯狂,所以我试了一下。但出于某种原因,这很慢。
我有一个名为blockchain
的队列。它有几条消息,消息大小约为1kb。然后我创建一个队列监听器,它基本上只是在stdout中写一个常量文本:
public async Task RunAsync(CancellationToken cancellationToken)
{
// using EasyNetQ in this example.
using (var bus = RabbitHutch.CreateBus(_queueSettings.RabbitConnection)).Advanced)
{
using (var _ = await ConsumeBus(bus, _queueSettings.QueueName))
{
Console.WriteLine("Listening for messages. Hit <return> to quit.");
cancellationToken.WaitHandle.WaitOne();
}
}
}
private async Task<IDisposable> ConsumeBus(IAdvancedBus bus, string queueName)
{
var queue = await bus.QueueDeclareAsync(queueName, true).ConfigureAwait(false);
return bus.Consume(queue,
(body, properties, info) => Console.WriteLine("Got a message!"));
}
但是当我在队列中观察时,我发现消息消耗速度仅为 ~40 msg / sec 。相比网络上的50k msg / sec written in articles似乎非常慢。当我进入管理页面时,我发现该队列几乎被完全利用了:
连接字符串似乎也可以,我们需要大批量处理它们:
"QueueSettings": {
"RabbitConnection":
"host=myhost:5672;username=reader;password=readerpass5;requestedHeartbeat=20;prefetchcount=100;timeout=1000;publisherConfirms=true",
"QueueName": "blockchain"
},
这里有什么问题?我怎样才能在每个队列中每秒获得这么多惊人的数千条消息?我应该部署1000个消费者,并期望他们有40 * 1000 msg /秒?
这个版本速度稍慢,但我仍然无法获得超过50 msg / sec
public async Task RunAsync(CancellationToken cancellationToken)
{
var factory = GetConnectionFactory()
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
using (var _ = ConsumeBus(channel, _queueSettings.QueueName))
{
_contextlessLogger.Information("Listening for messages. Hit <return> to quit.");
cancellationToken.WaitHandle.WaitOne();
}
}
}
private IDisposable ConsumeBus(IModel bus, string queueName)
{
return new Consumer(bus, queueName, async bytes => Console.WriteLine("Got a message!"));
}
public class Consumer : IDisposable
{
private readonly IModel _channel;
private readonly Func<byte[], Task> _action;
private readonly EventingBasicConsumer _consumer;
public Consumer(IModel channel, string queueName, Func<byte[], Task> action)
{
_channel = channel;
_action = action;
_consumer = new EventingBasicConsumer(channel);
_consumer.Received += OnReceived;
channel.BasicConsume(queueName, false, _consumer);
}
private async void OnReceived(object model, BasicDeliverEventArgs ea)
{
try
{
await _action(ea.Body);
_channel.BasicAck(ea.DeliveryTag, false);
}
catch
{
_channel.BasicNack(ea.DeliveryTag, false, true);
}
}
public void Dispose()
{
_consumer.Received -= OnReceived;
}
}