我们目前正在使用RabbitMQ,其中一个持续超快的生产者与受限于有限资源的消费者(例如,慢速MySQL插入)配对。
我们不喜欢使用x-max-length
声明队列,因为一旦达到限制,所有邮件都将被删除或死信,我们不想丢失邮件。
添加更多的消费者很容易,但他们都会受到一个共享资源的限制,因此无法使用。问题仍然存在:如何减缓生产者的速度?
当然,我们可以在Redis,memcached,MySQL或生产者读取的其他内容中设置流控制标志pointed out in an answer to a similar question,或者更好,生产者可以定期测试队列长度并节制自己,但这些对我来说似乎很糟糕。
我主要质疑我是否有一个根本的误解。我原以为这是一个常见的场景,所以我想知道:
限制生产者的最佳做法是什么?这是如何用RabbitMQ完成的?或者你是以完全不同的方式做到这一点?
假设生产者实际上知道如何通过正确的输入减慢自己的速度。例如。硬件传感器或硬件随机数生成器,可以根据需要生成任意数量的事件。
在我们特定的实际案例中,我们有一个用户可以用来添加消息的API。我们不想吞噬和丢弃消息,而是通过让我们的API在队列“满”时返回错误来应用反压,因此调用者/用户知道要退回,或者让API阻塞直到消费者赶上。我们不控制我们的用户,因此无论消费者的速度有多快,我都可以创建一个更快的生产者。
我希望有类似TCP套接字的API,其中write()
可以阻止,select()
可以用来确定句柄是否可写。因此,要么拥有RabbitMQ API块,要么在队列已满时返回错误。
答案 0 :(得分:2)
我认为这不是兔子特有的。基本上你有一个场景,有两个系统具有不同的处理能力,这种不匹配会带来溢出队列的风险(无论它是什么),或者甚至在生产者和消费者之间经常不匹配的情况下,只需创建事件创建及其处理之间的时间距离越来越大。
我曾经处理过这种情况,遗憾的是没有灵丹妙药。您是否必须加快处理(更好的硬件,更适合的软件?)或限制事件创建(实际上与MQ无关)。
现在,我会问你目标是什么以及如何产生事件。事件是否经常生成,无限制或非常高(例如来自传感器的读数 - 越多越好),或者是批量/尖峰创建(例如:特定时间段内的用户请求,批量加载)来自CRM系统)。我认为目标是处理所有事情,因为你提到你不想丢失任何排队的消息。
如果输出是常量,那么一些限制器(内部计数器,如果生产者是唯一的生产者,或者外部队列长度检查队列是否可以用其他系统填充)肯定是有的。
IF eventsInTimePeriod/timePeriod > estimatedConsumerBandwidth
THEN LowerRate()
ELSE RiseRate()
在现实世界的场景中,我们过去只是手动将输出限制为估计值,并且有一些警报设置为队列长度,从队列进入到队列离开的时间等。省略了这些限制器(大多数情况下是错误的)我们使用了以后找几个应该在几个小时内完成的任务,轮流等待三个月。
我担心很难回答“如何减慢制片人的速度?”如果我们对此一无所知,但有些想法是:上述速率检查或者可能阻止AddMessage方法:
AddMessage(message)
WHILE(getQueueLength() > maxAllowedQueueLength)
spin(1000); // or sleep or whatever
mqAdapter.AddMessage(message)
我说这一切都取决于生产者应用程序的具体情况以及一般的架构。
答案 1 :(得分:1)
对于x-max-length属性,您说过您不希望消息被丢弃或用死字母表示。我看到有一个更新,为此添加了更多功能。如我所见,它在文档中指定:
“使用溢出设置来配置队列溢出行为。如果将溢出设置为拒绝-发布,则将丢弃最近发布的消息。此外,如果启用了发布者确认,则将通过通知发布者拒绝basic.nack消息”
据我所知,您可以使用队列限制来拒绝来自发布者的新消息,从而将一些背压推向上游。