2020-02-25
消息重试
Consumer消费消息失败后,令消息再消费一次。
当消费者主动返回重试码RECONSUMELATER或抛出异常时,服务端会发起消息重试。
消息重投
生产者消息投递失败(网络问题、服务器异常等原因)后,再次投递该消息。
消息重投会造成重复消息。重复消息在RocketMQ中是无法避免的问题。
该如何处理一直重试的消息
对于一直无法消费成功的消息,RocketMQ 会在达到最大重试次数之后,将该消息投递至死信队列。我们需要关注死信队列,并对死信消息业务做人工的补偿操作。
RocketMQ会对重试的消息采用时间衰减策略,每重试一次消息的延迟级别就递增一级。消息的延迟级别有18级,“1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”,当大于最大级别时按最大级别计算。
该如何处理重复消息
RocketMQ 为了保障消息尽可能的投递成功、不丢失,会进行消息重投,所以不能保障消息不重复。对于不能接受重复消息的业务,应该由消费端保证消息的不重复消费。
其实无论是哪种消息队列,造成重复消费原因其实都是类似的。正常情况下,消费者在消费消息时候,消费完毕后,会发送一个确认信息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。只是不同的消息队列发送的确认信息形式不同,RocketMQ会返回一个CONSUME_SUCCESS 成功标志。那造成重复消费的原因?就是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道已经消费过该消息了,再次将该消息分发给其他的消费者。
如何解决?这个问题针对业务场景处理,如:
(1)消息是进行数据库的insert操作。给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
(2)消息是进行redis的set的操作,不用解决,因为无论set几次结果都是一样的,set操作本来就算幂等操作。
(3)其它情况。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。
参考:
网友评论