高并发,高可用,多线程,非阻塞中间件

延迟删除保证db,redis一致

2019-02-21  本文已影响22人  赤子心_d709

背景

本文结合一些自己理解,讲解cache miss等情况下如何保证缓存和db的一致性,下面的例子中缓存以redis为例

先redis,redis没有就读db

有几种

1.先更新redis再更新db
2.先更新db再更新redis
3.先更新DB再删除redis
4.先删除redis再更新DB
5.延迟双删
6.延迟删除等变种

各种写场景与db redis一致性

1.先更新redis再更新db

按下面步骤会有问题,AB是两个线程

A_update_redis
B_update_redis
B_update_db
A_update_db

最终db是a值但是redis是b值,不一致

2.先更新db再更新redis

A_update_db
B_update_db
B_update_redis
A_update_redis

最终db是b值但是redis是a值

3.先更新DB再删除redis

A_update_db
B_update_db
B_rm_redis
A_rm_redis

是不是不明白。想不出来怎么不一致了?
不是这样的,没这么简单,第二次rm_redis就会保证后面的redis和db是一致的
实际是下面这种形式

A_get_data
redis_cache_miss
A_get_db
B_update_db
B_rm_redis
(此时如果拿db是b值,但是redis没有值)
A_update_redis

依赖于A_update_redis在B_update_db之后,极端情况
此时redis是old,db是new

4.先删除redis再更新DB

A_rm_redis
B_get_data
B_redis_miss
B_get_db
B_update_redis
A_update_db

此时redis是old值,db是new值

5.延迟双删

rm_redis
update_db
sleep xxx ms
rm_redis

这样叫做双删,最后一次sleep一段时间再rm_redis保证再次读请求回溯打到db,用最新值写redis

6.思考变种

上面的3和5情况可以直接变种,即

update_db
sleep xxx ms
rm_redis

解决了3中的极端情况(靠sleep解决),
并且减少5中第一次不必要的rm redis请求
当然,这个rm_redis还可以考虑异步化(提高吞吐)以及重试(避免异步处理失败),这里不展示

总结

从db回源到redis,需要考虑上面这些极端情况的case

适用场景

当然这些极端情况本身要求同一个key是多写的,这个根据业务需求来看是否需要,比如某些场景本身就是写少读多的

最终从网上看到的延迟双删变种为延迟删除redis也是一种优化

refer

https://my.oschina.net/LucasZhu/blog/1827267
https://blog.csdn.net/hjm4702192/article/details/80518922
https://shidonghua.work/2018/06/05/redis-DB-consistency/

上一篇 下一篇

猜你喜欢

热点阅读