普通业务控制幂等性
1.mysql唯一索引
2.token机制(请求前生成一个token,请求时携带这个token,如果这个token在redis中没有则继续,有则 有请求进行中)
3.mysql悲观锁,乐观锁(推荐使用乐观锁)
4.分布式锁(redis,zookeeper)
问题的原因
我看先来看下整个流程,怎么会出现重复的消息呢?
生产者 -> MQ -> 消费者
1.生产者发送了多条同样的消息到MQ
2.一条消息消费了多次(在生产者只发送了一条消息的情况下,消费者消费完成,再给MQ发生消息确认这条消息消费完成,但是网络异常或服务中断,MQ没有收到确认。此时MQ不会删除此消息,下次再把这条消息给到消费者)
解决方案 生产者重复投递
在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列;
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.messageId(String.valueOf(UUID.randomUUID()));
解决方案 消费者重复消费
在消息消费时,要求消息体中必须要有一个bizId(对于同一业务全局唯一,如支付ID、订单ID、帖子ID等)作为去重和幂等的依据,避免同一条消息被重复消费。
1.新增场景: 拿到消息去数据库新增,添加mysql唯一索引,就会导致主键冲突,避免数据库出现脏数据。
2.修改场景: 让生产者发送消息时,每条消息加一个全局的唯一id,然后消费时,将该id保存到redis里面。消费时先去redis里面查一下有么有,没有再消费。