Redis设计

过期键删除策略

对于过期键值的删除有三种常见的做法

  1. 定时删除。为每一个过期的键创建一个定时器,过期立刻删除。
    优点:及时删除过期键值,释放内存空间
    缺点:如果过期键值较多时,在删除过期键值上占用的CPU较多,而在内存充足的情况下,过期键值其实是不必急着删除的,应该优先把CPU用在处理客户端请求上
  2. 惰性删除。当访问键的时候判断这个键是否已过期,过期就删除。
    优点:对CPU占用最少,不会在删除其他过期的键上花费时间
    缺点:不能及时删除键,释放内存。如果一个过期的键永远没有被访问,那么这个键就不会被删除,无用的垃圾数据会堆积在内存中,造成内存泄露
  3. 定期删除。每隔一段时间遍历一遍所有设置了过期时间的键,删除已过期键。
    优点:相对定时删除,占用的CPU时间更少,相对惰性删除,在执行频率设置合理的情况下也能及时删除过期键,释放内存
    缺点:频率很难设置,设置的过于频繁会退化成定时删除,设置的执行间隔太长,会导致过期键不能及时删除

Redis采用了惰性删除和定期删除,可以在合理使用CPU时间和避免浪费内存空间上取得平衡。另外在定期删除策略上也做了优化,每次执行定期删除会有最大执行时间限制,如果达到时间上限还没执行完会记录当前位置并停止处理,下次从纪录点继续执行

持久化

Redis是内存数据库,当Redis进程退出后,保存在内存中的数据就会丢失。为了解决这个问题,Redis提供了RDB跟AOF两种方式,将数据库状态进行持久化到磁盘中

RDB

RDB文件保存了Redis在某个时间点上的数据库状态,类似于快照,可以使用RDB文件将Redis数据恢复。Redis提供了两个命令生成RDB文件,分别是SAVE跟BGSAVE,区别是SAVE是由服务器进程直接执行,会阻塞服务器,BGSAVE是由子线程执行保存,不会阻塞服务器。
Redis默认设置了多个保存条件,900秒内对数据库修改1次、300秒内对数据库修改10次、60秒内对数据库修改10000次,服务器中有一个周期性执行的serverCron默认每隔100毫秒执行一次,在serverCron执行时检查只要其中任何一个条件得到满足就会执行BGSAVE命令自动保存。
image

AOF

除了RDB外,Redis还提供了AOF持久化功能,区别于RDB是通过直接保存数据库键值,AOF是通过保存服务器执行的写命令来记录数据库状态。当服务器的AOF功能打开的时候,每当服务器进行写操作,都会有对应的写命令记录在AOF的缓冲区中,缓冲区中的数据会根据配置持久化到文件中,目前AOF提供三种持久化的选项,分别是always(将缓冲区所有内容写入并同步到文件)、erverysec(每秒将缓冲区内容写入到文件)、no(由操作系统控制何时同步)
image
使用AOF还原数据库状态流程
image

AOF重写

前面讲到,AOF文件是具体执行的写命令记录,随着执行命令的次数越来越多,AOF文件内容会越来越大,为了解决这个问题,Redis提供了AOF文件重写的功能。通过这个功能,Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库状态相同,但新AOF文件不会包含冗余命令。实现原理是从数据库中读取键当前的值,然后用生成一条命令去代替之前记录这个键值的多条命令。
例如:

实际执行命令
sadd animals "cat"
sadd animals "dog" "panda" "tiger"
srem animal "cat"
sadd animals "lion" "cat"

重写后保存命令
sadd animals "dog" "panda" "tiger" "lion" "cat"

另外AOF重写一般是使用子线程在后台执行,在重写期间服务器仍然继续处理客户端的请求。在重写期间,如果服务端处理的请求导致现有的数据库内容被修改,就会导致服务器当前的数据库状态与重写后的AOF文件保存的数据库状态不一致
image
为了解决这个问题,Redis服务器中设置了AOF重写缓冲区,会将AOF重写期间执行的写命令追加到AOF重写缓冲区中,等子线程重写完成后,再将缓冲区内容追加到AOF文件末尾,保持数据库状态一致

主从复制

Redis的复制功能分为同步和命令传播两个操作:

  • 同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态
  • 命令传播操作则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态
    image

这个复制功能对于初次复制来讲能够很好地完成任务,但是对于断线后重复制来说,有可能从服务器跟主服务器数据只发生了几次变化甚至完全一致,但这个复制却要重新全量的覆盖一遍从服务器,效率非常低。为此Redis在2.8版本后开始,改进了复制功能,适用PSYNC命令代替SYNC命令。

完整重同步和部分重同步

PSYNC命令分为完整重同步和部分重同步两种操作

  • 完整重同步:完整重同步的执行步骤和SYNC命令的执行步骤基本一样,它们都是通过让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步
  • 部分重同步:用于处理断线后重复制情况:当从服务器在断线后重新连接主服务器时,主服务器将一部分最近传播的写命令保存在复制积压缓冲区中,如果从服务器的复制偏移量之后的数据仍然存在复制积压缓冲区中,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态

image
image

哨兵Sentinel

哨兵对redis服务器集群的监听

image
主观下线:Sentinel对redis服务节点默认每秒发送心跳检测节点是否在线,但Redis实例连续向Sentinel返回无效回复,该Sentinel节点会将实例标记为主观下线状态。
客观下线:当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一主服务器的其它Sentinel进行询问,看它们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。当Sentinel从其他Sentinel那里接收到足够数量的已下线判断后,Sentinel就会将主服务判定为客观下线,并对主服务执行故障转移。

执行者选举

Sentinel确认主服务已经客观下线后,会要求其他Sentinel节点将自己设为执行故障转移的节点,其他节点采用抢占的方式,只接受第一个到达的抢占请求,并返回当前节点认可的执行节点ID,通过统计,可以得到最终过半数胜出的领头Sentinel执行故障转移

故障转移

在选举产生出领头Sentinel之后,领头Sentinel将对已下线的主服务器执行故障转移操作,该操作包含以下三个步骤:

  1. 在已下线主服务器属下的所有从服务器中,挑选出一个从服务器,并将其转换为主服务器
  2. 让已下线主服务器属下的所有从服务器改为复制新的主服务器
  3. 将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,它就会成为新的主服务器的从服务器
    image

选择新的主服务器流程

  1. 筛选出在线的从服务器
  2. 根据从服务器的优先级,对从服务器进行排序,选择优先级最高从服务器
  3. 同最高优先级的从服务器,选择复制偏移量最大的从服务器(保存着最新数据)
  4. 以上都相同时,选择服务器运行ID最小的从服务器
posted @ 2023-07-21 16:58  IAyue  阅读(117)  评论(0编辑  收藏  举报