Redis优点
- <key, value>内存,速度快
- 异步保存到磁盘
- 保存多种数据结构(5种),单个value限制1G
Redis数据类型
- String,最基本的类型,可以是任何数据,甚至图片、序列化对象等,最大存储512M
- List,<key, list>,list是一个有序可重复集合,底层是双向链表
- Set,<key, set>,set是一个无序不重复集合,底层是value为空的hash表,就是只有key
- Sorted Set,<key, zset>,zset是一个有序不重复集合,由小到大
- Hash,<key, hash>,hash适用于存储对象,里面有属性和属性值,<key> <filed>:<value>
Redis使用的回收算法
- LRU,最近最少使用淘汰算法
Redis持久化方式
- RDB,在指定的时间间隔内对数据进行快照存储
- AOF,记录每次对服务器的写操作,当服务器重启时执行这些命令
雪崩
- Redis中的很多key失效,同时大量线程到数据库中查询,数据库崩了。主要是因为批量key
- 方式一:防止key同时失效,批量插入key的时候,随机生成保存时间;或者除了固定时间外,加上一个小的随机时间,避免同一时刻失效
- 方式二:集群部署的话,可以将热点数据均匀存储在不同Redis实例中
- 方式三:设置key永远不过期,当有更新操作时,更新缓存,电商首页数据就可以这样子操作
缓存击穿
- Redis中一个key不存在,但是大批量来查这个key,然后到数据库中,数据库也崩了。主要是因为热点数据失效,大量针对热点数据的请求击穿缓存来到数据库
- 方式一:使用互斥锁更新,保证同一个进程中针对同一个数据的请求不会并发请求到DB,减小压力(一个进程中的线程,互斥的查询。感觉不太行,因为一个请求都是一个线程,这样也太慢了,且进程多的话,那也没法法呀,所以觉得不太行,那面试的时候就不要题进程,提线程就好了)
- 方式二:设置热点key不过期
缓存穿透
- 指缓存和数据库中都没有数据,穿得透透的。主要是外部恶意攻击,使用不存在的key来查询(比如用户id),然后缓存和数据库都不命中
- 方式一:对于不存在的key,在其首次访问缓存后,增加<key, value>,其中value为空,然后设置短时过期时间,但是这样会造成比较多value为空的数据
- 方式二:布隆过滤器,如果布隆过滤器中不存在,那么肯定不存在;如果布隆过滤器中存在,也有可能不存在
- 方式三:接口校验,因为正常业务流程中,很少会出现key不存在与数据库,出现了那么主要是外部攻击,所以校验好很重要
主从复制模式
- 指将一台Redis服务器的数据,复制到其他的Redis服务器
- 数据的复制是单向的,只能由主节点到从节点。
- 一旦主节点宕机,从节点作为主节点的备份可以随时顶上来。需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。
- 主节点的写能力和存储能力受到单机的限制
哨兵模式
- 复制的基础上,哨兵实现了自动化的故障恢复
- 其实就是在主从节点和客户端之间增加哨兵节点
- 哨兵模式有两种节点:分别是哨兵节点和数据节点
- 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据
- 数据节点:主节点和从节点都是数据节点
- 一旦发现redis集群出现了问题,比如主节点挂了,从节点会顶上来。但是主节点地址变了,这时候应用服务无感知,也不用更改访问地址,因为哨兵才是和应用服务做交互的
- 主节点挂掉之后,哨兵节点商量好谁是新的主节点,然后通知下去
- 优缺点:
- 主从可以自动切换,解决主节点故障自动恢复
- 较难支持在线扩容,主节点压力依旧大
哨兵模式原理
- 每个哨兵节点都有三个定时任务
- 第一个定时任务: 每个哨兵节点每隔1s向所有的master、slaver、别的哨兵节点发送一个PING命令,作用:心跳检测
- 第二个定时任务: 每个哨兵每隔2s都会向master的__sentinel__:hello这个channel中发送自己掌握的集群信息和自己的一些信息(比如host,ip,run id),这个是利用redis的pub/sub功能,每个哨兵节点都会订阅这个channel,也就是说,每个哨兵节点都可以知道别的哨兵节点掌握的集群信息,作用:信息交换,了解别的哨兵的信息和他们对于主节点的判断
- 第三个定时任务: 每个哨兵节点每隔10s都会向master和slaver发送INFO命令,作用:发现最新的集群拓扑结构
- 如果一个 实例(instance)距离最后一次有效回复 PING命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel标记为 主观下线
- 如果一个 主服务器被标记为 主观下线,那么正在 监视 这个 主服务器 的所有 哨兵节点,要以 每秒一次 的频率确认 该主服务器是否的确进入了 主观下线 状态。
- 如果一个 主服务器 被标记为 主观下线,并且有 足够数量的 哨兵(至少要达到配置文件指定的数量)在指定的 时间范围 内同意这一判断,那么这个该主服务器被标记为 客观下线。
- 当一个 主服务器被 哨兵标记为 客观下线 时,哨兵向 下线主服务器 的所有 从服务器 发送 INFO 命令的频率,会从10秒一次改为 每秒一次(加快了解集群拓扑结构)
- 哨兵和其他 哨兵协商 主节点的状态,如果 主节点处于 SDOWN 状态,则投票自动选出新的主节点。将剩余的 从节点 指向 新的主节点 进行 数据复制。
- 当没有足够数量的 哨兵同意 主服务器 下线时, 主服务器 的 客观下线状态就会被移除。当 主服务器 重新向 哨兵的PING命令返回 有效回复 时,主服务器 的 主观下线状态 就会被移除。
集群模式
- 通过数据分片的方式来进行数据共享问题,同时提供数据复制和故障转移功能。
- 集群的键空间被分割为16384个slots(即hash槽),通过hash的方式将数据分到不同的分片上的,每个分片负责不同的slots区段
- 读请求分配给slave节点,写请求分配给master,数据从master同步到slave,每个master负责不同slots区段
- 新增master时,槽需要重新分配,数据也需要重新迁移,但是服务不需要下线
- 因为集群中的主节点们各自负责一部分槽,客户端不确定key到底会映射到哪个节点上。redis-cluster通过重定向解决这个问题,重定向到目标节点中
- redis集群的重新分片由redis内部的管理软件redis-trib负责执行
- redis提供了进行重新分片的所有命令,redis-trib通过向节点发送命令来进行重新分片
- 故障转移:假如途中红色的节点故障了,此时master3下面的从节点会通过 选举产生一个主节点
为什么是16384个slots
- 每个key通过CRC16校验后对16384取模来决定放置哪个槽
- 16384是2的14次方,也就是14k
- 其实CRC校验后由16位,也就是2的16次方,共65536个值
- 在集群中,每个节点需要保持一个myslots数组来标明自己负责的槽位
- 每秒钟,redis需要发送ping消息作为心跳包,也就是和其他节点相互交流,如果槽位是65536的话,那么myslots数组大,ping的消息里面消息头就很大,浪费带宽
- redis集群主节点基本上不超过1000个,节点多了,那么心跳包携带的信息也就多了,那么网络也拥堵。头信息除了携带myslots数组,还要携带几个其他节点的信息,约为总节点数的1/10,最低3个,所以节点多,心跳包大
- 槽位少,节点少,那么压缩比高。主节点中,通过myslots数组来保存自己所负责的哈希槽,其实myslot是通过bitmap来存储的,如果节点数少,哈希槽多,那么bitmap压缩率低