数据库和缓存一致性

数据库和缓存一致性一般分为两类,最终一致性和强一致性。

最终一致性

名词解释:db更新后经过一段时间后要求能访问到更新后的数据,是最终一致性。
适用场景:对于实时性要求不是很高的业务。

方案一:

读取:先从缓存读取,读取不到则读取db,然后写入缓存。

写入/更新/删除:先写db,再写入/更新/删除缓存。

可能遇到的问题:T0时刻请求A读取的时候缓存为空,从db读取数据,T1时刻请求B更新了DB和缓存,T2时刻更新了缓存,T3时刻请求A将老数据写入缓存,此时缓存数据为脏数据。
数据库和缓存一致性_第1张图片

方案二

读取:先从缓存读取,读取不到则读取db,然后写入缓存。

写入/更新/删除:先写入/更新/删除缓存,再更新db。

可能遇到的问题:T0时刻请求A读取的时候缓存为空,从db读取数据,T1时刻请求B删除了缓存,T2时刻请求A将老数据写入缓存,T3时刻请求B更新了缓存,此时缓存数据为脏数据。
数据库和缓存一致性_第2张图片

对于方案一二,既然先更新缓存和数据库都不行,那能否给更新db和缓存的整体操作中加上锁呢,的确可以,但是这样读取也需要加锁,会影响性能,除非是一致性要求很高的场景,不然不建议这样使用。

方案三:

读取:从缓存读取,读取不到则返回空。
写入/更新/删除:更新db再更新缓存,依然会有不同请求造成的并发问题,除非把更新db和缓存的整个操作加锁,不过会有性能问题,而且若更新db成功,更新缓存失败,会有脏数据。

方案四:

读取:从缓存读取,读取不到则返回空。

写入/更新/删除:先更新db,异步消息更新缓存,消息里加上数据更新时间作为版本号,消费者加锁消费消息,缓存数据也存储时间戳,根据时间戳判断是否需要进行更新,若缓存为空则直接写入。

可能遇到的问题:
1.若先更新再删除,消费者先消费到了删除请求,再消费到更新请求,则缓存为脏数据。
2.时间戳精度不够表示版本号。
3.更新db成功,发送消息失败。

解决方案:
1.加上isDel字段,删除操作视为更新操作,只是将isDel字段置为true。待缓存自动过期删除。
2.需要根据业务场景选取字段,或者在db加上版本号。
3.发送消息失败记录消息到本地消息表,定时任务轮询重发。
数据库和缓存一致性_第3张图片

强一致性:

名词解释:对于关系型数据库,要求更新过的数据能被后续的访问都能看到,是强一致性。
适用场景:对于实时性要求比较高的业务。

方案一:

读取:先从缓存读取,读取不到则读取db,然后写入缓存。
写入/更新/删除:先写入/更新/db,再删除缓存。
可能遇到的问题:

1.如图,查询操作在db更新后查询的还是老数据。

数据库和缓存一致性_第4张图片
2.和最终一致性的方案一一样,查询操作查询数据时缓存不存在,从db写入老缓存缓存,导致缓存存在脏数据。
数据库和缓存一致性_第5张图片

方案二:

新增/修改/删除: 将更新db和删除缓存整体操作加锁lock1。
查询:查询时先判断锁lock1是否存在,若锁存在则读取db并返回数据,锁不存在直接查询缓存,若缓存存在则直接返回结果,缓存不存在同样加锁lock1,执行查询db和更新缓存操作,这样可以保证强一致性。
数据库和缓存一致性_第6张图片

你可能感兴趣的:(redis)