redis脑裂问题,边路缓存问题,读穿透和写穿透
查看redis的一些问题。
脑裂问题 https://blog.csdn.net/Elliot\_2b/article/details/90106711
cache aside pattern 边路缓存问题 https://zhuanlan.zhihu.com/p/66462064
读穿透和写穿透
1.redis脑裂问题
-—— 哨兵模式下的脑裂;
-——-集群模式下的脑裂;
异地多活—保证高可用,
完全解决不可能,只能尽最大可能避免
-———主从迁移带来的不一致
(1)什么是redis集群的脑裂
redis的集群脑裂是指因为网络问题,导致redis master节点和redis slave节点和sentinel集群处于不同的网络分区,此时因为sentinel集群无法感知到master的存在,所以讲slave节点提升为master节点,此时存在两个不同的master节点,就像一个大脑分裂成两个
(2)redis集群的脑裂造成的问题
如果客户端还是基于原来的master节点继续写入数据,那么新的master节点吴法同步这些数据,当网络问题解决后sentinel(哨兵)集群将原来的master节点降为slave节点,此时在从新的master中同步数据,将会造成大量的数据流失
(3)解决redis脑裂问题的方案
在redis的配置文件中存在两个参数
min-slaves-to-write 3 //表示连接到master的最小slave数量
min-slaves-max-lag 10 //表示slave连接到master的最大延迟时间
若连接到master的slave数量小于第一个参数,且延迟时间小于等于第二个参数,那么master就会拒绝写请求,配置这两个参数后,若发生集群脑裂,原来的master节点接收到客户端的写入请求会拒绝,就可以减少数据同步之后的数据丢失
2.cache aside pattern 边路缓存问题
-——读数据先找cache,cache没有数据,找数据库,在将数据库查询结果保存在cache。先写DB,再删cache,在同步cache(解决写穿透)
cache aside pattern ——缓存模式,从数据存储区加载到缓存中的数据,这种模式可以提高性能,也有助于保持在缓存中的数据之间的一致性和底层数据存储的数据
在redis中经常使用这种方式保证数据库和缓存双写的数据的一致性
在读数据时,先读缓存,缓存没有,在读数据库,然后取出来放入缓存,同时返回响应;
在更新的时候,先更新数据库,再删除缓存
为什么是删除缓存,不是更新缓存
因为在复杂的缓存场景中,缓存不单单是数据库中直接取出来的值
比如可能更新了某个表的一个字段,然后其对应的缓存,是需要查询另外两个表的数据并进行运算,才能计算出缓存最新的值的。
另外更新缓存的代价有时候是很高的。是不是说,每次修改数据库的时候,都一定要将其对应的缓存更新一份?也许有的场景是这样,但是对于比较复杂的缓存数据计算的场景,就不是这样了。如果你频繁修改一个缓存涉及的多个表,缓存也频繁更新。但是问题在于,这个缓存到底会不会被频繁访问到?
最初级的缓存不一致问题及解决方案
问题:先更新缓存,再删除缓存,若缓存更新失败,会导致数据库是新数据,缓存中是旧数据,数据就出现不一致
解决:先删除缓存,在更新数据库,数据库更新失败,那数据库中的数据是旧数据,缓存中是空的,那么不会出现数据不一致
比较复杂的数据不一致问题及解决
数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改。一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中。随后数据变更的程序完成了数据库的修改
解决:更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个 jvm 内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新读取数据+更新缓存的操作,根据唯一标识路由之后,也发送同一个 jvm 内部队列中。
一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条一条的执行。这样的话,一个数据变更的操作,先删除缓存,然后再去更新数据库,但是还没完成更新。此时如果一个读请求过来,读到了空的缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成。
这里有一个优化点,一个队列中,其实多个更新缓存请求串在一起是没意义的,因此可以做过滤,如果发现队列中已经有一个更新缓存的请求了,那么就不用再放个更新请求操作进去了,直接等待前面的更新操作请求完成即可。
待那个队列对应的工作线程完成了上一个操作的数据库的修改之后,才会去执行下一个操作,也就是缓存更新的操作,此时会从数据库中读取最新的值,然后写入缓存中。
如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回;如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值。
3.读穿透和写穿透—》缓存穿透
—读穿透–》高并发查询,cache无数据,同时多线程穿透cache,进入数据库
—写穿透–》先写入cache,后写入DB
缓存穿透:查询一个根本不存在的数据,缓存层和存储层都不命中,通常处于容错的考虑,如果从存储层差不到数据则不写入缓存层
缓存空对象–
布隆过滤器拦截–
还没有评论,来说两句吧...