消息队列如何消息不丢失、不重复消费、有序性、消息堆积

消息不丢失

  • 生产者:发送消息给 Broker,要处理 Broker 的响应,若响应失败则重试发送、报警等,确保 Broker 成功接收消息。
  • Broker:接收到消息后**刷盘存储,**然后响应给生产者,如果是集群,那么确保一半写成功。
  • 消费者:确保消息拿到并执行完业务逻辑再响应给 Broker。

不重复消费

  • 生产者:消息不重复发送,比如确保收到正确的 Broker 响应,那么就可能存在 Broker 已经写入了,当时响应由于网络原因生产者没有收到,然后生产者又重发了一次,此时消息就重复了。
  • 消费者:拿到消息消费,业务逻辑已经走完了,事务提交了,更新 offset 时消费者挂了,另一个消费者顶上,此时 offset 还没更新,于是又拿到刚才那条消息再消费一遍。于是消息又重复了。

可以看到正常业务而言消息重复是不可避免的,因此我们只能从另一个角度来解决重复消息的问题。关键点就是幂等

  • version 即版本号控制,对比消息中的版本号和数据库中的版本号。
  • 数据库的约束例如唯一键,例如 insert into update on duplicate key… 。
  • 比如处理订单这种,记录处理过的订单 ID,假如有重复的消息过来,先判断下这个 ID 是否已经被处理过了,如果没处理再进行下一步。

有序性

有序性即先发送的消息先被消费,实际生产可能因为网络延迟和消息丢失导致无序。

时间戳

在消息中添加时间戳,记录消息的发送时间。消费者可以根据时间戳对消息进行排序,从而保证处理顺序。

缺点:这种方法依赖于生产者和消费者的时间同步,如果时间不同步,可能会导致排序错误。

序列号

在消息中添加序列号,记录消息的发送顺序。消费者可以根据序列号对消息进行排序,从而保证处理顺序。

缺点:如果消息丢失,序列号可能会出现断层,需要额外的机制来处理这种情况。

全局有序

局部有序

比如 kafka,一个 topic 多个分区,单个分区内消息有序,一个分区只能由一个消费者组中的一个消费者消费,保证了有序性、不重复消费。

消息堆积

消息堆积原因:

生产速度与消费速度不匹配

消息消费失败反复重试,如果是 bug 则处理 bug

消费者消费能力弱:优化下消费逻辑,比如之前是一条一条消费,可以改成批量消费。

假如逻辑我们已经都优化了,但还是慢,那就得考虑水平扩容了,增加 Topic 的队列数和消费者数量, 注意队列数一定要增加,不然新增加的消费者是没东西消费的。一个 Topic 中,一个队列只会分配给一个消费者。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计