在缩放rabbitmq时处理流量

时间:2016-07-14 21:12:28

标签: spring rabbitmq spring-integration

我在管道中有两个应用程序(让我们称之为A和B)。

App A是一个Spring Boot / Spring Integration应用程序,它从队列1中读取消息X,做一些工作,并将大量消息Y发送到队列2中 - 对于队列1中的每个X,大约300 Y将发布到2.单个线程处理每个X中的工作并发布单个消息。优化应用程序A让我到了一个单一实例可以承认每秒50 X的地方;因此每秒向队列2发布大约15k Y.

App B也是一个Spring Boot / Spring Integration应用程序,它从队列2中读取Ys并聚合它们,完成管道。 B的单个实例每秒处理大约7-8k Y.

总而言之,对于1 A,2 B和一个相当大的RabbitMQ服务器(AWS r3.4xlarge),我每秒大约50 X和15000 Y.

我一直在努力扩大这个过程;至少,我想达到每秒100 X / 30000 Y.因为这些应用程序中的逻辑适合横向扩展,所以我一直在尝试将部署加倍;即2个As和4个B。

但是,放大As并不会产生预期效果; Xs的确认大致稳定在50 / s,Ys也保持稳定在每秒15k左右,队列2保持或多或少空。

仔细检查发现,A的发布渠道处于flow模式,大概是因为每秒15k就要塞进队列2.然而,限制似乎不仅仅是一个接收15k Y的队列一秒;如果我设置更改绑定,以便Ys发布到没有任何消费者的队列,我每秒达到预期的100 X / 30k Y.

为什么我不能在队列2中每秒获得30k Y?

其他详情:

  • 队列2通过DLX
  • 声明为持久
  • Y消息作为非持久性发布

发布者声明如下:

@Bean
public IntegrationFlow outboundFlow(ConnectionFactory connectionFactory, MessageConverter jsonNodeMessageConverter,
                                    AmqpHeaderMapper headerMapper) {
    RabbitTemplate outboundTemplate = new RabbitTemplate(connectionFactory);
    outboundTemplate.setMessageConverter(jsonNodeMessageConverter);

    return IntegrationFlows
            .from(BeanNames.OUTPUT_CHANNEL)
            .split()
            .handle(Amqp.outboundAdapter(outboundTemplate)
                    .exchangeName(OUTBOUND_EXCHANGE_NAME)
                    .headerMapper(headerMapper)
                    .routingKeyExpression("headers." + ApplicationHeaders.DESTINATION_ROUTING_KEY))
            .get();
}

@Bean
public AmqpHeaderMapper headerMapper() {
    return new DefaultAmqpHeaderMapper() {
        @Override
        protected void populateStandardHeaders(Map<String, Object> headers, MessageProperties amqpMessageProperties) {
            super.populateStandardHeaders(headers, amqpMessageProperties);
            amqpMessageProperties.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
        }
    };
}

更新

我可以在这里充实我的设置。

申请A:

  • 消费者/主题:16
  • 在应用程序A:50
  • 中预取X.
  • 没有出版商的确认
  • 非持久

申请B:

  • 消费者/主题:16
  • 在应用程序B中预取Y:250
  • tx size:250

在RabbitMQ中(我升级到r3.8xlarge):

此时我甚至分流了流量;两个应用程序A读取一个队列1,但发布到两个队列2 - 2a和2b。队列1上的acks / s根本没有改变,2a和2b上的acks / s的总和与只有一个队列2时的acks / s的总和相同。的确,从应用程序A到兔子的连接和从应用程序A到队列2a和2b的通道仍然会定期进入flow

所有改变的是我使用的硬件资源甚至比之前少(因为我升级了兔子服务器) - 兔子从未超过30%的CPU,内存使用率仍然低得离谱。

1 个答案:

答案 0 :(得分:0)

我假设你没有在生产者方面使用交易渠道。

尝试增加Y个消费者监听器容器上的prefetchCounttxSize;第一个将缓冲容器中的消息;第二个会降低ack流量。

修改

有关RabbitMQ的具体信息,请参阅 Finding bottlenecks with RabbitMQ