开心一刻

今天好哥们找我借钱
哥们:兄弟,我最近手头紧,能不能借我点...
我:我手头也不宽裕,要不你试试银行贷款或者花呗?
哥们:不行,那个借了要还的
我:...

问题回顾

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

所以问题来了

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

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

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

问题排查

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

Consumer thread error, thread abort.

以及异常堆栈

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 关键依赖

<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

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

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

/**
* @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 方法

/**
* 业务处理
* @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,日志输出如下

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,日志输出如下

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

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

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

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 是 Error,并不是 Exception,所以我们的代码并不会捕获 OutOfMemoryError,继续往上抛给了 Spring,而

org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.AsyncMessageProcessingConsumer#run

中有这么一段代码

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

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

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

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

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

com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString

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

问题处理

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

/**
* 业务处理
* @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,此时日志输出如下

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 会捕获它,然后中止当前线程,对应的队列消费者也就无了

  3. 业务代码 catch Error 虽说只是缓兵之计,但从健壮性考虑的话,也是一个不错的解决办法

    但 OOM 的原因还得继续排查,然后对症下药,这才是最终解决之道

记一次 RabbitMQ 消费者莫名消失问题的排查的更多相关文章

  1. rabbitmq消费者“无故消失”

    hi,all   导读:9月1号17:12左右,发现影子队列存在大量“unacked”(收到了消息,但是还没有手动确认消息)的消息,一段时间后“unacked”的数量没有减少,但是观察消费者端的日志, ...

  2. 记一次RabbitMq 安装和配置坑

    记一次RabbitMq 安装和配置坑 正常情况下安装 先安装erl ,在安装rabbitmq 这个在windows下的安装没什么技巧,按照默认一路下一步就ok.安装好后可以到cmd测试是否安装好. 测 ...

  3. RabbitMQ~消费者实时与消息服务器保持通话

    这个文章主要介绍简单的消费者的实现,rabbitMQ实现的消费者可以对消息服务器进行实时监听,当有消息(生产者把消息推到服务器上之后),消费者可以自动去消费它,这通常是开启一个进程去维护这个对话,它与 ...

  4. RabbitMq消费者在初始配置之后进行数据消费

    RabbitMq消费者在初始配置之后进行数据消费 问题背景 在写一个消费rabbitmq消息的程序是,发现了一个问题,消费者的业务逻辑里面依赖这一些配置信息,但是当项目启动时,如果队列里面有积压数据的 ...

  5. supervisor安装以及监控管理rabbitmq消费者进程

    简介:Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启. 1.安装 apt-get install ...

  6. 通过Nacos配置刷新进行RabbitMQ消费者在线启停

    前提 公司在做一些金融相关业务,某些时候由于数据提供商定期维护或者特殊原因需要暂停某些服务的消费者.之前选用的消息队列技术栈是RabbitMQ,用于微服务之间的消息投递,对于这类需要暂停消费者的场景是 ...

  7. RabbitMQ消费者消失与 java OOM

    原因: 下午先是收到钉钉告警有一个消费者系统任务积压, 当时以为就是有范围上量没有当回事,后来客服群开始反馈说有客户的数据没有生成.这个时候查看mq的后台,发现任务堆积数量还是很多. 这个时候登录一台 ...

  8. 2017年5月11日17:43:06 rabbitmq 消费者队列

    从昨天开始发现个问题,一个接口在本地调用时大部分正常,一旦在生成者打一个断点调试,并且在promotion也打断点的时候会出现没有返回channel的异常,然后消费者就再也消费不了了 16:57:45 ...

  9. Win10系统Start Menu上的图标莫名消失

    今天在工作过程中,突然有测试的同事给我报来一个问题.她是这么描述的“执行完XXX工具之后,在Start Menu找不到图标了.” 针对问题本身: 1,是执行完XXXX工具之后? 2,Start Men ...

  10. RabbitMQ消费者消息权重,

    有的消费者处理速度快,有的消费者处理速度慢,我们想给处理快的多发消息,处理慢的少发消息, 怎么办呢?按照之前的轮询模式,肯定不行的,这里可以检测消息数量,如果消费者正在处理就不给他发 .... def ...

随机推荐

  1. 使用 useRequestURL 组合函数访问请求URL

    title: 使用 useRequestURL 组合函数访问请求URL date: 2024/7/26 updated: 2024/7/26 author: cmdragon excerpt: 摘要: ...

  2. ComfyUI插件:ComfyUI layer style 节点(一)

    前言: 学习ComfyUI是一场持久战,而ComfyUI layer style 是一组专为图片设计制作且集成了Photoshop功能的强大节点.该节点几乎将PhotoShop的全部功能迁移到Comf ...

  3. Jmeter函数助手25-log

    log函数用于记录一条日志并返回其值. String to be logged (and returned):函数会返回该值.控制台也能看到该字符 Log level (default INFO) o ...

  4. 【Java】Collection子接口:其二 Set 组接口

    Collection子接口:其二 Set 组接口 - Set接口是Collection的子接口,Set没有提供额外的方法 - Set集合中不允许包含重复的元素,如果重复添加,只保留最新添加的那一个 - ...

  5. windows11系统NVIDIA显卡驱动自动升级导致2070 Super显卡失效 —— 552.22版本自动升级到560.70版本后2070 Super型号显卡停止工作

    操作系统 Windows11,旧版本显卡驱动是552.22,由于安装的是NVIDIA Geforce Experience后显卡驱动自动升级到560.77版本,然后显卡不再工作. 重新安装显卡驱动56 ...

  6. NVIDIA的OpenUSD是什么? —— Universal Scene Description (USD)

    正如NVIDIA的老黄在2024年的技术大会上的展示一样,NVIDIA公司或许最准确的定义应该是计算机图形学公司,因为不论是NVIDIA搞GPU还是搞通用计算还是搞软件生态以至于现在搞AI搞机器人搞自 ...

  7. 国产深度学习框架吸引用户的一种免费手段——免费GPU时长

    国产的深度学习框架基本成为了一个头部公司的标配了,不论是阿里.百度还是华为都推出了自己的深度学习框架,这几家公司为了吸引用户也都采取了免费使用GPU的活动,但是与阿里.百度的不同,华为是与固定的高校的 ...

  8. 使用django-treebeard实现树类型存储与编辑

    前言 其实之前做很多项目都有遇到跟树相关的功能,以前都是自己实现的,然后前端很多UI组件库都有Tree组件,套上去就可以用. 不过既然用 Django 了,还是得充分发挥一下生态的优势,但是我找了半天 ...

  9. centos 安装 图像识别工具 tesseract-ocr 流程

    (1)首先安装依赖的leptonica库:wget http://www.leptonica.com/source/leptonica-1.72.tar.gztar -xvf leptonica-1. ...

  10. 利用Stream实现简单的等差数列求和

    我们都熟知高斯的故事,认识等差数列也是从这个故事开始的,编程课程为了练习for循环,也在不断的练习这个从1加到100的例子,那么原始的办法是这样的: int sum1 = 0; for (int i ...