一、 状态机
前提条件:
- 在消费者业务表中存在状态字段,并在消费消息后是变更状态
- 状态流转是单向不可逆的。例如:
status :[1 → 2 → 3 → 4...]
实现方式:
基于数据库乐观锁CAS
方式。例如: update table set status = 2... where status = 1
二、 数据库唯一约束
前提条件:
- 消息消费者在业务表中需要存储
上游业务唯一id
实现方式:
在消息这业务表中加入上游业务唯一id
并设置为唯一约束。
三、消息去重表
前提条件:
- 消息消费者必须存在数据库持久化操作
- 保证消费者对其业务表数据增删改和去重表入库在同一个
Connection
的同一个Transaction
中
实现方式:
- 每个库都需要建立一个消息去重表
- 对
上游业务唯一id
设置唯一约束 - 设置消费时间字段,根据业务场景设置记录有效时间
5d
、7d
、10d
,使用定时任务定时清除过期消费记录 - 在消息消费前,根据
上游业务唯一id
查询消息去重表,存在则直接ACK
;在消费者操作完自身业务后,同时保存消息信息到消息去重表
优化方式:
可以加入redis
缓存层,在查询时查询redis是否存在该上游唯一id
,在消息消费者消息同时存入redis
中,并设置有效期
优点:
相对于方法一、方法二可以使用注解
+ AOP
从业务中解耦,无侵入、统一处理的方案