缓存是一种将数据存储在高速缓存中的技术,它可以提高应用程序的性能和响应速度。
1. 高性能(主要目的)
查询耗时,但变化少,又有很多读请求情况下,可以将查询结果放到缓存中。减少对数据库的压力,提升响应速度。
2. 高并发
Mysql对高并发支持不好,单机撑到2kQPS容易告警,所以对于1s上万个请求,会让mysql宕机。缓存功能简单,说白了就是 key-value 式操作,单机支撑的并发量一秒可达几万十几万,单机承载并发量是 mysql 单机的几十倍。
本地缓存
定义:直接运行在应用程序本地的缓存组件
优点:应用程序和cache是在同一个进程内部,请求缓存非常快速,没有过多的网络开销等,在单应用不需要集群支持或者集群情况下各节点无需互相通知的场景下使用本地缓存较合适。
缺点:缓存跟应用程序耦合,多个应用程序无法直接的共享缓存,各应用或集群的各节点都需要维护自己的单独缓存,对内存是一种浪费。
分布式缓存
定义:分布式缓存是指独立的缓存服务,不和任何一个具体的应用耦合,可以独立运行并搭建缓存集群。类似数据库,所有的应用程序都可以连接同一个缓存服务以获取相同的缓存数据。
优点:自身就是一个独立的应用,与本地应用隔离,多个应用可直接的共享缓存。
缺点:优点也就是缺点,因为自身是一个独立的应用,本地节点都需要与其进行通信,导致依赖网络,同时如果缓存服务崩溃可能会影响所有依赖节点(缓存雪崩)。
1.缓存雪崩
定义:大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机。调用时这些接口查询缓存时无数据,去查询数据库,这些请求都指向数据库,数据库压力增大,耗时增加。
解决方案:
模拟测试方法:对多个使用到缓存的接口进行并发调用,设置这些缓存时间已过期(即删除缓存),调用时这些接口查询缓存时无数据,去查询数据库,这些请求都指向数据库,数据库压力增大,耗时增加。
测试通过标准:每个缓存失效的数据都只执行了一次数据库查询并设置缓存,之后请求都命中了缓存。
2.缓存击穿
定义:热点数据过期,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮。
解决方案:
模拟测试方法:对某个 Key 有大量的并发请求,这时从缓存中删除这个 key,再并发访问。
测试通过标准:并发调用接口,缓存失效的那个数据只有一个请求执行了数据库查询并设置缓存,其他查询则命中缓存。其他请求都命中了缓存。
3.缓存穿透
定义:不断发起查询缓存和数据库中都没有的数据,导致压力全部落在数据库,导致数据库压力过大。
解决方案:当数据库查询为空时,将缓存赋值默认值,后续查询都走缓存,减少数据库压力。
模拟测试方法:查询一个根本不存在的数据,缓存层和存储层都不会命中。
测试通过标准:每个不存在的数据都只执行了一次数据库查询并设置缓存,之后请求都命中了缓存,有效防止了缓存穿透问题。
有三种更新方式:
1. 先删除缓存后更新数据库(会造成数据不一致)
在删除缓存未更新数据库前,有读请求更新缓存,从而导致数据库和缓存不一致。
2. Cache Aside(更新数据库后缓存失效)旁路换存储策略
最常用策略,应用程序直接与「数据库、缓存」交互,并负责对缓存的维护
也会发生数据不一致问题,但出现概率不高,原因是缓存的写入通常远快于比数据库写入。实际很难出现B更新完数据库删了缓存,A才更新完缓存清空。
如果业务对缓存命中率有严格的要求,那么可以考虑两种解决方案:
3. Read/Write Through(读穿 / 写穿)策略
该模式把更新DB操作由Cache自己代理,对开发人员更简便。应用认为后端就是个单一存储,而存储自己维护自己的Cache。服务器只和 Cache 沟通,Cache 负责去沟通 DB,把数据持久化。
业界典型代表:Redis(可理解为 Redis 里包含了一个 Cache 和一个 DB)
Read Through 策略
先查询缓存中数据是否存在,如果存在则直接返回,如果不存在,则由缓存组件负责从数据库查询数据,并将结果写入到缓存组件,最后缓存组件将数据返回给应用。
Write Through 策略
4. Write Behind Caching
Write Back(写回)策略在更新数据的时候,只更新缓存,同时将缓存数据设置为脏的,然后立马返回,并不会更新数据库。对于数据库的更新,会通过批量异步更新的方式进行。
优点
1.缓存时间设置合理性。
缓存时间设置,需要根据数据更新的频次合理设置;缓存时间太长会导致用户访问到的数据一直是老的,缓存设置时间太短对数据库访问会比较频繁。所以最好调研清楚实际数据更新的频次,再去设置缓存时间
2.存储逻辑合理性。
①服务端或数据库返回数据正确性。返回异常,不应该缓存;返回数据正常,才需要缓存;
②在缓存数据时,需要考虑查询条件的选择,这通常取决于业务需求和数据访问模式。例如,如果一个系统允许通过歌名或歌手来检索歌曲信息,那么可能需要为每种查询类型分别缓存数据。
3. 缓存读取逻辑合理性。以下是比较合理的逻辑:
有缓存,优先读取缓存;
无缓存,请求接口或查数据库获取数据;并存储缓存;
注意:缓存不命中也需要结合具体业务,比如上面的例子中,如果三位查不到缓存,大多数情况就是没有数据,在我们看来是一种正常的情况,会直接返回空结果,而不会去查数据库,避免造成缓存穿透。
4.缓存更新逻辑
缓存失效后是否会更新缓存的内容
注意:关注过期时间和更新时间的临界点,会不会出现异常情况,比如
5.缓存内容
redis缓存具体内容是否正确、格式(list、string)是否合理、实际每次缓存的数据数是否与需求一致
6.缓存数据重复
同样的数据触发保存缓存逻辑之后,应该只有一条在redis缓存中可以查到,重复缓存会浪费资源
基本功能:
特殊场景
参考:https://mp.weixin.qq.com/s/9YXstvCin7pkmWlk4JI-fA
https://blog.csdn.net/qq_40685200/article/details/124861245