MassTransit封顶消息率为10

时间:2014-06-02 14:40:48

标签: rabbitmq masstransit

我有一个公共交通消费者服务设置与RabbitMQ一起工作,我无法弄清楚如何提高消费者的速度 - 似乎很难限制每秒收到的10条消息。

我已尝试过此处列出的步骤:https://groups.google.com/forum/#!msg/masstransit-discuss/plP4n2sixrY/xfORgTPqcwsJ,但没有成功 - 将预取和并发使用者设置为25只会增加已确认的消息,但它不会增加速率消息的下载。

我的配置如下:

ServiceBusFactory.ConfigureDefaultSettings(x =>
    {
        x.SetConcurrentReceiverLimit(25);
        x.SetConcurrentConsumerLimit(25);
    });

_bus = ServiceBusFactory.New(
    sbc =>
        {
            sbc.UseRabbitMq(x => 
                x.ConfigureHost(
                    "rabbitmq://localhost/Dev/consume?prefetch=25",
                    y =>
                        {
                            y.SetUsername(config.Username);
                            y.SetPassword(config.Password);
                        }));
            sbc.UseLog4Net();
            sbc.ReceiveFrom("rabbitmq://localhost/Dev/consume?prefetch=25");
            sbc.Subscribe(x => RegisterConsumers(x, container));
            sbc.UseJsonSerializer();
            sbc.SetConcurrentConsumerLimit(25);
        });

我在两个地方设置并发消费者限制,因为我不确定是否需要将其设置为默认或总线配置,并且消费者通过统一注册 - 我已省略所有订阅者都在接收消费者订阅。

我是否还需要设置其他任何内容,或者是否需要更改我设置配置的顺序。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:5)

在度过了一个浪漫的夜晚,并尝试了克里斯提出的不同建议之后,我发现还有还有另一个的事情要让它按照应有的方式运作。

具体而言,,您需要在使用者队列地址上设置预取:

sbc.UseRabbitMq(
                f =>
                    f.ConfigureHost(
                        new Uri( "rabbitmq://guest:guest@localhost/masstransit_consumer" ),
                        c =>
                        {
                        } )
                );

int pf = 20; // prefetch

// set consumer prefetch (required!)
sbc.ReceiveFrom( string.Format( "rabbitmq://guest:guest@localhost/masstransit_consumer?prefetch={0}", pf ) );

但这仍然不够。

密钥可以在mtstress工具的代码中找到克里斯在他的回答下面的评论中提到的。结果是工具调用:

int _t, _ct;
ThreadPool.GetMinThreads( out _t, out _ct );
ThreadPool.SetMinThreads( pf, _ct );

将此添加到我的代码可以解决问题。我想知道为什么MSMQ传输不需要这个,但是......

更新#1

经过进一步调查后,我发现了一个可能的罪魁祸首。它位于ServiceBusBuilderImpl

有一种方法可以提高限额ConfigureThreadPool

这里的问题是它调用CalculateRequiredThreads,它应该返回所需线程的数量。不幸的是,后者在我的客户端Windows 7和Windows Server上都返回值。因此,ConfigureThreadPool实际上没有做任何事情,因为在调用ThreadPool.SetMin/MaxThreads时会忽略负值。

这个负面价值怎么样?似乎CalculateRequiredThreads调用ThreadPool.GetMinThreadsThreadPool.GetAvailableThreads并使用公式来提供所需线程的数量:

var requiredThreads = consumerThreads + (workerThreads - availableWorkerThreads);

这里的问题是在我的机器上这有效地做到了:

40 (my limit) + 8 (workerThreads) - 1023 (availableThreads) 

当然会返回

-975

结论是:上述代码来自公共交通内部似乎是错误的。当我提前手动提高限制时,ConfigureMinThreads会尊重它(因为只有当它高于读取值时才设置限制)。

如果不事先手动设置限制,则无法设置限制,因此代码执行的线程数与默认线程池限制(在我的计算机上似乎为8)一样多。

显然有人认为这个公式会产生

40 + 8 - 8

在默认情况下。为什么GetMinThreadsGetAvailableThreads返回此类不相关的值还有待确定...

更新#2

更改

    static int CalculateRequiredThreads( int consumerThreads )
    {
        int workerThreads;
        int completionPortThreads;
        ThreadPool.GetMinThreads( out workerThreads, out completionPortThreads );
        int availableWorkerThreads;
        int availableCompletionPortThreads;
        ThreadPool.GetAvailableThreads( out availableWorkerThreads, out availableCompletionPortThreads );
        var requiredThreads = consumerThreads + ( workerThreads - availableWorkerThreads );
        return requiredThreads;
    }

    static int CalculateRequiredThreads( int consumerThreads )
    {
        int workerThreads;
        int completionPortThreads;
        ThreadPool.GetMaxThreads( out workerThreads, out completionPortThreads );
        int availableWorkerThreads;
        int availableCompletionPortThreads;
        ThreadPool.GetAvailableThreads( out availableWorkerThreads, out availableCompletionPortThreads );
        var requiredThreads = consumerThreads + ( workerThreads - availableWorkerThreads );
        return requiredThreads;
    }

解决了这个问题。这两个都返回1023,公式的输出是正确数量的预期线程。

答案 1 :(得分:0)

您的消费者正在进行多少工作?如果运行速度足够快,那么.NET运行时可能无需创建额外的线程来处理入站消息速率。

我们有许多生产系统使用指定的计数,我们将消费者限制与预取计数相匹配,在所有这些情况下,RabbitMQ显示的未确认消息计数等于这些设置。我们通常看到几乎相同数量的线程处理消息。最初,.NET运行时在所使用的已分配线程中是保守的,但当消费者只是等待远程操作(如HTTP请求或SQL命令)时,它会快速达到完整的线程数。

如果消费者的某个区域是单线程的,则可能会限制基于该瓶颈的线程扩展,因此请验证您的线程模型是否也已正确配置。