RabbitMQ 消息丢失 重复消费 集群部署

文章目录

      • 一、什么是RabbitMQ
      • 二、各个消息队列的对比
      • 三、常用概念
          • 1、交换机
          • 2、队列
          • 3、绑定
      • 四、交换机的类型
          • 1、Fanout(广播)
          • 2、Direct (路由键匹配型)
          • 3、Topic (主题匹配型)
      • 五、死信队列
          • 1、死信队列是什么?
          • 2、如何配置死信队列
      • 五、延迟队列
          • 1、给消息加上TTL属性
          • 2、给队列加上TTL属性
          • 3、实现延迟队列
      • 六、消息丢失问题
          • 1、发送者丢失
          • 2、队列丢失
          • 3、消费者丢失
            • (1)自动确认机制
            • (2)手动确认机制
          • 4、重复消费,如何保证消费者消费时的幂等性
      • 十、集群部署
          • 1、普通集群模式
          • 2、镜像队列模式

一、什么是RabbitMQ

rabbitmq是一个消息队列,可以用作进程之间的消息传递,有助于系统之间的解耦,流量削峰,还可以用作实现延迟队列。它有交换机,消息队列的概念,消息生产者先将消息发往交换机,再由交换机按照一定的规则转发到一个或多个队列,消费者通过监听队列进行消费消息。

二、各个消息队列的对比

1、ActiveMQ:在互联网公司生产落地案例较少,无法确认是否可以保障高可用和高并发。
2、RabbitMQ:支持高可用,高并发,且低延迟。在生产落地案例较多,社区活跃度高,支持集群部署(消息的高可用,高并发),有完善便捷的管理端。缺点是基于erlang语言开发,较难维护源码。
3、RocketMQ:阿里开源,支持高并发,高可用,性能好,基于java语言开发,可维护性高。
4、kafka:常用作实时日志采集,实时数据同步。拥有超高吞吐量,在大数据领域运用较多。
RabbitMQ 消息丢失 重复消费 集群部署_第1张图片

三、常用概念

1、交换机

所有的消息都是先投递到交换机,再由交换机分发给各个队列。交换机可以指定消息按什么规则,投递到哪个队列。

2、队列

队列是消息的载体,消息到达队列后,等待消费者的消费。

3、绑定

绑定是指交换机和队列之间的绑定。交换机和队列之间可以通过路由键进行绑定(Routing Key),路由键就是消息从交换机发往哪个队列的规则。

四、交换机的类型

1、Fanout(广播)

当消息到达交换机后,广播到和交换机绑定的所有队列。

2、Direct (路由键匹配型)

当消息到达交换机后,交换机会按照消息携带的路由键,和交换机与队列绑定的路由键进行匹配,匹配通过则发到对应的队列。

3、Topic (主题匹配型)

发送类型是topic的交换机的消息的路由键可以加上通配符,*可以代替一个单词,#可以代替零个或多个单词。
举例如下:

交换机X和队列Q1之间的绑定关系为*.orange.*
交换机X和队列Q2之间的绑定关系为*.*.rabbitlazy.#
如下图:
RabbitMQ 消息丢失 重复消费 集群部署_第2张图片RabbitMQ 消息丢失 重复消费 集群部署_第3张图片RabbitMQ 消息丢失 重复消费 集群部署_第4张图片

五、死信队列

1、死信队列是什么?

“死信”是RabbitMQ中的一种消息机制,当消费者在消费时,如果存在以下情况: (1)消息被否定确认,使用channel.basicNack或channel.basicReject,并且此时requeue属性被这支为false。 (2)消息在队列的存活时间超过设置的生存时间(TTL)时间。 (3)消息队列的消息数量已经超过了队列的最大长队。 那么该消息就会成为“死信”,Dead Letter,该消息会被RabbitMQ进行特殊处理,如果配置了死信队列,那么该消息就会被丢进死信队列中,如果没有配置,则该消息将会被丢弃。

2、如何配置死信队列

死信队列的消息是从业务队列丢到死信队列的,所以需要先配置业务队列,步骤如下:
(1)创建业务交换机,创建业务队列
(2)绑定业务队列到业务交换机上
(3)创建死信交换机,创建死信队列
(4)绑定死信队列到死信交换机上
(5)为业务队列配置死信交换机和路由键

注意:并不是直接声明一个死信队列,然后所有的死信消息都跑到死信队列中去了。而是需要为每个业务队列配置一个死信交换机,同一个项目的死信交换机可以共用一个,然后为每个业务队列分配一个单独的路由key。
死信队列并不是什么特殊的队列,只不过是绑定在死信交换机上的队列,死信交换机也不是什么特殊的交换机,只不过是用来接收普通业务队列中的死信消息的交换机。
特殊点在于为普通业务队列配置死信交换机时,第(5)步,是需要在创建普通队列时指定参数x-dead-letter-exchange和x-dead-letter-routing-key,如下:

//声明业务队列
@Bean("businessQueueB")
public Queue businessQueueB(){
	Map<String,Object> args = new HashMap<>(2);
	args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);//DEAD_LETTER_EXCHANGE为声明的死信交换机,与普通交换机声明一样
	args.put("x-dead-letter-routing-key", DEAD_LETTER_ROUTING_KEY);//到死信交换机的路由键
	return QueueBuilder.durable("BUSINESS_QUEUE_NAME").withArguments(agrs).build();
}

五、延迟队列

TTL(time to live),在rabbitmq中,队列和消息本身都有这个属性,当消息过期后就成了死信,会被清除,但是他们却有着区别。

1、给消息加上TTL属性

代表消息多久过期,但是判断过期是在消息出队列的时候判断的,所以这种方式没有实时做到清除过期的消息,而且当队列存在积压时,过期消息也没有得到及时删除。

2、给队列加上TTL属性

给队列加上TTL属性后,代表消息在队列中存活的最大时间,消息一旦过期就会被删除,存在积压时能有效的及时清除过期的消息。

3、实现延迟队列

TTL属性和死信队列配合使用,就可以实现延迟队列,如下:
(1)首先实现死信队列,但是需要给业务队列加上TTL属性
(2)当业务队列的消息过期后就成了死信,会被丢到死信队列
(3)消费者监听死信队列消费就可以了

六、消息丢失问题

1、发送者丢失

问题描述:发送者丢失是指发送者到交换机,交换机将消息投递到对应的队列这一链路出了问题。
解决机制:开启发送确认模式 ,开启confirm模式后,发送者发送的消息会被指派一个唯一的id,一旦消息被正确投递到队列,就会返回一个正确投递的应答(包含消息的唯一id)给发送者;如果某一环节出错,则会返回一个错误应答给发送者,发送者拿到这个应答可以重试,也可以记录日志或者记录表,用定时任务进行轮询。

2、队列丢失

问题描述:队列丢失是指消息在队列中丢失,一般造成原因是rabbitmq服务挂掉或者宕机了。
解决机制:可以开启持久化机制,当消息到达队列后会持久化到磁盘上。可以和发送确认模式配合使用,当消息投递到对应队列后,进行持久化,持久化完成过后再将正确应答返回给发送者,持久化失败则返回错误应答,发送采取重发等机制。

3、消费者丢失

消费确认机制: 消息消费确认机制分为自动确认机制和手动确认机制。

(1)自动确认机制

自动确认机制是默认的,当消息到达消费者的时候,消费者就会自动向rabbitMQ确认消息已到达,rabbitMQ就会删除队列中已经确认的消息。
存在消息丢失问题:当消费者收到消息后立即确认消息,但是在处理业务的过程中却报错了,导致业务没有被正确处理完,但这个时候消息已经被删除了,也不会重发了,所以此时就造成消息丢失了,解决此问题就需要开启手动确认机制。

(2)手动确认机制

开启手动确认机制,当消息到达消费者后,先执行业务逻辑再进行确认,如果执行业务失败,就否定确认,让rabbitmq重新发送消息。

4、重复消费,如何保证消费者消费时的幂等性

重复消费问题是指消费者在成功消费消息后,队列没有删除消息,队列又将该消息投递给下一个消费者,导致重复消费。那关键点在于为什么队列没有删除消息,正常情况是队列接收到消费者的应答后才会删除消息,但是在应答的途中,由于网络原因导致消费者和rabbitmq之间的连接中断,导致rabbitmq没有收到消费者的应答,所以又选择下一个消费者投递消息。
这里需要注意的是,rabbitmq和消费者之间并没有超时机制,为了保证消息只投递一次,是给足了时间让消费者消费,除非连接断开导致没有收到应答。

十、集群部署

参考文档

1、普通集群模式

队列只存在于被创建的节点上,而其它节点只拥有队列的元数据(队列名和属性),其它节点只做转发,将请求转发到队列所在的队列上。优点在于能够在一定程度上提高并发量。缺点在于不能保障高可用,因为一旦队列所在的节点挂掉了,就丢失了,没有备份。

RabbitMQ 消息丢失 重复消费 集群部署_第5张图片

2、镜像队列模式

镜像节点在集群中的其他节点拥有从队列拷贝,一旦主节点不可用,最老的从队列将被选举为新的主队列。但镜像队列不能作为负载均衡使用,因为每个操作在所有节点都要做一遍。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。

你可能感兴趣的:(JAVA,基础总结复习,java-rabbitmq,rabbitmq,java)