面试官:你是如何保障MySQL数据库与Redis缓存的数据一致性?

什么是数据库与缓存的一致性?

数据一致性?

数据一致性是值:

1)缓存中存有数据,并且该数据在缓存中的数据值=数据库中的数据值。

2)缓存中没有该数据,那么数据库中的值=最新值。

为什么会有一致性问题?

在我们把Redis作为缓存的时候,如果数据需要更改,我们就得经过双写来保证缓存与数据库的数据一致性

如果要保证强一致性的话,势必要引入2PC等分布式一致性协议,或者引入分布式锁等技术,但是这肯定也会对性能有影响,这也违背了我们使用Redis缓存的目的 -- 提高性能

所以我们现在谈的数据库与缓存的一致性问题,该一致性其实指的就是最终一致性

具体策略是什么?

旁路缓存模式

在使用缓存时,现在业务系统最常用的缓存策略是 Cache-Aside 模式(旁路缓存)。下面简单说一下该模式下的读写缓存实践。

读缓存实践

1)先读缓存,命中则返回;未命中则读数据库,然后再将该数据写入缓存。

写缓存实践

1)先写数据库,再操作缓存。

2)直接删除缓存,而不是修改。

值得注意的是,如果缓存的更新成本很高(如涉及访问多张表联合计算),建议直接删除缓存,而不是更新。当然也推荐直接删除缓存

策略提升 -- 延迟双删

在旁路缓存模式下,为了尽可能保证缓存与数据库的最终一致性,我们可以采用延迟双删策略

延迟双删

1)先删除缓存

2)写数据

3)休眠查询一次数据库的时间,再删除缓存。

为什么要两次删除缓存?

在进行第二步写数据的时候,在高并发场景下,很有可能有另一个线程此时在数据库中读取将要删除的数据,而我们第一步已经把缓存删掉了,所以该线程会将读取的脏数据写入缓存,以致于缓存中存入的是脏数据。

第二次删除缓存失败咋办?

为了保证第二次删除缓存成功,我们可以采用重试机制,比如重试3次,如果3次都失败的话则记录日志到数据库并通知人工介入。如果在高并发场景下,重试最好采用异步方式,比如发送消息到MQ中间件,实现异步解藕。

但是引入中间件的话就会对业务代码造成侵入。于是可以采用下一个方案 -- 启动一个专门订阅数据库binlog的服务,用来读取需要删除的数据,然后进行缓存删除操作。

读取binlog异步删除

该方案步骤:

1)更新数据库

2)数据库会把操作信息记录在binlog日志中

3)使用canal订阅binlog日志来获取目标数据

4)缓存删除系统获取canal里的数据,解析目标数据,尝试删除缓存

5)如果缓存删除系统尝试删除缓存失败,则将消息发送到消息队列

6)缓存删除系统重新从消息队列获取数据,再次执行删除操作。

总结

为了尽可能保证数据库与缓存的一致性,我们可以采用延迟双删策略,同时采用异步重试机制来防止第二次删除缓存失败。异步机制我们可以利用MQ消息中间件,或者利用canal订阅数据库binlog日志来监听写请求,然后删除对应数据缓存。

我们没有办法做到强一致性,因为这是由CAP理论决定的,缓存系统适用的场景就是非强一致性的场景,所以它属于CAP中的AP。但是我们可以做到最终一致性。

CAP:C是Consistency(强一致性),A是Availability(可用性),P是Partition tolerance(分区容错性)。在分布式系统中,该系统要么满足AP,要么满足CP,而满足CP的系统的性能一般不是很高。

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值