分布式锁-Redisson-缓存和数据库一致性

双写模式:写数据库后,更新缓存。
问题:并发时,1、2两个线程写进入,写完DB后都写缓存,1先进来的,2后进来的,但是2线程写redis比1快,就会导致有暂时的脏数据(1给2的缓存覆盖了)。
解决:通过加锁保证并发读写,写写的时候按顺序排好队。读读无所谓。所以适合使用读写锁。(业务不关心脏数据,允许临时脏数据可忽略)

失效模式:写完数据库后,删缓存,等待下一次查询时,将数据缓存。
问题:网络或者i/o问题导致第三个请求拿到了数据库中数据:db-1,此时第二个请求数据库写更新db-1->db-2已完成,立刻删除缓存,第三个请求(是读请求)又将缓存刷新成第一个请求时的数据

还是会出现脏数据问题:最终不一致性
解决:缓存设置过期时间,定期更新
解决:写数据写时,加分布式的读写锁。

如图:
双写模式(写和写的并发问题)
在这里插入图片描述

失效模式(写和读的并发问题)
在这里插入图片描述
总结(三个解决方案已加粗):

如果是用户纬度数据(订单数据、用户数据),这种并发几率非常小,不用考虑这个问题,缓存数据加上过期时间,每隔一段时间触发读的主动更新即可.

如果是菜单,商品介绍等基础数据,也可以去使用canal订阅binlog的方式 缓存数据+过期时间也足够解决大部分业务对于缓存的要求。

通过加锁保证并发读写,写写的时候按顺序排好队。读读无所谓。所以适合使用读写锁。(业务不关心脏数据,允许临时脏数据可忽略);

补充:
我们能放入缓存的数据本就不应该是实时性、一致性要求超高的。所以缓存数据的时候加上过期时间,保证每天拿到当前最新数据即可。
我们不应该过度设计,增加系统的复杂性
遇到实时性、一致性要求高的数据,就应该查数据库,即使慢点。

我们系统一致性的解决方案是:
1、缓存的所有数据都有过期时间,数据过期下一次查询触发主动更新。
2、读写数据的时候,加上分布式的读写锁。(一定要写少读多情况,不然太影响性能了。读读相等于无锁,读多没事,写少就行)

Guess you like

Origin blog.csdn.net/qq_42969135/article/details/117045172