第八章目录
第八章 Redis
Redis是一个基于内存的key-value存储系统,是一个非关系型数据库
8.1 原理
8.1.1 数据结构
String、hash、list、set、sorted set
8.1.2 Redis 线程模型
单线程异步阻塞的多路复用模型
举例:小曲只雇佣一个快递员,客户送来的快递,小曲按送达地点标注好,然后依次放在一个地方。最后,那个快递员依次的去取快递,一次拿一个,然后开着车去送快递,送好了就回来拿下一个快递。
8.1.3 Redis 持久化
RDB持久化
符合一定条件时redis会将内存中所有数据以二进制方式生成一份副本存储到硬盘上(快照),redis重启时可以通过该副本恢复数据,生成快照时redis进入阻塞状态。
AOF持久化
redis将日志追加到磁盘文件中,redis启动时优先选择从AOF文件恢复数据。由于每次写操作都会记录日志,因此AOF会降低性能,但比起RDB的一次性阻塞式备份数据,AOF消耗的内存和资源更少。AOF文件达到阀值时(或执行bgrewriteaof命令),会重写一次AOF文件,将每个Key只保留最新的value的日志
混合持久化
开启混合持久化后,redis按照正常RDB快照规则生成快照文件,在两次快照期间则通过AOF追加日志到RDB数据后面,因此最终生成的AOF文件是一个以RDB数据开头,多个日志操作结尾的文本文件,新产生的AOF文件会直接覆盖旧的AOF文件。优点:兼具了RDB加载快、数据量小和AOF数据高安全性(日志)的优点,而且也不需要重写过程了。缺点:redis4之前的版本不识别混合AOF文件。
8.1.4 Redis 过期策略
redis采用定期删除+惰性删除的方式清理过期数据
定期删除:每100ms随机抽取部分key检查,如果过期就删除
惰性删除:使用某key时检查该key,如果过期就删除
综上,redis有可能产生过期内存不被清理的情况,解决方案是采用内存淘汰机制
将 maxmemory-policy 设置为allkeys-lru,当内存不足时删除最近最少使用的key
8.1.5 redis的集群原理
8.2 其它
8.2.1 为什么用Redis
高性能共享:当数据需要被多个不同线程/进程/节点频繁读取时,redis基于内存读写效率高
并发缓冲:当多个写请求需要连接其它数据库时,使用redis做一个缓冲,将多个并发连接转化为一次连接
8.2.2 Redis 双写一致性问题
对数据库进行写操作时会产生的redis缓存与数据库数据不一致的问题。
目前流行的是先更新数据库+删除缓存+补偿机制的方案
1.线程A写数据库->线程A写完之后删除缓存->删除失败时将key放入消息队列->外部某个程序定时重试删除
3.线程B读缓存,读不到->线程B读数据库->线程B将读到的数据放入缓存
8.2.3 Redis缓存击穿
由于高并发请求刚好失效的key或黑客攻击导致,后端大量请求redis中不存在的key,一般业务程序在redis不存在缓存时会到数据库中查询,因此这种情况就会导致数据库瞬间并发大量连接,造成数据库崩溃。
解决方案
1.为mysql各表的key设置布隆过滤器,请求mysql前先用布隆过滤器确认一遍,存在才申请(防黑客)
2.使用互斥锁,缓存不存在时向数据库发起带锁的读取请求,其它并发请求获取不到锁则休眠重试读取(防高并发失效)
8.2.4 缓存雪崩
缓存在同一时间大面积失效,此时大量请求失效key,造成数据库高并发连接崩溃。
解决方案
1.缓存预热:根据大数据统计结果提前缓存热门数据(防初启动)
2.同样采用互斥锁
3.过期时间追加随机值