保证消息消费的幂等性
消费消息需要考虑:
- 会不会重复消费
- 能不能避免重复消费
- 重复消费了也别造成系统异常
rabbitmq、rocketmq、kafka都可能出现重复消费,因为这个问题不是MQ自身保证的,是开发人员保证的。
何时重复消费?
kafka每个消息写进去,都有个offset,代表其序号,然后Con消费了消息后,每隔一段时间,会把自己消费过的消息的offset提交一下,代表我已消费过,下次我要是重启啥的,你让我继续从上次消费到的offset继续消费。
但若重启系统或直接kill进程再重启,就会导致Con有些消息处理了,但没来及提交offset。重启后,少数消息会再消费。因此设计时,必须考虑到重复消费,即如何保证消息的幂等性?
如有系统,消费一条往DB插一条,要是你一个消息重复两次,你就插入两条,那这数据不就错了?但你要是消费到第二次时,自己判断一下已消费,直接扔了,不就只保留了一条数据!一条数据重复出现两次,DB里就只有一条数据,这就保证了消息的幂等性。
幂等性,就一个数据或一个请求,给你重复来多次,你得确保对应的数据是不会改变的,不能出错。
如何为保证MQ消费的幂等性?
得结合业务,大体思路如下:
- 写DB,先根据主键查,若已有这条数据,就别插入了,update之
- 写redis,那没问题,反正每次都是set,天然幂等
- 其它场景,要让Pro发每条消息时,加个全局唯一id,然后消费到后,先根据该id去redis查下之前是否消费过:
- 没有消费过 就处理,然后这个id写redis
- 消费过了 不处理了,保证不重复处理相同消息
还有比如基于DB的唯一索引保证重复数据不会重复插入多条。