缓存穿透
原因:当请求大量访问数据库中没有的数据,就会导致每次请求都访问数据库。
解决方案1:缓存空数据
解决方案2:布隆过滤器
布隆过滤器基于位图实现
位图:相当于是一个以(bit)位为单位的数组,每个单位存的都是0或1
布隆过滤器作用:检索一个元素是否在集合中
存储数据:例如是索引1,通过多个hash函数计算出hash值,根据计算出的hash值将对应位置处的0改为1
查询数据:继续使用多个hash函数计算出hash值,看对应位置是否是1
缺点:有误判的可能
缓存击穿
原因:给某个热点key设置了过期时间,过期时间突然结束,大量请求来到访问数据库,把数据库给压倒了
解决方案1:添加互斥锁
解决方案2:设置逻辑过期
缓存不设置ttl时间,在对象上增添一个逻辑过期字段
缓存雪崩
原因:缓存在同一时刻大量的key失效或者是redis服务宕机导致大量请求到达数据库,给数据库造成巨大的压力
Redis的双写一致
定义:当修改数据库时也要更新缓存,需要保证数据库数据和缓存数据的一致性
高一致性方案:
延迟双删
回答:
1.要先删除数据库后删除缓存,因为删除缓存的速度比删除数据库的速度快,先删除缓存出现脏数据的概率比先删除数据库出现脏数据的概率大
2.删除两次缓存是为了防止出现脏数据
3.因为数据库一般是主从同步,我们需要延时一会,把主节点的数据同步给从节点
因为可能无法确定延时多长时间,所以依然有脏数据的风险
基于互斥锁
一般情况:在读写操作时加锁只让一个线程来做
优化:存入缓存的数据一般是读多写少
在读的时候使用读写锁,在写的时候用排他锁
允许延迟:
异步通知
Redis的持久化
redis持久化两种方式:1.RDB 2.AOF
RDB
主进程:通过save命令执行RDB,会阻塞所有命令
子进程:通过basave命令执行RDB,不会阻塞所有命令,但是在创建子进程的时候会阻塞
RDB执行原理:
读写操作在内存中进行操作,在Linux系统中任何进程都无法直接操控物理内存,但是操作系统会给进程分配一个虚拟内存,进程可以操控虚拟内存,在主进程中有一个页表里面包含了进程中物理内存和虚拟内存的映射关系,因此进程可以通过操作虚拟内存进而操作物理内存,到时候主进程会复制一个子进程,里面包含了主进程的页表,然后子进程基于页表进行bgsave操作。
当子进程写RDB文件的同时,主进程也接收到用户的请求去修改内存数据可能会出现脏数据
为此fork采用copy-on-write技术。
AOF
AOF缺点:
因为是记录命令,AOF文件会比RDB文件大的多,而且AOF可能会对同一个key执行多次写操作,但是只有最后一次写操作有意义。
解决方法:
redis可以在触发阈值时自动重写AOF文件,阈值可以在redis配置文件中配置
RDB与AOF对比
数据过期策略
定义:
惰性删除
定期删除
redis的过期删除策略:
总结:
数据淘汰策略
定义:
总结
redis实现的分布式锁
redis获取锁命令:
redis释放锁命令:
加锁必须设置锁的过期时间,以防止死锁的问题
Redis实现分布式锁如何合理的控制锁的有效时长:
1.根据业务执行时间预估
2.给锁续期(需要单独开一个线程去给锁续期)
redission实现的分布式锁
redission实现的分布式锁已经包含了给锁续期的功能
图解:redission加锁成功后就可以操作redis了,并且同时会开启一个线程监测分布式锁会每隔(releaseTime/3)的时间做一次续期,该线程就是看门狗机制,其中releaseTime是锁的过期时间,比如分布式锁的过期时间为30s,那么看门狗会每隔10s把分布式锁的过期时间重置为30s
而释放锁需要我们手动的释放并且会通知看门狗取消监听改分布式锁。当另一个线程尝试加锁时,若加锁成功则操作redis,若加锁失败则会在一个while循环中不断尝试获取锁,但是这个循环次数会有一个阈值
redission实现的分布式锁可重入
什么是可重入?
同一个线程可以重复获取锁
图解:key是锁,field是线程标识,value重入次数
如上图代码所示,同一个线程中锁被重复调用,若被重复调用时value次数会加一,当释放锁时不会直接释放而是判断value是否为0,若不为0,value-1,若为0则释放锁。在释放锁前要校验改线程与线程标识是否一样,以防止误删
普通redission实现的分布式锁无法保证主从一致性
解决方案:RedLock(红锁)
缺点:实现复杂,性能差,运维繁琐
优化方案:使用zookeeper实现的分布式锁
Redis集群方案
主从复制
图解:建立多个节点,主节点负责写操作,从节点负责读操作,主节点写完之后会将数据同步给从节点。因为redis数据读多写少,因为多个从节点实现读操作,大大提高了redis并发能力。
主从数据同步原理
主从全量同步原理
图解:
1.从节点执行replicaof命令建立链接,请求与主节点数据同步,并给主节点发送自己的 replid与offset
2.主节点根据replid判断与从节点的replid是否一致,若一致则是第一次建立同步,主节点返回自己的数据版本信息replid和offest给从节点,主节点并且执行bgsave,生成RDB文件并将RDB文件发送给从节点,从节点保存版本信息,并且清空本地数据加载RDB文件实现第一次主从同步。
3.如果replid一致说明不是第一次主从同步,主节点不会发送RDB文件进行同步数据,而是根据repl_baklog文件(记录RDB期间的所有命令)发送给从节点进行数据同步。例如第二次进行数据同步主节点的offset为80,从节点的offset为40,主节点就会把repl_baklog文件中40-80的数据同步给从节点
主从增量同步原理
图解:由于slave重启后再次与主节点同步时一定不是第一次同步,因此同步原理与上述主从同步第二次同步原理相同。