C# MassTransit-解释单个消费者的预取计数和多个通道

C# MassTransit-解释单个消费者的预取计数和多个通道,c#,rabbitmq,masstransit,C#,Rabbitmq,Masstransit,我一直在玩预回迁,并试图找出为什么队列管理界面上的预回迁总是设置为0。在RabbitMQ管理界面中,我可以看到通道上配置的预取,但不能看到队列本身。我还注意到,它们注册为“全球”而不是“每消费者”,但就我而言,我似乎无法在MassTransit中找到改变这一点的设置,尽管我猜我对这一点有误解,而且文档也没有帮助我获得ELI5 这是一个示例配置: var busControl = Bus.Factory.CreateUsingRabbitMq(cfg => { var host = c

我一直在玩预回迁,并试图找出为什么队列管理界面上的预回迁总是设置为0。在RabbitMQ管理界面中,我可以看到通道上配置的预取,但不能看到队列本身。我还注意到,它们注册为“全球”而不是“每消费者”,但就我而言,我似乎无法在MassTransit中找到改变这一点的设置,尽管我猜我对这一点有误解,而且文档也没有帮助我获得ELI5

这是一个示例配置:

var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
   var host = cfg.Host(
        new Uri(busSettings.HostAddress),
        h =>
        {
            h.Username(busSettings.Username);
            h.Password(busSettings.Password);
        });

    cfg.ReceiveEndpoint(
        host,
        "TEST-QUEUE-PF",
        ec =>
        {
            ec.Consumer<MyConsumer>(context);
            ec.PrefetchCount = 50; // consumer specific
            ec.UseConcurrencyLimit(1); // consumer specific
        });

    cfg.PrefetchCount = 100; // bus control specific
    cfg.UseConcurrencyLimit(1); // bus control specific
});
var-busControl=Bus.Factory.CreateUsingRabbitMq(cfg=>
{
var host=cfg.host(
新Uri(busSettings.HostAddress),
h=>
{
h、 用户名(busSettings.Username);
h、 密码(busSettings.Password);
});
接收端点(
主办
“TEST-QUEUE-PF”,
ec=>
{
欧共体消费者(上下文);
ec.PrefetchCount=50;//特定于消费者
ec.UseConcurrencyLimit(1);//特定于消费者
});
cfg.PrefetchCount=100;//特定于总线控制
cfg.UseConcurrencyLimit(1);//特定于总线控制
});
这将创建以下队列:

然后查看通道,我看到以下关于预取的信息:

如果我查看所有频道,我会看到以下内容:

我很难理解这些预取计数与什么有关

作为一个背景,我们有几个运行消费者的多核服务器(即循环,或者更合适的“饥饿的河马”,因为我不关心平均分布)。PrefetchCount和ConcurrencyLit的默认设置对我们来说效果不太好,因为我们的使用者有很多工作要做,而且会使数据库服务器过载,导致超时。我正在寻找一种方法来配置这些消费者,这样他们就不会这样做

这是MassTransit 5.5.5,因为上面的任何内容都会破坏UseSerilog()集成,我找不到简单的升级路径。Erlang和RabbitMq本身就是当前版本。这是更详细的AutoFac模块:

private class BusModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterAssemblyTypes(GetType().Assembly).As<IConsumer>();
        builder.Register(context =>
        {
            var busSettings = context.Resolve<BusSettings>();
            var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
            {
                var host = cfg.Host(
                    new Uri(busSettings.HostAddress),
                    h =>
                    {
                        h.Username(busSettings.Username);
                        h.Password(busSettings.Password);
                    });

                cfg.ReceiveEndpoint(
                    host,
                    $"TEST-QUEUE-GLOBAL", // shared queue name for all nodes
                    ec =>
                    {
                        ec.PrefetchCount = 50;
                        ec.UseConcurrencyLimit(2);
                        ec.Consumer<MyConsumer>(context);
                        ec.EnablePriority(5);
                        ec.UseRetry(retryConfig =>
                        {
                            retryConfig
                                .Intervals(new[] { 1, 2, 4, 8, 16, 32 }
                                .Select(t => TimeSpan.FromMinutes(t))
                                .ToArray());
                            retryConfig
                                .Handle<HttpRequestException>();
                            retryConfig
                                .Handle<SwaggerException>(ex => ex.IsRetryValid());
                        });
                    });

                cfg.PrefetchCount = 100;
                cfg.UseConcurrencyLimit(2);
                cfg.UseSerilog();

                var correlationIdProvider = context.Resolve<ICorrelationProvider>();
                cfg.ConfigurePublish(x => x.UseExecute(sendContext =>
                {
                    sendContext.CorrelationId = 
                        sendContext.CorrelationId == Guid.Empty ? 
                            correlationIdProvider.GetId() : sendContext.CorrelationId; // cascade
                }));
            });

            return busControl;
        })
        .SingleInstance()
        .As<IBusControl>()
        .As<IBus>();
    }
}
专用类总线模块:模块
{
受保护的覆盖无效负载(ContainerBuilder builder)
{
RegisterAssemblyTypes(GetType().Assembly).As();
builder.Register(上下文=>
{
var busSettings=context.Resolve();
var busControl=Bus.Factory.CreateUsingRabbitMq(cfg=>
{
var host=cfg.host(
新Uri(busSettings.HostAddress),
h=>
{
h、 用户名(busSettings.Username);
h、 密码(busSettings.Password);
});
接收端点(
主办
$“TEST-QUEUE-GLOBAL”,//所有节点的共享队列名称
ec=>
{
ec.预取计数=50;
ec.UseConcurrencyLimit(2);
欧共体消费者(上下文);
ec.使能优先权(5);
ec.UseRetry(retryConfig=>
{
retryConfig
.间隔(新[{1,2,4,8,16,32}
.选择(t=>TimeSpan.FromMinutes(t))
.ToArray());
retryConfig
.Handle();
retryConfig
.Handle(ex=>ex.IsRetryValid());
});
});
cfg.PrefetchCount=100;
cfg.UseConcurrencyLimit(2);
cfg.useserlog();
var correlationIdProvider=context.Resolve();
ConfigurePublish(x=>x.UseExecute(sendContext=>
{
sendContext.CorrelationId=
sendContext.CorrelationId==Guid.Empty?
correlationIdProvider.GetId():sendContext.CorrelationId;//级联
}));
});
返回总线控制;
})
.SingleInstance()
.As()
.As();
}
}

首先,我假设您使用的是较旧版本的MassTransit,因为该交换机是从v6开始的全局预取转移而来的

其次,高预取计数加上1的并发限制将导致(预取计数-1)消息位于接收端点上等待处理,而一次处理一条消息。因此,如果只有50条消息,第一个节点可能会获得所有消息,而其他节点则处于空闲状态,因为这些消息正在等待单个节点通过瓶颈

带有通道预取的RabbitMQ管理控制台的当前版本如下所示:

由于MassTransit只在一个通道上放置一个消费者,以前的方法本质上将消费者限制在全局通道预取上,但现在它更明确了。此外,新设置适用于仲裁队列,仲裁队列不支持全局预取设置


如果您正在重载数据库,并且已经优化了数据库查询以避免锁定/阻塞,并且需要减少流量,请降低预取以接近并发限制的140%。所以,说真的,如果你是1,那么将prefetch设置为2。

我假设每个分布式使用者都有相同的队列名称不是问题?关于上面的评论,我不关心哪个节点获取和处理消息,只要添加节点有助于更快地处理整个消息。基本上就是我所说的“饥饿的河马”