04丨MQ面试问题三连:如何解决消息不丢失、重复消费、积压?(一)

2,377 阅读2分钟

写在前面

大家好,我是爱刨根问底的小明不明,在面试中一旦问道消息队列,消息可靠性投递、重复消费、消息积压几乎是必问,让一起来好好刨一刨这些问题的根吧~

如何确保消息不丢失?

为什么消息会丢失?

image.png

整个消息从生产到消费,哪些地方可能导致丢消息?

生产阶段:消息在Producer中被创建,网络传输到Broker。

存储阶段:消息在Broker存储,若是集群,消息会被复制到其他副本上。

消费阶段:Consumer从Broker拉取消息,网络传输到Consumer上。

总结下来有以下可靠性问题:

  1. 网络传输时的可靠性问题
  2. 存储时的可靠性问题

在主流的消息队列产品中都提供了非常完成的消息可靠性保证机制,确保消息的可靠传递,不丢失消息。

你怎么知道消息丢没丢?

首当其冲的问题其实不是如何保证消息传递的可靠性,而是应该考虑如何知道消息是否丢失。

答案是有序性

原理很简单:

  1. 在Producer端,每个发送的消息添加一个连续递增的序号。
  2. 在Consumer端,若检测到消息序号不连续了,则丢消息了,还可以确定丢的是那一条数据。

分布式提升了消息丢失检查方法的复杂度

在Kafka和RocketMQ中,为了提升并发程度,降低了有序性。从Topic级有序降到了分区级有序。

因此由原来的每个Topic检测消息序号的连续性,降为每个分区单独检测消息序号的连续性。

因此我们要注意:

在Producer端

  1. 我们要指定发送消息的分区
  2. 若有多个Producer实例,每个Producer分别生成各自的消息序号,且附加上Producer标识。

在Consumer端

  1. 按照Producer分表来检测序号的连续性。
  2. Consumer实例数最好和分区数一致,一一对应可以方便Consumer检测序号的连续性。

image.png

怎么确保消息不丢失?

请求确认机制(ACK)解决网络传输时的可靠性问题

image.png

请求确认机制原理

  1. Producer告诉Broker我消息发给你了,你收到了告诉我一声。
  2. Broker收到消息之后给Producer发送,我收到了。

生产阶段和消费阶段发送ACK的时机不同

生产阶段:

  1. 若存储阶段为单机,则Broker将消息写入硬盘之后,再返回ACK。
  2. 若存储阶段为集群,则将消息发送到Broker两个以上节点,再返回ACK。 消费阶段:

Consumer消费掉消息之后,再返回ACK。

总结

image.png