缓存的正确使用方式

缓存概述

缓存在互联网架构中是十分重要的一部分,良好设计的缓存可以有效缓解系统压力,提高系统整体性能。
但是,使用缓存也会提高技术复杂度,一般情况下从两个方面来确认是否需要缓存。

  1. CPU占用高的行为
    某些过程需要消耗大量的cpu资源进行计算,可以根据业务考虑将结果保存缓存。
  2. 数据库访问频繁
    如果系统的访问量十分巨大,全部请求指到数据库中可能会导致连接不够甚至数据库崩溃,那么使用缓存是一种有效的暂时手段。
    注意,这意味着使用缓存可以随意应对高并发数据量,一旦发生缓存雪崩,而后端没有相应的处理方案的话,数据库肯定会陷入超负荷状态。

缓存加速原理

数据库访问数据,磁盘IO,慢
缓存里访问数据,存操作,快
数据库里的热数据,可在缓存冗余一份
先访问缓存,如果命中,能大大的提升访问速度,降低数据库压力

使用基本方法 -Cache Aside 模式

  1. 先访问缓存,如果命中直接返回结果
  2. 如果没命中缓存,去数据库查询结果,返回并保存到缓存中一份记录

如果读没有命中,或者涉及写操作,系统流程将会变得更复杂。

读操作没有命中缓存

image

 

尝试从缓存get数据,结果没有命中
从数据库获取数据,读从库,读写分离
把数据set到缓存,未来能够命中缓存

写操作

写需要修改数据库的值和缓存中的值,那么就会有两种修改方式

  1. 先操作数据库,再写缓存
  2. 先写缓存,再操作数据库

缓存的两种更新方法

  • 更新
  • 淘汰
    相比于更新,淘汰会多一次cache miss。
    更新操作可能会需要额外的IO操作去查库或者重新计算。
    所以在绝大部分场景下,淘汰比更新需要的性能更小,所以推荐直接淘汰,在下次请求cache miss之后再进行操作放入缓存。

先操作缓存还是先操作数据库?

先操作缓存

更新缓存

先更新缓存,然后在缓存设置成功的情况下,如果数据库操作失败,产生了事务不一致。此时缓存与数据库中的数据不一致。

淘汰缓存

先淘汰缓存,在淘汰成功的情况下,再去操作数据库。
问题出在两个线程并发读写的情况下:线程1写操作去修改缓存成功,再去试图写入数据库,即锁表
线程2读操作是在线程1缓存修改成功之后进入,因为cache miss,回去数据库中查询数据。此时有可能出现线程2先读到了还未更新的数据库中数据,最终导致缓存中设置的是还未更新的值,缓存与数据库中的数据不一致,而且出现的几率很高。

 

并发读写导致脏数据

先操作数据库

更新缓存

操作完数据库之后,更新数据库。
并发写的场景下,可能出现两个线程因为时间先后顺序不同导致缓存出现脏数据。
线程1在更新完数据库早于线程2,但是线程2的更新缓存晚于线程1,此时缓存你中的值将会不是最新的值,即缓存中出现脏数据。

 

并发写导致脏数据

淘汰缓存

先操作数据库再淘汰缓存,是所有情况下最为稳妥的方式。
可能出现并发的场景为:线程1读缓存未命中,去数据库中获取到数据之后,然后线程2锁表开始写数据,写完成后将缓存删除,此时线程1再去更新缓存中的值(因为读是读得后再去更新),这时候缓存的数据就是之前的脏数据

 

并发读写导致脏数据

这种场景出现的比较苛刻,要在读失效的前提下,读数据库操作发生在写数据库之前,然后写缓存发生在淘汰缓存之后,因为数据库中读的速度远快于写,读完立即去写入,理论上来说要发生在写完后的操作是十分困难的。

总结

根据上文分析,操作缓存最好使用先操作数据库再淘汰缓存是最好的使用方式。

缓存是通过牺牲强一致性来提高性能的。所以使用缓存提升性能,就是会有数据更新的延迟。这需要我们在设计时结合业务仔细思考是否适合用缓存。然后缓存一定要设置过期时间,这个时间太短太长都不好,太短的话请求可能会比较多的落到数据库上,这也意味着失去了缓存的优势。太长的话缓存中的脏数据会使系统长时间处于一个延迟的状态,而且系统中长时间没有人访问的数据一直存在内存中不过期,浪费内存。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值