消息不丢失

- 生产者:发送消息给 Broker,要处理 Broker 的响应,若响应失败则重试发送、报警等,确保 Broker 成功接收消息。
- Broker:接收到消息后**刷盘存储,**然后响应给生产者,如果是集群,那么确保一半写成功。
- 消费者:确保消息拿到并执行完业务逻辑再响应给 Broker。
不重复消费
- 生产者:消息不重复发送,比如确保收到正确的 Broker 响应,那么就可能存在 Broker 已经写入了,当时响应由于网络原因生产者没有收到,然后生产者又重发了一次,此时消息就重复了。
- 消费者:拿到消息消费,业务逻辑已经走完了,事务提交了,更新 offset 时消费者挂了,另一个消费者顶上,此时 offset 还没更新,于是又拿到刚才那条消息再消费一遍。于是消息又重复了。
可以看到正常业务而言消息重复是不可避免的,因此我们只能从另一个角度来解决重复消息的问题。关键点就是幂等。
- version 即版本号控制,对比消息中的版本号和数据库中的版本号。
- 数据库的约束例如唯一键,例如 insert into update on duplicate key… 。
- 比如处理订单这种,记录处理过的订单 ID,假如有重复的消息过来,先判断下这个 ID 是否已经被处理过了,如果没处理再进行下一步。
有序性
有序性即先发送的消息先被消费,实际生产可能因为网络延迟和消息丢失导致无序。
时间戳
在消息中添加时间戳,记录消息的发送时间。消费者可以根据时间戳对消息进行排序,从而保证处理顺序。
缺点:这种方法依赖于生产者和消费者的时间同步,如果时间不同步,可能会导致排序错误。
序列号
在消息中添加序列号,记录消息的发送顺序。消费者可以根据序列号对消息进行排序,从而保证处理顺序。
缺点:如果消息丢失,序列号可能会出现断层,需要额外的机制来处理这种情况。
全局有序

局部有序
比如 kafka,一个 topic 多个分区,单个分区内消息有序,一个分区只能由一个消费者组中的一个消费者消费,保证了有序性、不重复消费。
消息堆积
消息堆积原因:
生产速度与消费速度不匹配。
消息消费失败反复重试,如果是 bug 则处理 bug
消费者消费能力弱:优化下消费逻辑,比如之前是一条一条消费,可以改成批量消费。
假如逻辑我们已经都优化了,但还是慢,那就得考虑水平扩容了,增加 Topic 的队列数和消费者数量, 注意队列数一定要增加,不然新增加的消费者是没东西消费的。一个 Topic 中,一个队列只会分配给一个消费者。