缓存架构设计方案

本文探讨了缓存架构存在的问题,如低利用率和数据不一致,并提出了解决方案。第一版方案通过调整读写策略和设置缓存有效期来提高效率。第二版方案引入删除缓存策略,但面临并发时的数据一致性挑战。最终,第三版和第四版方案通过监听数据库binlog,结合MQ,确保更新与删除缓存的正确性,以解决高并发下的数据一致性问题。同时,文章也涵盖了缓存穿透、缓存击穿和缓存雪崩的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缓存架构设计方案

 

第一版设计方案:应用从redis获取缓存数据,写数据走MySQL通道。定时将mysql数据同步至Redis

存在问题

1、缓存利用率低

redis中的大部分数据,访问频率很低。定时同步过程中,有很大的资源浪费。

2、缓存与数据库数据不一致

redis与数据库经常容易出现数据不一致的情况,只有定时同步后,数据才能保证一致。

问题一解决方案

1、取消mysql定时同步策略,应用读数据完全走redis通道,redis不存在数据,再到mysql中查询数据并更新。redis中存在数据,均为热点数据。

2、缓存设置有效时间,超过时间后,自动清除缓存。redis自动可将非热点数据清除,保证redis中的缓存数据高效性。

由此得出第二版设计方案:

 

第二版设计方案未解决问题2,即缓存与数据库数据不一致问题。为解决缓存不一致问题,最先想到的解决方案为,更新数据库同时更新缓存数据。但是,更新数据库与更新缓存两个动作不可能处于同一个事务中。因此两个动作必有先后。当并发读写时,均可能出现redis与mysql长时间数据不一致的问题。分析过程如下:

1、先更新mysql,后更新redis

假设缓存数据X,线程1为t1,线程2位t2

t1 mysql:x=1

t2 mysql:x=2

t2 redis:x=2

t1 redis:x=1

结果:mysql中数据与redis中数据不一致

2、先更新redis,后更新mysql

t1 redis:x=1

t2 redis:x=2

t2 mysql:x=2

t1 mysql:x=1

结果:mysql中数据与redis中数据不一致

因此,在高并发场景下,不管redis与mysql的更新次序,均可能出现mysql与redis数据长期不一致的结果。采用如下替代方案,更新mysql数据时,不更新redis中的缓存,直接删除该缓存。应用在缓存中找不到数据后,直接到DB中查询,并同步至redis中。

1、先更新DB、后删除缓存

假设缓存数据X,线程1为t1,线程2位t2,缓存中最初不存在x,mysql中x=0

t2 获取mysql:x=0

t1 mysql:x=1

t1 删除x

t2 设置redis:x=0

结果:mysql中数据与redis中数据不一致。

发生条件:1、缓存中最初无x;2、读写并发;3、写数据穿插于读数据步骤之间。条件3发生概率基本为0,因为数据库写数据通常比读数据时间长。

2、先删除缓存、后更新DB

t1 删除x

t2 获取x,缓存找不到x,取mysql:x,

t2 设置redis:x=0

t1 mysql:x=1

结果:mysql中数据与redis中数据不一致

由上述分析发现,优先选择第一种方式:先更新DB、后删除缓存。但是还遗留一个问题,更新DB、删除缓存中第二个步骤可能不成功。

解决方案:mysql数据库记录需要删除缓存,采用异步线程方式,删除缓存。但是,这种方式会导致数据库的压力过大。采用MQ替代数据库,记录需要删除的缓存(第一次未删除缓存成功,再写MQ)。但是mq保存也可能出现失败。为什么不直接放在内存中。因为,进程重启,内存数据就丢失了。

由此,第三版设计图如下:

 

采用监听binlog推送数据至mq方式,可以减小应用代码书写量。第四版设计图如下

 

但是第四版设计方案对应canal、mq的可用性要求高,只要一个出问题,会导致redis不能更新。

缓存常见问题及解决方案

1、缓存穿透

缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。

解决方案:缓存中的key值value可设置为不存在,不存在与空不一样。应用查询到该key值,就不需要访问数据库。

2、缓存击穿

缓存中一个热点key值失效后,同一时间点,大量并发请求发生。此时,有大量请求访问数据库。可能导致数据库崩溃。

解决方案:

1、分布式锁:每个key值,只能有一个线程,能够刷新缓存最新数据。

2、缓存无失效时间,通过程序自动清除无效缓存。解决麻烦,不建议使用。

3、缓存雪崩

如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成缓存雪崩。

解决方案:

1、加锁排队,限流:同一时间内,处理缓存更新的最大线程数预先设定好。

2、缓存层高可用:redis采用cluster模式,建议结合1使用。

3、二级缓存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值