Redis篇
缓存三兄弟(穿透,击穿,雪崩)
- 缓存穿透:是指查询一个缓存中不存在的数据,然后会到数据库查,数据库也没有这个数据,那么缓存就不会写入,导致每次查询都会到数据库查
- 解决办法:
- 返回空值
- 使用布隆过滤器,先预热数据库中的数据,放入布隆过滤器,然后查询redis之前先到bitmap中查,查不到直接返回结果
- 缓存击穿:一个热点数据在特点时间失效,然后有大量请求过来,造成数据库压力
- 解决办法
- 第一可以使用互斥锁:当缓存失效时,不立即去load db,先使用如 Redis 的 setnx 去设置一个互斥锁,当操作成功返回时再进行 load db的操作并回设缓存,否则重试get缓存的方法
- 设置逻辑过期时间列,不给key设置过期时间,查询的时候先看数据是否过期,过期则另开一个线程进行数据同步,当前线程正常返回,但是数据不是最新的
- 缓存雪崩:就是在同一时间,大量缓存同时失效,所有查询落在数据库上,导致数据库压力甚至宕机
- 解决办法:给这些缓存设置不同的过期时间或者服务降级
双写一致(MySQL数据如何保证和Redis数据保持一致)
- 允许延迟: 使用mq异步通知来实现最终一致性,原理是更新数据之后,异步通知缓存更改,靠的是MQ的可靠性.
- 强一致: 采用Redisson提供的读写锁,共享锁readLock:其它线程可以进行读操作,排他锁writeLock(底层是setnx),加锁之后会阻塞其它线程
Redis持久化
RDB: 也就是快照,是把缓存中的数据备份到磁盘中,Redis宕机时,读取rdb快照文件恢复数据.
AOF: 追加文件,redis的写操作都会记录在aof文件中,Redis宕机时,读取aof文件,重新执行里面的命令来恢复文件.
区别:
- RDB是二进制文件,占用内存小,恢复数据快,但存在丢失数据可能较多,而aof恢复数据较慢,因为会重新执行命令,但是aof丢失数据风险要小些,另外,我们可以设置aof的刷盘策略,可以设置为每秒批量写入一次命令.
数据过期策略
- 惰性删除: 当设置的key过期时,只有在获取key时,才会删除这个key
- 定期删除:
- SLOW模式: 定时任务,默认执行频率为10hz,每次不超过25ms,频率可以通过redis.conf设置
- FAST模式: 执行频率不固定,但每次间隔不低于2ms,每次耗时不超过1ms
数据淘汰策略
一共八种
-
noenviction: 当内存达到限制的时候,不淘汰任何数据,不可写入任何数据集,所有引起申请内存的命令会报错。
-
allkeys-random: 所有key里面随机淘汰
-
allkeys-lru: 所有key里淘汰最近最少使用的:也就是最近使用时间间隔最长的
-
allkeys-lfu: 淘汰最近使用频率最低的
-
volatile-random: 设置了过期时间的key中随机淘汰
-
volatile-ttl: 设置了过期时间的key中淘汰快要过期的
-
volatile-lru: 设置了过期时间的key中淘汰最近最少使用的
-
volatile-lfu: 根据lfu算法,在设置了过期时间的key中淘汰最近使用频率最低的
分布式锁
实现: 使用的是Redisson实现的,底层是setnx和lua脚本(保证原子性)
控制有效时长: 使用的是Redisson提供的watchdog,它可以给只有锁的线程续期(默认是10秒续期一次)
是否可重入: 可以重入,但要在一个线程,使用hash结构来存储信息和重入次数.
能否解决主从一致: 不能解决,可以使用redLock解决,但是性能太低,如果一定要保证强一致性,可以使用zookeeper提供的分布式锁.
Redis集群
-
主从集群
: 单点Redis并发能力有限,搭建主从集群实现读写分离,一般都是一主多从,主节点写数据,从节点读数据
:主从同步
- 全量同步:
- 从节点请求主节点同步数据
- 主节点判断是否为第一次请求,是第一次就是同步版本信息
- 主节点执行bgsave,生成rdb文件,发送给从节点执行
- 在rdb生成执行期间,如果有请求到主节点,主节点会以命令的方式记录到缓冲区
- 把生成后的命令日志文件发送给从节点进行同步
- 增量同步
- 从节点请求主节点同步数据,主节点判断是不是第一次请求,不是第一次就获取从节点的offset值
- 主节点从命令日志中获取offset值后的数据,发送给从节点进行数据同步
-
哨兵模式
作用: 实现主从集群的监控,自动故障恢复,通知的功能
心跳机制:
- 主观下线: 节点发现实例未在规定时间响应,则认为该实例主观下线
- 客观下线: 超过指定数量的哨兵都认为实例主观下线,则该实例客观下线,指定数量最好超过哨兵实例的一半
哨兵选主规则: 判断从节点slave节点的offset值,越大越优先
一般业务主从(1主1从)+哨兵就可以解决
集群脑裂:主要是由于主从节点在不同的网络分区,使得哨兵没有感知到主节点,从而选举了新的主节点,这样就存在两个master,客户端还会向老的主节点写入注解,当老主节点恢复之后降为从节点,再从新master同步时间,就会丢失数据
解决: 修改redis配置,设置最少的节点数量以及 缩短同步的延迟时间,达不到要求就拒绝请求,可以避免大量数据丢失
3.分片集群
作用:
1.集群中有多个master,每个master保存不同的数据
2.每个master有多个slave节点
3.master直接通过平监测彼此健康状态
4.客户端可以访问任意节点,最终都会转发到正确的节点
存储和读取:
1.引入了哈希槽的概念,Redis集群有16284个哈希槽
2.将16384个哈希槽分配到不同的实例
3.根据key的有效部分(key前面有大括号就是大括号里面的,没有就是key本身)计算哈希值,对16384取余,余数做哈希槽,寻找插槽所在实例
Redis为什么那么快:
- redis是纯内存操作,执行速度快
- 采用单线程,避免非必要的上下文切换(会损坏性能),多线程还有线程安全问题
- 采用I/O多路复用模型,非阻塞IO
- 是用C语言编写的,C语言是一种底层语言,执行效率高