问题
配置中心的原来实现是先更新DB,再更新cache,这个两个操作加起来不是原子的。无法做到操作的一致性。可能会导致DB 更新成功,cache 失败,会导致
cache中是脏数据。
思考
如何保证这两个操作后数据的一致性?
参考
分布式事务一致性:
* 强一致性 : XA,mysql 支持XA,但是redis不支持,强一致性的方案无法使用。
* 最终一致性 : 保证数据的最终一致性,能够容忍短时间数据的不一致。
修改实现
修改配置后,可以容忍一段时间缓存中数据是旧数据的情况,可以使用最终一致性。
实现一
设计个记录更新表。记录下修改操作。
更新配置可以使用如下伪代码
BEGIN TRANSACTION
update xxx set xx=xx;
INSERT test(xx,'status') VALUES('xxx','0')
COMMIT
后使用定时任务,定时扫描这个记录更新表,使缓存失效。此方案亦可改造成mysql 更新数据+消息队列发送一条异步更新cache的消息。
得注意消息的先后顺序,以及消息的消费的幂等性。
实现二
先更新redis并记录一笔更新操作写入到redis中的list数据类型的队列中,这个使用lua脚本操作。
启动两个线程监听更新队列,备份队列,一个执行写入DB 操作,一个执行检查备份队列中的数据。
线程一将更新队列中的更新log写到DB中。从更新队列中取出数据使用rpoplpush 命令将数据移出队列并push到另一个备份队列。
取出数据后更新DB,若DB 更新成功则删除备份队列中的数据。
线程二检查备份队列,将队列中的数据重新加入到原队列中。
此实现配置表中必须有个版本号,保证处理队列消息的幂等性以及对过期消息丢弃。