消息积压你作何处理?

1,516 阅读3分钟

1.前言

当被通知消费的队列存在消息积压并呈一个持续上升趋势,需要紧急处理一下,你会怎么办?能怎么办呢?先内心慌张一会,战斗一番,然后打开著名的搜索引擎进行搜索,在搜索结果中寻找答案。本文也即将成为你搜索引擎中出现的一个搜索结果,为你提供解决方案。

2.解决方案

以下解决方案都是针对rabbitmq

2.1 加机器

最简单最方便的处理方案就是让运维加机器,这样消息队列中的消息可以通过负载的方式将消息均摊到更多的机器上,消费者多了,会慢慢处理掉队列中积压的消息。

2.2 加消费者

当然加机器方案并不是万能的,如果你的系统不够格,是加不了加机器(成本过高),那么就得另辟蹊径了,增加并发消费线程数。

2.2.1 固定并发数

@RabbitListener注解中有这么一个属性concurrency,注释如下:

/**
   * Set the concurrency of the listener container for this listener. Overrides the
   * default set by the listener container factory. Maps to the concurrency setting of
   * the container type.
   * <p>For a
   * {@link org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer
   * SimpleMessageListenerContainer} if this value is a simple integer, it sets a fixed
   * number of consumers in the {@code concurrentConsumers} property. If it is a string
   * with the form {@code "m-n"}, the {@code concurrentConsumers} is set to {@code m}
   * and the {@code maxConcurrentConsumers} is set to {@code n}.
   * <p>For a
   * {@link org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer
   * DirectMessageListenerContainer} it sets the {@code consumersPerQueue} property.
   * @return the concurrency.
   * @since 2.0
   */

翻译过来就是为监听器设置并发数,如果属性值是一个int类型,那么设置的就是固定并发数;如果属性值是一个string类型(m-n),那么设置的就是动态并发数,最小并发数为m,最大并发数为n

基于文档注释,可以得出一个结论,那就是如果想要设置并发,那么只需要在@RabbitListener注解中添加concurrency属性并指定一个数值即可

@RabbitListener(queues = "test3", containerFactory = "rabbitListenerContainerFactory", concurrency = "10")

2.2.2 动态并发数

设置消费者并发数后消息消费快了,也不积压了,问题被完美解决。由于存在动态并发数这一章节,说明事情并没有这么简单。设置消费者并发数的初衷是想解决消息积压问题,但是消息并非时时刻刻都会积压,大部分情况下队列中可能都不存在可以消费的消息,此时消费者并发数的设置无疑会给系统带来一定的资源消耗。好在spring框架相关大佬已经给出了解决方案:动态并发数

动态并发数设置形式:

@RabbitListener(queues = "test3", containerFactory = "rabbitListenerContainerFactory", concurrency = "1-10")

concurrency设置为1-10则表示消费者并发数最小为1个,当有更多消息需要处理时,会逐渐增大消费者并发数,最大值为10,当没有消息需要处理是,会逐渐减少消费者并发数,减到1为止

看完上面的描述,你可能认为我是在胡扯,且等看看如下代码实现再下结论

private void checkAdjust(boolean receivedOk) {
    if (receivedOk) {
        // 1.当前消费者处于激活状态
        if (isActive(this.consumer)) {
            this.consecutiveIdles = 0;
            // 1.1 如果连续消息数超过默认值10,则考虑新增一个消费者
            if (this.consecutiveMessages++ > SimpleMessageListenerContainer.this.consecutiveActiveTrigger) {
                considerAddingAConsumer();
                this.consecutiveMessages = 0;
            }
        }
    }
    else {
        this.consecutiveMessages = 0;
        // 2.如果连续超过10次都没有消费到消息,则考虑终止当前消费者
        if (this.consecutiveIdles++ > SimpleMessageListenerContainer.this.consecutiveIdleTrigger) {
            considerStoppingAConsumer(this.consumer);
            this.consecutiveIdles = 0;
        }
    }
}

3. 总结

消息队列中出现消息积压,首先不要慌,其实是能加机器就加机器,不能加机器,说明你的系统不太重要,就得老老实实增加消费者并发数,增加消费者并发数基于上述认知,你应该设置动态并发数