3

我目前正在调查这个,但我想我还是会问。一旦我发现如果没有回答,将发布答案。

问题如下:

应用程序调用 RabbitHutch.CreateBus 来创建 IBus/IAdvancedBus 的实例以将消息发布到 RabbitMQ。返回实例,但 IsConnected 标志设置为 false(即在后台完成连接重试)。当应用程序处理特定请求时,将调用 IAdvancedBus.PublishAsync 以在总线仍未连接时发布消息。在大量负载下,对应用程序的请求最终会超时,因为总线永远无法连接到 RabbitMQ。

当处理请求时与 RabbitMQ 的连接丢失时,会观察到相同的行为。

问题是:

EasyNetQ 如何在总线断开时处理发布消息的尝试?

在建立连接之前,消息是否在内存中排队?如果是这样,它是否会在达到某个限制后处理消息?这是可配置的吗?

还是强制总线尝试连接到 RabbitMQ?

还是完全转储消息?

PublisherConfirms 是否打开影响行为?

4

1 回答 1

4

我无法测试上述所有场景,但看起来在尝试发布到 RabbitMQ 之前,EasyNetQ 正在检查总线是否已连接。如果不是,它或多或少地进入了一个连接循环,如下所述:https ://github.com/EasyNetQ/EasyNetQ/wiki/Error-Conditions#there-is-a-network-failure-between-my -subscriber-and-the-rabbitmq-broker

随着我们负载的增加,看起来连接循环正在失控,因为我们的基础设施或配置已损坏,它们都无法连接到 RabbitMQ。为什么我们会出现我尚未确定的超时,但我怀疑当多个连接循环尝试同时连接时可能会出现并发问题。

我也怀疑关闭 PublisherConfirms 是否会有所帮助,因为我们无法发布消息,因此无需等待 RabbitMQ 的确认。

我们的解决方案:

那么为什么我没有得到这个问题的明确答案呢?事实上,严格来说,此时我们试图发布的消息并不是关键任务。如果我们的配置错误,运行健康检查时部署将失败,我们将基本上中止部署。如果 RabbitMQ 由于某种原因变得不可用,我们可以不发布这些消息。

此外,为了避免超时,如果我们检测到我们的应用程序和 RabbitMQ 之间的电路已打开,我们将使用断路器来包装消息发布以停止消息发布。粗略地说,它的工作原理如下:

var bus = RabbitHutch.Create(...).Advanced;
var rabbitMqCircuitBreaker = new CircuitBreaker(...);
rabbitMqCircuitBreaker.AttemptCall(() => {
    if (!bus.IsConnected)
       throw new Exception(...);
    bus.Publish(...);
});

请注意,当通过抛出异常将 IsConnected 标志设置为 false 时,我们正在通知我们的断路器存在问题。如果在配置的时间段内抛出异常 X 次,电路将打开,我们将在配置的时间内停止尝试发布消息。我们认为这是可以接受的,因为如果 RabbitMQ 可用,连接应该非常快速且 99.xxx% 的时间可用。另外值得注意的是,总线是在我们的应用程序启动时创建的,而不是在每次调用之前创建的,因此在有效场景中实际设置之前检查标志的可能性非常低。

目前为我们工作,任何其他信息将不胜感激。

于 2015-04-22T12:43:05.510 回答