兔子为什么慢得令人惊讶?

时间:2018-06-05 13:02:47

标签: c# .net rabbitmq easynetq

我试图通过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似乎非常慢。当我进入管理页面时,我发现该队列几乎被完全利用了:

enter image description here

连接字符串似乎也可以,我们需要大批量处理它们:

"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;
    }
}

0 个答案:

没有答案