RabbitMQ连接池问题
小于 1 分钟
出现消息丢失可能会出现在以下场景:
- 异步发送(验证码,短信,邮件)
- MySQL和Redis,ES之间的数据同步
- 分布式事务
- 削峰消谷
总结为:消息未达到交换机,消息未达到队列,队列中丢失消息,消费者未接收到消息
- 解决办法:生产者确认机制:
生产者确认机制是指生产者发送消息后,需要等待RabbitMQ服务器的确认消息,以确保消息已经被成功地发送到RabbitMQ服务器。如果RabbitMQ服务器没有收到消息或者消息发送失败,生产者会收到一个确认消息,从而可以进行重发或者其他处理。
消息失败之后如何处理呢?
- 回调方法即时重发
- 记录日志
- 保存到数据库然后定时重发,成功发送后即刻删除表中的数据
MQ宕机导致消息丢失:
- 解决办法:消息持久化
MQ默认是内存存储消息,开启持久化可以确保缓存中MQ消息不丢失
主要是交换机,队列,消息持久化
交换机持久化
@Bean public DirectExchange simpleExchange(){ //三个参数分别是:交换机名称,durable是否持久化,autoDelete是否自动删除 return new DirectExchange("simple.direct",true,true); }
队列持久化
@Bean public Queue simpleQueue1(){ //使用QueueBuilder创建队列,durable就是持久化 return QueueBuilder.durable("simple.queue1").build(); }
消息持久化,通过MessageDeliveryMode.PERSISTENT实现
Message message = MessageBuilder .withBody("hello".getBytes(StandardCharsets.UTF_8)) .setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();// 持久化消息
- 解决办法消费者确认机制
RabbitMQ支持消费者确认机制,即:消费者处理消息后可以向MQ发送ack回执,MQ收到ack回执后才会删除该消息。而SpringAMQP.则允许配置三种确认模式:
- manual:手动ack,需要在业务代码结束后,调用api发送ack。
- auto:自动ack,由spring监测listener代码是香出现异常,没有异常则返回ack;抛出异常则返回nack
- none:关闭ack,MQ假定消费者获取消息后会成功处理,因此消息投递后立即被删除
我们可以利用Spring的retry机制,在消费者出现异常时利用本地重试,设置重试次数,当次数达到了以后,如果消息依然失败,将消息投递到异常交换机,交由人工处理
同步与异步对比:
同步:两个人实时打电话,问题:拓展性差,性能下降,级联失败
异步:微信聊天,交互不实时
异步调用模型: