缓存击穿
查询一个不存在的数据时会将请求打入数据库,如果恶意访问就会打崩数据库
解决
1 将不存在的数据也储存在缓存中
2 将redis前面加一个布隆过滤器,把不存在的数据给储存在布隆过滤器中,这样还能节省不少redis的性能
缓存穿透
当一个热点数据过期之后,会有一大堆的相同请求打入数据库,数据库崩溃
解决
1 强一致性 互斥锁
在大量请求打入数据库之前,使用setnx来实现一个互斥锁,只有一个请求可以获取到锁(往redis中成功插入数据)然后获取到数据储存到缓存中,而去他请求不能获取到锁(因为redis中存在该数据而不能插入),于是进入等待,之后在调递归重新参数从redis中获取到数据
2 弱一致性高可用性 逻辑过期
对储存在缓存中的数据没有设置过期时间,之后再获取数据才知道是否过期
先是一个请求获取到互斥锁锁,然后开辟一个线程来进行缓存重构,成功之后释放锁,而主线程可以返回过期的数据,追求的是高可用性,而其他线程再获取锁失败,直接返回过期的数据
缓存雪崩
在同一时间多个数据同时过期,或者redis挂了,那么就会有一堆请求打入数据库,数据库崩溃
双写一致性
不管时先删除缓存在更新数据库或者时先更新数据库在更新缓存在多线程下都会有可能导致缓存和数据库中的数据不同
解决: 延迟双删
将数据插入数据库之前先删除缓存,在更新数据,在等一会再删除缓存,等一会是等主库数据同步到从库
分布式锁
对插入操作加上锁,线程之间串行执行
数据持久化
将redis数据持久化 RDB和AOF
RDB 快照持久化
快照触发机制分save和bgsave俩种
save:会阻塞当前redis服务器用来全力备份当前数据,会阻塞当前业务,一般不使用
bgsave :redis中设计RDB的备份都是用的bgsave,他会fork一个子进程来进行数据的备份,同时不会阻塞redis当前的服务
在reids中,操作数据并不是直接操作物理内存,而是有一个逻辑内存叫做页表,他和物理内存进行了映射,备份数据时,会fork主线程为子线程,这时子线程就拥有了和这个主线程相同的页表,他们共同指向了一块物理内存,在通过页来把获取到物理内存上的实际数据,因为页的复制是在内存上的,消耗的时间是纳秒级别的,所以快照持久化复制的速度很非常快,和数据库的影响页不大
但是在复制当前数据快照的时候,也是可以正常操作reids的,那么如果有数据的修改或增加,那么最终储存的就有脏数据了,而为了解决这个问题,在fork时使用的是read-on-write技术,在备份时读取数据正常读取,而在写入数据时,会从缓存中复制一份这个数据,在这个数据上进行修改,在最终备份完缓存之后,在把数据写入到缓存中
AOF 日志持久化
AOF(Append Only File)持久化:以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前已经是主流的redis持久化方案
在实际reids使用中AOF和RDB都有在使用
redis数据过期策略
惰性删除
数据过期时不会立刻删除,而是在下次获取时,发现数据已经过期了,那么在进行删除
定期删除
每个一段时间会对key进行检查,取出一定量的key,并删除其中的过期的key,定期删除又有俩个策略
SLOW模式:默认频率为10hz 0.1秒一次,每次遍历时间不会超过25毫秒,并且可以在配置文件中修改
FAST模式:执行频率不固定,但是俩次之间的间隔不超过2ms,每次删除的时间不会超过1ms
redis缓存淘汰策略
当redis中的内存不够用时,在往里面插入数据,那么reids会按一定的策略来对key进行删除,这种删除的策略叫做内存淘汰
redis提供了8种内存淘汰策略
1 noeviction:如果满了之后在往里面添加数据报错,默认这种策略
2 volatile-ttl:对设置了过期的key进行比较,删除的是ttl最小的,最快过期的key
3 allkeys-random:对所有key进行随机删除
4 volatile-random:对设置ttl的key进行随机删除
5 allkeys-lru:在所有key中,删除最久未使用的key
6 allkeys-lfu:在所有key中,删除使用频率最低的key
7 volatile-lru:在所有设置了ttl的key中,删除最久未使用的
8 volatile-lfu:在所有设置了ttl的key中,删除使用频率最低的
LRU(Least Rencenty Use)算法:最久未使用的数据,lru中有一个优先级队列,数据的优先级是取决于他最久一次使用的时间,当前时间 - 这个时间,越大删除的优先级越高
LFU(Leanst Frequently Use)算法:最少频率使用算法, 纪录的是数据的使用频率,频率越低删除的优先级最高
redis分布式锁
setnx
利用setnx 若存在key则插入失败的机制可以把他当作一个不同服务之间的锁
获取锁 set key value nx time 设置过期时间是防止死锁
释放锁 del key
但是这就有个问题了,锁过期的时间应该如何设置,如果再业务还未执行完毕锁就过期了,那么数据不就出错了
redisson实现分布式锁
获取锁之后,会创建一个线程来监听获取锁的线程状态,并为锁进行续期,每次监听的时间为10秒
并重置锁的过期时间
如果有其他线程获取锁失败,他会进入while循环,不断尝试获取锁