消息丢失
检测消息丢失的方法
- 可以在生产端增加一个连续递增的序号,在消费端检查序号的连续性。
- 大多数消息队列的客户端都支持拦截器,可以在生产者发消息前的拦截器中将序号注入到消息,在消费者收到消息的拦截器中检测序号。
- 由于RocketMQ和Kafka在Topic不保证严格有序,仅在队列或分区中有序,所以序号中要带有分区信息,每个分区单独检测消息序号连续性。
- 如果有多个生产者,则消息序号中还需要带上生产者的的标识。
可能丢消息的地方
- 生产阶段,发消息时正确处理broker返回值或者捕获异常,就可以保证消息不丢失。特别的,异步发送需要在回调方法里检查发送结果。
- 存储阶段,需要通过配置Broker参数来避免因为宕机而丢消息。
对于单个节点的Broker,需要配置在收到消息后,将消息写入磁盘后再给生产者返回确认。对于多个节点的集群,需要配置成至少将消息发送给2个以上节点时,再给生产者返回确认
。 - 消费阶段,要在执行完所有消费逻辑后,再返回消费确认。不要在收到消息时就立即确认。
消息重复
MQTT协议
- 给出了三种传递消息时能够提供的服务质量标准,这三种服务质量从低到高依次是:
- At most once:最多一次,允许丢消息
- At least once:最少一次,不允许丢消息,允许有重复。
- Exactly once:恰好一次,不允许丢也不允许重复。
幂等性
- 在消费端保证操作具有幂等性。
- 比如,利用数据库唯一约束、为更新数据设置前置条件,记录消息全局id并在操作前检查。
消息积压
- 消息积压的直接原因,一定是系统中的某个部分出现了性能问题,来不及处理上游发送的消息,才会导致消息积压
- 发送端性能优化:使用并发或者批量发送。
- 消费端性能优化:优化消费逻辑,或者扩充分区和消费者数量,确保 Consumer 的实例数和分区数量是相等的。
- 注意,不要使用将消息暂存在内存中的方式来提高消费者的吞吐量,这样很容易丢失消息。