Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >记一次 RabbitMQ 消费者莫名消失问题的排查

记一次 RabbitMQ 消费者莫名消失问题的排查

作者头像
青石路
发布于 2024-09-24 05:08:51
发布于 2024-09-24 05:08:51
31100
代码可运行
举报
文章被收录于专栏:开发技术开发技术
运行总次数:0
代码可运行

问题回顾

某天下午,生产监控告警:消息积压,队列 xxx 消息数超过 100;我第一时间想到的是应用服务是不是停了,但应用服务存活监控又没有告警,但我还是找值班运维同事帮忙确认了下,确认结果是服务的 6 个节点都是存活的,然后我又让运维确认了下队列的消费者情况,结果发现消费者列表中只有 2 个节点的消费者,其他 4 个节点的消费者不见了,所以消息消费不过来,导致了消息积压!

所以问题来了

那 4 个节点的注册的消费者为何消失?

但当务之急是解决消息积压的问题,所以让运维重启那 4 个节点的服务,消费者重新注册上,消息得以快速消费,消息积压告警得以恢复

生产问题虽暂时得以解决,但未找到根因,还是存在复发风险;下面就请大家跟随我的脚本,来看看我是如何排查的

问题排查

直接查 ERROR 级别的日志,很容易就能就找到了关键日志

Consumer thread error, thread abort.

以及异常堆栈

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
	at java.lang.StringCoding$StringEncoder.encode(StringCoding.java:300)
	at java.lang.StringCoding.encode(StringCoding.java:344)
	at java.lang.String.getBytes(String.java:918)
    ...

Consumer thread error, thread abort 大家能看懂吧,就是字面意思

消费者线程错误,线程中止

消费者线程就是我们前面提到的队列消费者,一个队列消费者就是一个消费者线程,消费者线程中止那就意味着队列消费者中止,也就对应文章标题中的 消费者消失;是不是离真相越来越近了?

OutOfMemoryError 是不是很熟悉,内存溢出嘛

OutOfMemoryError 表示 Java 虚拟机在堆内存中没有足够的空间来分配对象

问你们一个问题:OOM 一定会导致 JVM 退出吗,这个问题你们先思考,后面答案会揭晓

回到正题,从关键日志以及异常堆栈,我们是不是可以得出以下推测

OOM 会导致消费者线程中止

有了推测,那就去验证呗;我先给大家模拟下案例,基于 SpringBootpom.xml 关键依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

配置文件 application.yml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server:
  port: 8088
spring:
  rabbitmq:
    host: 192.168.2.118
    port: 5672
    username: admin
    password: admin
    virtual-host: /
    listener:
      simple:
        acknowledge-mode: manual #设置确认模式手工确认
        concurrency: 3 #消费者个数,线程个数
        prefetch: 1

RabbitMQ 配置 TaskRabbitConfig.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.qsl.rabbit.config;

import com.qsl.rabbit.constant.Constant;
import com.qsl.rabbit.listener.TaskMessageListener;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: 青石路
 */
@Configuration
public class TaskRabbitConfig {

    @Value("${spring.rabbitmq.listener.simple.concurrency:3}")
    private int concurrency;
    @Value("${spring.rabbitmq.listener.simple.prefetch:1}")
    private int prefetch;

    @Bean
    public DirectExchange taskExchange() {
        return new DirectExchange(Constant.TASK_EXCHANGE, true, false);
    }

    @Bean
    public Queue taskQueue() {
        return new Queue(Constant.TASK_QUEUE, true, false, false);
    }

    @Bean
    public Binding bindingTaskQueue() {
        return BindingBuilder.bind(taskQueue()).to(taskExchange()).with(Constant.TASK_QUEUE);
    }

    @Bean
    public SimpleMessageListenerContainer taskMessageListenerContainer(ConnectionFactory connectionFactory) {

        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        //设置确认模式手工确认
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        container.setQueueNames(Constant.TASK_QUEUE);
        //消费者个数,线程个数
        container.setConcurrentConsumers(concurrency);
        //设置预处理个数
        container.setPrefetchCount(prefetch);

        container.setMessageListener(new TaskMessageListener());
        return container;
    }
}

消息监听器 TaskMessageListener.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * @author: 青石路
 */
@Slf4j
public class TaskMessageListener implements ChannelAwareMessageListener {

    @Override
    public void onMessage(Message message, Channel channel) {
        String content = new String(message.getBody(), StandardCharsets.UTF_8);
        log.info("消费者接收到消息:{}", content);
        handleTask(content);
        try {
            // 手动ACK
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            log.error("消息确认失败,异常:", e);
        }
    }

    private void handleTask(String message) {
        try {
            // 业务处理
            log.info("处理任务:{}", message);
            log.info("任务处理完成");
        } catch (Exception e) {
            log.error("处理任务失败,异常:", e);
        }
    }
}

业务处理的时候进行 Exception 捕获,并且手动确认消息,我相信你们平时都是这么用的,这难道有什么问题?我调整下 handleTask 方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 业务处理
 * @param message 消息内容
 * @author: 青石路
 */
private void handleTask(String message) {
    try {
        // 业务处理
        log.info("处理任务:{}", message);
        int i = 3 / (message.length() % 10);
        if (i == 1) {
            throw new OutOfMemoryError("模拟内存溢出");
        }
        log.info("任务处理结果:{}", i);
    } catch (Exception e) {
        log.error("处理任务失败,异常:", e);
    }
}

启动服务后,队列消费者情况如下

服务启动队列消费者情况
服务启动队列消费者情况

发送消息 a,日志输出如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2024-09-22 20:15:55|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|INFO|20|消费者接收到消息:a
2024-09-22 20:15:55|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|INFO|37|处理任务:a
2024-09-22 20:15:55|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|INFO|42|任务处理结果:3

相当于业务正常处理;我们再发送消息 abcdefghij,日志输出如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2024-09-22 20:17:45|taskMessageListenerContainer-3|com.qsl.rabbit.listener.TaskMessageListener|INFO|20|消费者接收到消息:abcdefghij
2024-09-22 20:17:45|taskMessageListenerContainer-3|com.qsl.rabbit.listener.TaskMessageListener|INFO|37|处理任务:abcdefghij
2024-09-22 20:17:45|taskMessageListenerContainer-3|com.qsl.rabbit.listener.TaskMessageListener|ERROR|44|处理任务失败,异常:
java.lang.ArithmeticException: / by zero
	at com.qsl.rabbit.listener.TaskMessageListener.handleTask(TaskMessageListener.java:38)
	at com.qsl.rabbit.listener.TaskMessageListener.onMessage(TaskMessageListener.java:21)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:975)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:921)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1296)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1202)
	at java.lang.Thread.run(Thread.java:748)

被除数为 0,出现 ArithmeticException

ArithmeticException
ArithmeticException

相当于业务处理出现了 Exception,而我们进行了 catch,所以日志打印也符合我们的代码逻辑,也不会对消费者线程造成影响,队列消费者还是最初的那 3 个

还是那三个消费者
还是那三个消费者

我们发送消息 ab,日志输出如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2024-09-22 20:36:31|taskMessageListenerContainer-1|com.qsl.rabbit.listener.TaskMessageListener|INFO|20|消费者接收到消息:ab
2024-09-22 20:36:31|taskMessageListenerContainer-1|com.qsl.rabbit.listener.TaskMessageListener|INFO|37|处理任务:ab
2024-09-22 20:36:31|taskMessageListenerContainer-1|org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer|ERROR|1268|Consumer thread error, thread abort.
java.lang.OutOfMemoryError: 模拟内存溢出
	at com.qsl.rabbit.listener.TaskMessageListener.handleTask(TaskMessageListener.java:40)
	at com.qsl.rabbit.listener.TaskMessageListener.onMessage(TaskMessageListener.java:21)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:975)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:921)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1296)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1202)
	at java.lang.Thread.run(Thread.java:748)
2024-09-22 20:36:31|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|INFO|20|消费者接收到消息:ab
2024-09-22 20:36:31|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|INFO|37|处理任务:ab
2024-09-22 20:36:31|taskMessageListenerContainer-2|org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer|ERROR|1268|Consumer thread error, thread abort.
java.lang.OutOfMemoryError: 模拟内存溢出
	at com.qsl.rabbit.listener.TaskMessageListener.handleTask(TaskMessageListener.java:40)
	at com.qsl.rabbit.listener.TaskMessageListener.onMessage(TaskMessageListener.java:21)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:975)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:921)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1296)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1202)
	at java.lang.Thread.run(Thread.java:748)
2024-09-22 20:36:31|taskMessageListenerContainer-3|com.qsl.rabbit.listener.TaskMessageListener|INFO|20|消费者接收到消息:ab
2024-09-22 20:36:31|taskMessageListenerContainer-3|com.qsl.rabbit.listener.TaskMessageListener|INFO|37|处理任务:ab
2024-09-22 20:36:31|taskMessageListenerContainer-3|org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer|ERROR|1268|Consumer thread error, thread abort.
java.lang.OutOfMemoryError: 模拟内存溢出
	at com.qsl.rabbit.listener.TaskMessageListener.handleTask(TaskMessageListener.java:40)
	at com.qsl.rabbit.listener.TaskMessageListener.onMessage(TaskMessageListener.java:21)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:975)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:921)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1296)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1202)
	at java.lang.Thread.run(Thread.java:748)
2024-09-22 20:36:31|taskMessageListenerContainer-1|org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer|ERROR|1415|Stopping container from aborted consumer
2024-09-22 20:36:31|taskMessageListenerContainer-1|org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer|INFO|646|Waiting for workers to finish.
2024-09-22 20:36:31|taskMessageListenerContainer-1|org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer|INFO|649|Successfully waited for workers to finish.

可以看到,除了我们的业务日志,还有 spring 的日志;从日志可以看出,消息一共被消费了 3 次,但无一例外,都消费失败了,每次失败日志都包括

Consumer thread error, thread abort. Stopping container from aborted consumer

我们再去看下队列消费者情况

消费者无了
消费者无了

我们把这个流程捋一捋

消费者线程 taskMessageListenerContainer-1 收到消息,业务处理的时候 OOM 了,Spring 中止该线程,消息未被手动确认,回到队列等待被消费 消费者线程 taskMessageListenerContainer-2 收到消息,业务处理的时候又 OOM,Spring 中止该线程,消息未被手动确认,回到队列等待被消费 消费者线程 taskMessageListenerContainer-3 收到消息,业务处理的时候扔 OOM,Spring 中止该线程,消息未被手动确认,回到队列等待被消费

全部的 3 个消费者线程都被 Spring 中止了,对应的 3 个队列消费者也就都无了,消息最终回到队列,等待下一个就绪的消费者消费

我们不是 catch 了 Exception 吗,为什么 OutOfMemoryError 还是向上抛给了 Spring ?

OutOfMemoryError
OutOfMemoryError

OutOfMemoryError 是 Error,并不是 Exception,所以我们的代码并不会捕获 OutOfMemoryError,继续往上抛给了 Spring,而

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.AsyncMessageProcessingConsumer#run

中有这么一段代码

Spring对Error处理
Spring对Error处理

publishConsumerFailedEvent 发布一个消费者失败事件,事件处理器收到该事件后会中止该线程;这里就不展开讲了,后续我再写一篇源码,给你们好好介绍下 Spring 的中止逻辑

至此,OutOfMemoryError 会导致消费者线程中止,大家都清楚了吧;细心的小伙伴可能会有这样的疑问了

照理来说,生产中 6 个节点的消费者线程不应该都被中止吗,为什么还剩 2 个节点的消费者?

这 2 个节点内存比较充足,所以 JVM 的堆内存配置的比较大,它们的消费者线程在处理消息的时候,并不会 OOM;而当天正好是业务人员在进行历史大数据量处理,几轮操作下来,把那 4 个内存比较小的节点的消费者全干没了,只剩下那 2 个内存比较大的节点的消费者了

根因其实是 OutOfMemoryError,当前只知道是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString

这个方法导致的,具体原因还待进一步排查

问题处理

因为 OutOfMemoryError 的原因没找到,并且是在操作历史大数据量这种很少出现的场景中触发 OutOfMemoryError,也没有导致服务重启,所以暂定方式是将 ERROR 也捕获

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 业务处理
 * @param message 消息内容
 * @author: 青石路
 */
private void handleTask(String message) {
    try {
        // 业务处理
        log.info("处理任务:{}", message);
        int i = 3 / (message.length() % 10);
        if (i == 1) {
            throw new OutOfMemoryError("模拟内存溢出");
        }
        log.info("任务处理结果:{}", i);
    } catch (Exception | Error e) {
        log.error("处理任务失败,异常:", e);
    }
}

重新启动服务,继续消费队列中那条未被消费的消息 ab,此时日志输出如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2024-09-22 21:38:57|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|INFO|20|消费者接收到消息:ab
2024-09-22 21:38:57|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|INFO|37|处理任务:ab
2024-09-22 21:38:57|taskMessageListenerContainer-2|com.qsl.rabbit.listener.TaskMessageListener|ERROR|44|处理任务失败,异常:
java.lang.OutOfMemoryError: 模拟内存溢出
	at com.qsl.rabbit.listener.TaskMessageListener.handleTask(TaskMessageListener.java:40)
	at com.qsl.rabbit.listener.TaskMessageListener.onMessage(TaskMessageListener.java:21)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:975)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:921)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1296)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1202)
	at java.lang.Thread.run(Thread.java:748)
2024-09-22 21:38:57|main|com.qsl.rabbit.RabbitmqApplication|INFO|61|Started RabbitmqApplication in 1.045 seconds (JVM running for 1.515)

虽然业务处理仍然失败,但只有符合我们代码逻辑的错误日志输出,并没有 Spring 的错误日志,此时队列消费者情况如下

问题处理
问题处理

当然,这只是缓兵之计,最终解决方案还是要分析 OOM 的原因,然后对症下药

总结

  1. 示例代码:spring-boot-rabbitmq
  2. OOM 不一定会导致 JVM 退出,但是 SimpleMessageListenerContainer 会捕获它,然后中止当前线程,对应的队列消费者也就无了
啪,快乐没了
啪,快乐没了
  1. 业务代码 catch Error 虽说只是缓兵之计,但从健壮性考虑的话,也是一个不错的解决办法 但 OOM 的原因还得继续排查,然后对症下药,这才是最终解决之道
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
springboot下使用rabbitMQ之开发配置方式(二)
消息参数传递在开发中也是个坑,不论使用内置的SimpleMessageConverter还是Jackson2JsonMessageConverter均无法让Consumer接收动态参数
上帝
2023/10/16
5920
springboot下使用rabbitMQ之开发配置方式(二)
RabbitMQ 使用细节 → 优先级队列与ACK超时
  说到队列,相信大家一定不陌生,是一种很基础的数据结构,它有一个很重要的特点:先进先出
青石路
2024/02/19
1.1K0
RabbitMQ 使用细节 → 优先级队列与ACK超时
RabbitMQ消息监听异常问题探究「建议收藏」
在使用Spring RabbitMQ做消息监听时,如果监听程序处理异常了,且未对异常进行捕获,会一直重复接收消息,然后一直抛异常。为了更好的描述问题,下面写个简单的例子。
全栈程序员站长
2022/09/22
1K0
RabbitMQ消息监听异常问题探究「建议收藏」
如何解决eclipse远程服务器上面的Rabbitmq连接超时问题?
1、嗯,问题呢,就是一开始安装好RabbitMQ,练习了一下RabbitMQ的使用,但是呢,过了一段时间,我来复习的时候,发现运行出现下面的错误了。后来想想,是自己学习微服务的时候,修改了/etc/h
别先生
2019/11/23
1.6K0
springboot下使用rabbitMQ之开发配置方式(一)
本次结合着B站某MQ视频以及最近在MQ上的实践聊一聊个人在使用rabbitMQ中所得。
上帝
2023/10/16
1.2K0
springboot下使用rabbitMQ之开发配置方式(一)
RabbitMQ日常爬坑分享
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linzhiqiang0316/article/details/91346480
林老师带你学编程
2019/07/02
2.3K0
rabbitmq实际使用案例_沉默的螺旋案例
大家好,又见面了,我是你们的朋友全栈君。 一.发布与订阅模式(队列–>交换机) yml配置: server: port: 8088 spring: rabbitmq: host: 127.0.0.1 port: 5672 username: guest password: guest publisher-confirm-type: correlated #消息确认方式,通过 correlated 来确认(将来的消息中才会带 correlation_
全栈程序员站长
2022/11/10
6950
rabbitmq实际使用案例_沉默的螺旋案例
RabbitMQ学习笔记(四)——RabbitMQ与SpringBoot适配
◆ 异步消息监听容器 ◆ 原生提供RabbitTemplate,方便收发消息 ◆ 原生提供RabbitAdmin,方便队列、交换机声明 ◆ Spring Boot Config原生支持RabbitMQ
不愿意做鱼的小鲸鱼
2022/09/26
1.6K0
RabbitMQ学习笔记(四)——RabbitMQ与SpringBoot适配
Spring Cloud Stream消费失败后的处理策略(一):自动重试
今天第一节,介绍一下Spring Cloud Stream中默认就已经配置了的一个异常解决方案:重试!
程序猿DD
2018/12/27
1.3K0
Rabbitmq延迟队列实现定时任务
开发中经常需要用到定时任务,对于商城来说,定时任务尤其多,比如优惠券定时过期、订单定时关闭、微信支付2小时未支付关闭订单等等,都需要用到定时任务,但是定时任务本身有一个问题,一般来说我们都是通过定时轮询查询数据库来判断是否有任务需要执行,也就是说不管怎么样,我们需要先查询数据库,而且有些任务对时间准确要求比较高的,需要每秒查询一次,对于系统小倒是无所谓,如果系统本身就大而且数据也多的情况下,这就不大现实了,所以需要其他方式的,当然实现的方式有多种多样的,比如Redis实现定时队列、基于优先级队列的JDK延迟队列、时间轮等。因为我们项目中本身就使用到了Rabbitmq,所以基于方便开发和维护的原则,我们使用了Rabbitmq延迟队列来实现定时任务,不知道rabbitmq是什么的和不知道springboot怎么集成Rabbitmq的可以查看我之前的文章Spring boot集成RabbitMQ
搜云库技术团队
2019/10/18
3.5K0
【RabbitMQ分析】01 SimpleMessageListenerContainer原理分析
SimpleMessageListenerContainer是spring在rabbitmq原生api基础上封装实现的一个消费工具类,该类非常强大,可以实现:监听单个或多个队列、自动启动、自动声明,它还支持动态配置,如动态添加监听队列、动态调整并发数等等,基本上对RabbitMQ消费场景这个类都能满足。如@RabbitListener、cloud-stream中StreamListener中底层实现都是基于该类,所以,理解SimpleMessageListenerContainer原理对理解spring rabbitmq中消费模型非常关键。
Reactor2020
2023/03/22
3.5K0
【RabbitMQ分析】01 SimpleMessageListenerContainer原理分析
【Rabbitmq篇】RabbitMQ⾼级特性----消息确认
前期讲了RabbitMQ的概念和应⽤,RabbitMQ实现了AMQP0-9-1规范的许多扩展,在RabbitMQ官⽹上,也给⼤家介绍了RabbitMQ的⼀些特性,我们挑⼀些重要的且常⽤的给⼤家讲⼀下
用户11369558
2024/11/20
5940
【Rabbitmq篇】RabbitMQ⾼级特性----消息确认
rabbitmq动态创建队列
阿超
2023/11/22
4240
SpringBoot 整合 RabbitMQ(包含三种消息确认机制以及消费端限流)
本文 SpringBoot 与 RabbitMQ 进行整合的时候,包含了三种消息的确认模式,如果查询详细的确认模式设置,请阅读:RabbitMQ的三种消息确认模式 同时消费端也采取了限流的措施,如果对限流细节有兴趣请参照之前的文章阅读:消费端限流
海向
2019/09/23
2.5K0
SpringBoot 整合 RabbitMQ(包含三种消息确认机制以及消费端限流)
Springboot 整合RabbitMQ ---基于Class的开发
1 加载配置文件 package com.zjxnjz.mall.core.config; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitAdmin; import
用户5927264
2019/08/01
4790
SpringBoot: RabbitMQ消息队列之同时消费多条消息
basicQos(int prefetchCount) basicQos(int prefetchCount, boolean global) basicQos(int prefetchSize, int prefetchCount, boolean global)
Freedom123
2024/03/29
5030
RabbitMQ与Spring的框架整合之Spring AMQP实战
  RabbitAdmin类可以很好的操作RabbitMQ,在Spring中直接进行注入即可。注意,autoStartup必须设置为true,否则Spring容器不会加载RabbitAdmin类。RabbitAdmin底层实现就是从Spring容器中获取Exchange交换机、Binding绑定、RoutingKey路由键以及Queue队列的@Bean声明。
别先生
2019/12/02
1.7K0
手把手带你Springboot整合RabbitMq ,一篇讲完
该篇文章内容较多,包括有rabbitMq相关的一些简单理论介绍,provider消息推送实例,consumer消息消费实例,Direct、Topic、Fanout的使用,消息回调、手动确认等。(但是关于rabbitMq的安装,就不介绍了)
java进阶架构师
2020/06/16
1.7K0
手把手带你Springboot整合RabbitMq ,一篇讲完
如何使用 Spring 和 RabbitMQ 创建一个简单的发布和订阅应用程序?
原标题:Spring认证中国教育管理中心-了解如何使用 Spring 和 RabbitMQ 创建一个简单的发布和订阅应用程序。(内容来源:Spring中国教育管理中心)
IT胶囊
2022/02/10
2K0
如何使用 Spring 和 RabbitMQ 创建一个简单的发布和订阅应用程序?
【RabbitMQ】如何进行消息可靠投递【上篇】
前几天,突然发生线上报警,钉钉连发了好几条消息,一看是RabbitMQ相关的消息,心头一紧,难道翻车了?
弗兰克的猫
2019/09/29
1.1K1
【RabbitMQ】如何进行消息可靠投递【上篇】
推荐阅读
相关推荐
springboot下使用rabbitMQ之开发配置方式(二)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档