深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等

文章目录

  • 上一章
  • 一、Redis为什么这么快
  • 二、Redis 六种淘汰策略
  • 三、 Redis 两种持久化机制
    • 3.1RDB快照持久化
      • 3.1.1 RDB工作原理
      • 3.1.2 RDB 的优点
      • 3.1.3 RDB 的缺点
    • 3.2 AOF
      • 3.2.1AOF的优点
      • 3.2.2 AOF的缺点
    • 3.3 如何选择
      • AOF rewrite
      • Redis 的「混合持久化」
  • 四、主从复制
    • 复制过程
    • 主从复制存在的问题
  • 五、哨兵模式
    • 哨兵的工作原理
    • 简单来讲
  • 六、分片集群:横向扩展_略
  • 下一章

上一章

深入学习Redis_(一)五种基本数据类型、RedisTemplate、RedisCache、缓存雪崩等

一、Redis为什么这么快

  1. Redis 完全基于内存,绝大部分请求是纯粹的内存操作,非常迅速,数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度是 O(1)。
  2. 数据结构简单,对数据操作也简单。
  3. 采用单线程,避免了不必要的上下文切换和竞争条件,不存在多线程导致的 CPU 切换,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有死锁问题导致的性能消耗。
  4. 使用多路复用 IO 模型,非阻塞 IO。

二、Redis 六种淘汰策略

  1. voltile-lru 从已经设置过期时间的数据中中挑选最近最少使用的数据淘汰
  2. voltile-ttl 从已经设置过期时间的数据库中当中挑选将要过期的数据
  3. voltile-random 从已经设置过期时间的数据中任意选择淘汰数据
  4. allkeys-lru 从所有数据中挑选最近最少使用的数据淘汰
  5. allkeys-random 从所有数据中任意选择淘汰的数据
  6. no-eviction 不淘汰数据,若超过最大内存,返回错误信息。

深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第1张图片
LRU 算法实现:
1.通过双向链表来实现,新数据插入到链表头部;
2.每当缓存命中(即缓存 数据被访问),则将数据移到链表头部;
3.当链表满的时候,将链表尾部的数据丢弃。

Redis 4.0 加入了 LFU(least frequency use)淘汰策略,包括 volatile-lfu 和 allkeys-lfu,通过统计访问频率,将访问频率最少,即最不经常使用的 KV 淘汰。

三、 Redis 两种持久化机制

Redis 为了保证效率,数据缓存在了内存中,但是会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件中,以保证数据的持久化。
Redis 的持久化策略有两种:

3.1RDB快照持久化

RDB:快照形式是直接把内存中的数据保存到一个 dump 的文件中,定时保存,保存策略。
默认 Redis 是会以快照"RDB"的形式将数据持久化到磁盘的一个二进制文件 dump.rdb。
RDB(快照持久化)是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置:

#在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 900 1

#在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 300 10

#在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。 
save 60 10000

深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第2张图片

3.1.1 RDB工作原理

当 Redis 需要做持久化时,Redis 会 fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB 文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处是可以 copy-on-write。

3.1.2 RDB 的优点

文件体积小,数据恢复速度也快

3.1.3 RDB 的缺点

丢失数据

3.2 AOF

AOF:把所有的对 Redis 的服务器进行修改的命令都存到一个文件里,命令的集合。Redis 默认是快照 RDB 的持久化方式。
当 Redis 重启的时候,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存。
使用 AOF 做持久化,每一个写命令都通过 write 函数追加到 appendonly.aof 中,配置方式如下:


# appendfsync always  #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘    默认
# appendfsync no     #让操作系统决定何时进行同步

深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第3张图片

AOF 可以做到全程持久化,通过appendonly参数开启。
深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第4张图片
这样 Redis 每执行一个修改数据的命令,都会把它添加到 AOF 文件中,当 Redis 重启时,将会读取 AOF 文件进行重放,恢复到 Redis 关闭前的最后时刻。

3.2.1AOF的优点

数据最全

3.2.2 AOF的缺点

文件体积大,数据恢复速度慢

3.3 如何选择

如果你的业务对于数据丢失不敏感,采用 RDB 方案持久化数据
如果你的业务对数据完整性要求比较高,采用 AOF 方案持久化数据

AOF rewrite

由于 AOF 文件中记录的都是每一次写操作,但对于同一个 key 可能会发生多次修改,我们只保留最后一次被修改的值,是不是也可以?
是的,这就是我们经常听到的「AOF rewrite」,你也可以把它理解为 AOF 「瘦身」。
当AOF文件随着写命令的运行膨胀时,当文件大小触碰到临界时,rewrite会被运行。

rewrite机制:aof里存放了所有的redis 操作指令,当aof文件达到一定条件或者手动bgrewriteaof命令都可以触发rewrite
rewrite之后aof文件会保存keys的最后的状态,清除掉之前冗余的,来缩小这个文件。
自动触发的条件:
long long growth =(server.appendonly_current_size*100/base) - 100;
if (growth >=server.auto_aofrewrite_perc)

在配置文件里设置过:
auto-aof-rewrite-percentage 100 (当前写入日志文件的大小超过上一次rewrite之后的文件大小的百分之100时就是2倍时触发Rewrite)
深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第5张图片

Redis 的「混合持久化」

具体来说,当 AOF rewrite 时,Redis 先以 RDB 格式在 AOF 文件中写入一个数据快照,再把在这期间产生的每一个写命令,追加到 AOF 文件中。因为 RDB 是二进制压缩写入的,这样 AOF 文件体积就变得更小了。
Redis 4.0 以上版本才支持混合持久化。
修改redis.conf配置文件

aof-use-rdb-preamble yes

或者使用命令行的方式:

redis-cli
config set aof-use-rdb-preamble yes

深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第6张图片

四、主从复制

Redis 单节点存在单点故障问题,为了解决单点问题,一般都需要对 Redis 配置从节点,然后使用哨兵来监听主节点的存活状态,如果主节点挂掉,从节点能继续提供缓存功能。
主从配置结合哨兵模式能解决单点故障问题,提高 Redis 可用性。

Redis 服务器分为两类:一类是主数据库(Master),另一类是从数据库(Slave)。
主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。
从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库, 而一个从数据库只能拥有一个主数据库。

复制过程

从节点执行 slaveof[masterIP][masterPort],保存主节点信息。

从节点中的定时任务发现主节点信息,建立和主节点的 Socket 连接。

从节点发送 Ping 信号,主节点返回 Pong,两边能互相通信。

连接建立后,主节点将所有数据发送给从节点(数据同步)。

主节点把当前的数据同步给从节点后,便完成了复制的建立过程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。

主从复制存在的问题

一旦主节点宕机,从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。

主节点的写能力受到单机的限制。

主节点的存储能力受到单机的限制。

原生复制的弊端在早期的版本中也会比较突出,比如:Redis 复制中断后,从节点会发起 psync。

此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时,可能会造成毫秒或秒级的卡顿。

解决方案:哨兵模式

五、哨兵模式

Redis Sentinel(哨兵)主要功能包括主节点存活检测、主从运行情况检测、自动故障转移、主从切换
深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第7张图片
Redis Sentinel(哨兵) 最小配置是一主一从。Redis 的 Sentinel 系统可以用来管理多个 Redis 服务器。
该系统可以执行以下四个任务:
监控:不断检查主服务器和从服务器是否正常运行。

通知:当被监控的某个 Redis 服务器出现问题,Sentinel 通过 API 脚本向管理员或者其他应用程序发出通知。

自动故障转移:哨兵每间隔一段时间,询问 master 是否正常,master 正常回复,表示状态正常,回复超时表示异常,哨兵发现异常,发起主从切换。
它会将与失效主节点是主从关系的其中一个从节点升级为新的主节点,并且将其他的从节点指向新的主节点,这样人工干预就可以免了。

配置提供者:在 Redis Sentinel 模式下,客户端应用在初始化时连接的是 Sentinel 节点集合,从中获取主节点的信息。

哨兵的工作原理

  1. 每个 Sentinel(哨兵) 节点都需要定期执行以下任务:每个 Sentinel 以每秒一次的频率,向它所知的主服务器从服务器以及其他的 Sentinel 实例发送一个 PING 命令。
  2. 如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel 标记为主观下线。
  3. 如果一个主服务器被标记为主观下线,那么正在监视这个服务器的所有 Sentinel 节点,要以每秒一次的频率确认主服务器的确进入了主观下线状态。
  4. 如果一个主服务器被标记为主观下线,并且有足够数量的 Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线
  5. 一般情况下,每个 Sentinel 会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。当一个主服务器被标记为客观下线时,Sentinel 向下线主服务器的所有从服务器发送 INFO 命令的频率,会从 10 秒一次改为每秒一次。
  6. Sentinel 和其他 Sentinel 协商客观下线的主节点的状态,如果处于 SDOWN 状态,则投票自动选出新的主节点,将剩余从节点指向新的主节点进行数据复制
  7. 当没有足够数量的 Sentinel 同意主服务器下线时,主服务器的客观下线状态就会被移除。当主服务器重新向 Sentinel 的 PING 命令返回有效回复时,主服务器的主观下线状态就会被移除。

简单来讲

如果 master 状态正常,但这个哨兵在询问 master 时,它们之间的网络发生了问题,那这个哨兵可能会误判。
我们可以部署多个哨兵,让它们分布在不同的机器上,它们一起监测 master 的状态,流程就变成了这样:

  1. 多个哨兵每间隔一段时间,询问 master 是否正常
  2. master 正常回复,表示状态正常,回复超时表示异常
  3. 一旦有一个哨兵判定 master 异常(不管是否是网络问题),就询问其它哨兵,如果多个哨兵(设置一个阈值)都认为 master 异常了,这才判定 master 确实发生了故障
  4. 多个哨兵经过协商后,判定 master 故障,则发起主从切换
    所以,我们用多个哨兵互相协商来判定 master 的状态,这样一来,就可以大大降低误判的概率。

哨兵协商判定 master 异常后,这里还有一个问题:由哪个哨兵来发起主从切换呢?

答案是,选出一个哨兵「领导者」,由这个领导者进行主从切换。

在选举哨兵领导者时,我们可以制定这样一个选举规则:
每个哨兵都询问其它哨兵,请求对方为自己投票
每个哨兵只投票给第一个请求投票的哨兵,且只能投票一次
首先拿到超过半数投票的哨兵,当选为领导者,发起主从切换。
这个选举的过程就是我们经常听到的:分布式系统领域中的「共识算法」
这个算法还规定节点的数量必须是奇数个,这样可以保证系统中即使有节点发生了故障,剩余超过「半数」的节点状态正常,依旧可以提供正确的结果,也就是说,这个算法还兼容了存在故障节点的情况。

六、分片集群:横向扩展_略

  1. 稳定性:Redis 故障宕机,我们有哨兵 + 副本,可以自动完成主从切换
  2. 性能:读请求量增长,我们可以再部署多个 slave,读写分离,分担读压力
  3. 性能:写请求量增长,但我们只有一个 master 实例,这个实例达到瓶颈怎么办?
    看到了么,当你的写请求量越来越大时,一个 master 实例可能就无法承担这么大的写流量了。
    要想完美解决这个问题,此时你就需要考虑使用「分片集群」了。
    深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第8张图片

深入学习Redis_(二)淘汰策略、持久化机制、主从复制、哨兵模式等_第9张图片

下一章

深入学习Redis_(三)事务、分布式锁、消息队列、延时队列等

你可能感兴趣的:(Redis,面试,redis)