我有一个公共交通消费者服务设置与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);
});
我在两个地方设置并发消费者限制,因为我不确定是否需要将其设置为默认或总线配置,并且消费者通过统一注册 - 我已省略所有订阅者都在接收消费者订阅。
我是否还需要设置其他任何内容,或者是否需要更改我设置配置的顺序。
非常感谢任何帮助。
答案 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.GetMinThreads
和ThreadPool.GetAvailableThreads
并使用公式来提供所需线程的数量:
var requiredThreads = consumerThreads + (workerThreads - availableWorkerThreads);
这里的问题是在我的机器上这有效地做到了:
40 (my limit) + 8 (workerThreads) - 1023 (availableThreads)
当然会返回
-975
结论是:上述代码来自公共交通内部似乎是错误的。当我提前手动提高限制时,ConfigureMinThreads
会尊重它(因为只有当它高于读取值时才设置限制)。
如果不事先手动设置限制,则无法设置限制,因此代码执行的线程数与默认线程池限制(在我的计算机上似乎为8)一样多。
显然有人认为这个公式会产生
40 + 8 - 8
在默认情况下。为什么GetMinThreads
和GetAvailableThreads
返回此类不相关的值还有待确定...
更新#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命令)时,它会快速达到完整的线程数。
如果消费者的某个区域是单线程的,则可能会限制基于该瓶颈的线程扩展,因此请验证您的线程模型是否也已正确配置。