代码改变世界

消息队列常见问题

2024-03-27 14:56  Spiderman25  阅读(30)  评论(0)    收藏  举报
  rocketmq kafka rabbitmq
重复消费原因 https://www.cnblogs.com/spiderman25/articles/18088312
  1. 消息发送异常时重复发送
  2. 消费消息抛出异常
  3. 消费者提交offset失败
  4. 服务端持久化offset失败
  5. 主从同步offset失败
  6. 重平衡
  7. 清理长时间消费的消息
  1. 并发很大,可能在规定的时间(session.time.out默认30s)内没有消费完,就会可能导致reblance重平衡,导致一部分offset自动提交失败,然后重平衡后重复消费
  2. 消费者宕机、重启等。导致消息已经消费但是没有提交offset
  1. 消费者应答问题:在消息消费过程中,如果消费者在处理消息后没有正确地发送确认应答(ack),或者由于消费者异常导致应答未发送成功,可能会导致消息在 RabbitMQ 中未被标记为已消费,从而再次被投递给消费者,导致消息重复消费。

  2. 消息重回队列:当消费者处理消息发生异常或超时,消息可能会被重新放回队列,等待下一次消费。如果不对消息进行幂等性处理,可能会导致消息重复消费。

  3. 消费者数量变化:当消费者数量发生变化(如新增或减少消费者),RabbitMQ 可能会重新分配消息给新的消费者,造成消息重复消费的情况。

重复消费解决方法
  1. 消息消费幂等性:保证消费端的业务逻辑具有幂等性,即使同一条消息被消费多次,最终的结果也是一致的。这样即使消息被重复消费,也不会对系统造成影响。

  2. 消息消费状态管理:消费端可以维护一个消费状态表,记录已经消费过的消息 ID 或消费的偏移量等信息。在消费消息之前,可以先查询这个状态表,确保消息没有重复消费。

  3. 消息去重机制:消费端可以实现消息的去重机制,比如利用缓存或数据库记录已经处理过的消息 ID,以避免重复消费相同的消息。

  • 数据库唯一索引
  • 缓存消费过的消息id
  • 确保消费者正确处理消息并发送确认应答。
  • 在消费端实现幂等性处理,确保同一消息多次处理结果相同。
  • 针对消息重复消费场景设计消息去重机制。
  • 合理设置消息的 TTL(Time-To-Live)和重试策略,避免消息长时间存留和重复投递。
数据丢失原因
  1. 消息未成功发送:在消息生产者发送消息时,如果由于网络故障、生产者异常等原因导致消息未成功发送到 RocketMQ 服务器,就会导致数据丢失。

  2. 消息未被正确消费:消息成功发送到 RocketMQ 服务器后,如果消费者消费消息时发生异常或者消费者消费速度跟不上消息的生产速度,会导致消息在消费过程中丢失。

  3. 消息重复覆盖:在某些场景下,当消息的 key 相同并且设置了相同的 key 时,新消息会覆盖之前的消息,这可能导致之前的消息被丢失。

  4. Broker 故障:如果 RocketMQ 的 Broker 节点发生故障,可能导致消息丢失。特别是在同步刷盘模式下,如果主节点宕机,尚未同步完成的消息可能会丢失。

  5. 数据同步问题:在 RocketMQ 集群部署时,如果数据同步出现问题,可能导致消息在不同节点间的数据同步失败,从而导致消息丢失。

  6. 消息超时:如果消息设置了超时时间,并且在超时时间内未被消费者消费,则消息可能会被 RocketMQ 标记为过期而丢失。

  1. https://blog.csdn.net/qq_38871408/article/details/131669727
  2. 未正确配置复制因子:在 Kafka 集群中,如果未正确配置副本的复制因子(replication factor),当主题的副本数不足时,数据可能会因为副本丢失而发生数据丢失。

  3. 未持久化消息:如果 Kafka Broker 配置不正确,导致消息未被持久化到磁盘而只存储在内存中,一旦 Broker 发生故障或重启,未持久化的消息将会丢失。

  4. 消息过期:如果在 Kafka 中设置了消息的过期时间(retention time),消息在超过设定的时间后会被删除,如果消息在此期间未被消费,就会导致数据丢失。

  5. 数据写入失败:在消息生产者发送消息到 Kafka 时,如果网络故障、Producer 故障等原因导致数据写入失败,就会导致数据丢失。Kafka默认ack设置为1,改为-1即可

  6. 消费者提交偏移量失败:Kafka 消费者消费消息后需要提交偏移量(offset)来标记消息已经被消费,如果消费者提交偏移量失败或者提交不准确,可能导致消息被重复消费或丢失。

  7. 硬件故障:硬件故障如磁盘损坏、服务器宕机等情况也可能导致 Kafka 数据丢失。

  1. 未持久化消息:在 RabbitMQ 中,如果消息未被标记为持久化,当 RabbitMQ 服务重启或发生故障时,非持久化的消息会丢失。

  2. 生产者发送消息失败:生产者发送消息到 RabbitMQ 的过程中,如果发生网络故障、生产者异常等情况,可能导致消息丢失。

  3. 消费者消费失败:消费者在消费消息时发生异常,或者消费者应用程序处理消息的过程中发生故障,也可能导致消息丢失。

  4. 队列溢出:如果队列设置了最大长度限制,并且消息数量超过了该限制,新消息将无法进入队列而导致数据丢失。

  5. 集群节点故障:如果 RabbitMQ 部署了集群,当某个节点故障时,可能造成部分数据丢失。特别是在镜像队列(Mirrored Queue)的场景下,需要注意主备节点间的数据同步问题。

  6. 手动删除消息:管理员或者应用程序可能会手动删除消息,如果操作失误或者误删了重要消息,也会导致数据丢失。

数据丢失解决方法
  • 配置合适的消息发送确认机制,确保消息成功发送到 RocketMQ。
  • 消费者消费消息时实现幂等性,防止重复消费导致数据丢失。
  • 配置消息存储策略和消息发送超时时间,避免消息因存储问题或超时而丢失。
  • 定期监控 RocketMQ 集群状态,及时发现问题并处理。
  • 合理设计消息的重试机制,确保消息能够被正确消费。
  • 配置适当的副本复制因子,确保数据有足够的冗余备份。
  • 设置合适的消息保存时间和大小限制,避免消息过期或被自动删除。
  • 定期备份 Kafka 数据,以防止数据丢失。
  • 实现消息生产者和消费者的幂等性,避免重复消息或处理异常导致数据丢失。
  • 监控 Kafka 集群状态,及时发现问题并处理。
  • 确保消息被正确标记为持久化,以便在服务重启时数据不会丢失。
  • 设置合适的队列属性,如持久化、最大长度限制等。
  • 实现消息的可靠发送和消费,处理消息发送和消费过程中的异常情况。
  • 部署 RabbitMQ 高可用集群,确保数据备份和故障恢复能力。
  • 定期备份和监控 RabbitMQ 数据,及时发现问题并处理。
顺序消费方法
  1. 顺序消息模式配置:首先需要在 RocketMQ 中为特定的 Topic 开启顺序消息模式。可以通过设置消息队列选择器(MessageQueueSelector)和消息队列监听器(MessageQueueListener)来实现消息发送和消费的顺序性。

  2. 消息发送端保证有序发送:在发送有序消息时,需要保证同一个业务逻辑的消息发送到同一个 Message Queue 中。可以使用消息队列选择器(MessageQueueSelector)来确保相同业务逻辑的消息发送到同一个队列中。

  3. 消费端实现有序消费:消费端需要根据消息的顺序进行消费,可以通过监听器(MessageListenerConcurrently 或 MessageListenerOrderly)来实现消息的有序消费。对于有序消息,建议使用 MessageListenerOrderly 接口,以确保消息的有序处理。

  4. 控制并发消费者数量:为了确保消息的有序性,需要控制消费者的并发消费数量,避免多个消费者同时消费同一个 Message Queue 中的消息。

  5. 保证消费幂等性:为了应对可能出现的重复消费情况,消费端需要保证消费的幂等性,即使消息重复消费也不会造成数据错误。

发消息时指定key,实现Partitioner类,根据key

算出要放到的分区

  1. 使用单分区:将所有相关的消息发送到同一个分区中,这样可以确保消息在该分区内的顺序性。通过指定消息的 key 来确保相关消息被发送到同一个分区。

  2. 自定义分区器:实现自定义的分区器,根据消息的 key 或其他特定规则将消息发送到指定的分区,确保相关消息被发送到同一个分区,从而保证有序性。

  3. 消费者端顺序处理:在消费端通过控制消费者的数量和顺序消费消息来实现消息的有序处理。

  4. 使用外部存储辅助排序:在消息消费过程中,可以将消息存储到外部存储(如数据库)中,并在消费时按照特定的顺序进行处理。

  1. 单一消费者:一个简单的方法是确保每个队列只有一个消费者。这样可以确保消息按照其发送顺序来处理。

  2. 多个队列,单个消费者:如果需要多个消费者并且要确保有序性,可以设置多个队列,但是只允许一个消费者从这些队列中接收消息。这样就可以确保消息的有序性。

  3. 使用消息的 Sequence Number:在消息的属性中添加序列号(Sequence Number),消费者在接收到消息后可以按照序列号进行排序和处理。

  4. 延迟消费:可以在消息中添加延迟时间,确保消息在特定的时间被消费,从而保证有序性。

  5. 插件扩展:RabbitMQ 社区也有一些插件可以帮助实现有序消息,如 rabbitmq_delayed_message_exchange 插件等。