Redis 持久化、复制、哨兵、集群随笔

目录

redis持久化

RDB

AOF

redis过期key:

redis复制:

redis哨兵模式:

服务下线、故障转移

故障转移细节

新的主服务器是怎样挑选出来的

redis cluster 集群

 重新分片

ASK错误

复制和故障转移


redis持久化

redis的持久化是分为AOF、RDB两种方式。

RDB

redis数据库生成时间点数据的快照文件。当需要执行save、bgsave操作时,会fork出子进程,子进程去根据当前内存数据生成RDB文件,在创建子进程时,此时redis是停顿状态的,创建好后,生成RDB的过程中,redis主进程正常接受客户端的请求。创建RDB文件,会消耗CPU、内存、磁盘IO的资源(子进程执行数据写入RDB的操作、写入操作中,对时间点原数据的内存备份、写入RDB文件中)。当运行期间命中到配置的生成快照规则,也会触发besave操作,生成快照文件。

优点是:生成文件小、易于启动时的数据载入;缺点是:间隔时间较长,当服务器因异常情况挂掉,会导致距离上一次生成RDB文件后写入的数据丢失。

AOF

redis数据库每次写入会命令追加到aop_buf缓冲区中,根据配置将缓冲区数据落盘,默认是每秒一次。随着时间的增长,AOF内容越来越多,Redis提供了AOF文件重写,通过该功能,可以创建新的AOF文件来代替旧的AOF。新的AOF不会包含冗余的操作,优化合并 写操作(首先从数据库中读取键现在 的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条 命令),在文件体积上通常要小得多。

AOF优点:保存的数据完整,数据库挂掉,只会近一秒的数据丢失。缺点:文件较大、载入花时间较多。

redis过期key:

主要是三种:惰性过期、定期过期、主动过期

惰性过期:查询key时,通过expireIfNeeded函数,若过期,删除,返回空,否则正常返回。redis3.2之前 从服务器不会主动过期key,当查询从服务器仍能查到过期key的值,当主服务器执行过期,并将命令发送到从服务器才会执行删除。需要升级版本解决。

定期过期:默认每秒十次(10hz)执行定时过期,从过期字典中随机拿到20个key,若不存在1/4的可以过期,则此次过期后退出。否则继续执行当前操作,直到未到1/4h或者本次过期打到25ms自动退出。改变hz频率,对应每次执行的最长时间也会改变,每秒最长执行过期操作是250ms。

主动过期:当内存使用打到设置的最大使用数值,触发主动过期,根据设置的过期策略进行过期。

redis复制:

redis2.8之前旧版复制,从服务器向主服务器发送sync命令,主服务器fork子进程,生成RDB文件,期间redis的写操作会在缓冲区记录,当RDB文件生成完成,发送给从服务器,然后再将缓冲区的写操作发送给从服务器,后续正常同步写操作,即可保证主从服务器的数据一致性。当主从出现短时间网络问题恢复后,仍是通过sync全量同步,性能较差,因为主服务器fork子进程生成RDB文件会消耗CPU、内存、磁盘IO的资源,而期间可能只有少部分写操作,只需要将这部分数据同步即可。

redis2.8以上,会发送 PSYNC <runid> <offset>命令,初次发送PSYNC ? -1,主服务器识别出是首次同步,进行fork并创建文件操作,返回时将主服务器的runId返回,后续若存在网络原因需要同步时,会传 服务器的runId和从服务器此刻的偏移量过来,主服务器中存在复制积压缓冲区,队列中默认记录1M的最近的写操作,当主服务器判断是runid一致,且传入的偏移量ID+1的数据存在于缓冲区,会返回给从服务器+continue,进行部分重同步操作,将队列中的后续写操作发送给从服务器,即可保证数据的一致性(优化),若缓冲区不存在,返回+FULLRESYNC,重新全量同步,若返回-ERR说明主服务器低于2.8版本,无法进行部分重同步,进行全量同步。

心跳检测
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令,既可以检测主从服务器检测主从网络状态,又可以检测命令丢失(如果因为网络故障,主服务器传播给从服务器的写命令在半路丢失,那么当从服务器向主服务器发送REPLCONF ACK命令时,主服务
器将发觉从服务器当前的复制偏移量少于自己的复制偏移量,然后主服务器就会根据从服务器提交的复制偏移量,在复制积压缓冲区里面找到从服务器缺少的数据,并将这些数据重新发送给从服务器。)

redis哨兵模式:

sentinel启动后会与master建立两个异步连接,命令连接和订阅连接,通过命令连接向主服务器发送INFO命令,通过返回数据,来得到redis服务器的主从节点信息,这样sentinel就可以直到当前较新的服务器节点信息,通过新增、删除、更新来维护sentinel本身的redis服务器基本信息(IP、端口、偏移量等)。

然后为每个从服务器建立命令连接和订阅连接,通过命令连接获取到从服务器的runId、优先级、偏移量、角色role、主从连接状态等。(为什么有两个连接?

在Redis目前的发布与订阅功能中,被发送的信息都不会保存 在Redis服务器里面,如果在信息发送时,想要接收信息的客户端 不在线或者断线,那么这个客户端就会丢失这条信息。因此,为了 不丢失__sentinel__:hello频道的任何信息,Sentinel必须专门用一个 订阅连接来接收该频道的信息。)

sentinel服务器 每两秒一次通过命令连接向所有主从服务器 发送命令,服务端进行__sentinel__:hello频道的发送当前sentinel服务器的基本信息(运行ID、ip、端口、配置纪元等)。所有sentinel服务器收到订阅消息后,判断runid一致忽略(自己发送的消息),不一致,将此sentinel信息维护到sentinel字典中,这样,所有的sentinel之间就可以完成互相之间的识别、并建立命令连接。

服务下线、故障转移

默认情况下,sentinel会每秒通过命令连接向所有主从服务器sentinel服务器发送ping命令,根据返回判断实例是否下线,

有效回复:实例返回+PONG、-LOADING、-MASTERDOWN三种 回复的其中一种。

·无效回复:实例返回除+PONG、-LOADING、-MASTERDOWN三 种回复之外的其他回复,或者在指定时限内没有返回任何回复。

当在配置文件配置down-after-milliseconds(不仅会被Sentinel 用来判断主服务器的主观下线状态,还会被用于判断主服务器属下 的所有从服务器,以及所有同样监视这个主服务器的其他Sentinel 的主观下线状态)数值的毫秒内仍无有效回复,那么认为实例主观下线,sentinel实例向其他sentinel实例发送SENTINEL is-master-down-by-addr命令,从得到其他实例对主观下线实例的状态反馈,(防止sentinel实例自身网络问题),当返回结果的服务下线数值,达到配置指定的判断客观下线所需的数量时,认为该实例客观下线。

选举leader sentinel:向其他实例发送请求,带着当前sentinel的runid、配置纪元(版本号),去找小弟,当其他从服务器配置纪元一致且未设置过leader sentinel就会将请求的runid作为选举leader,并将结果返回,不论选举是否成功,所有Sentinel 的配置纪元(configuration epoch)的值都会自增一次(如果在给定时限内,没有一个Sentinel被选举为领头Sentinel,那么 各个Sentinel将在一段时间之后再次进行选举,直到选出领头Sentinel为 止。);当某个sentinel选举得到超过一半的支持数,则作为leader sentinel去所有从服务器中选举一个作为主服务器。

故障转移细节

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

在已下线主服务器属下的所有从服务器里面,挑选出一个从服 务器,并将其转换为主服务器。

让已下线主服务器属下的所有从服务器改为复制新的主服务 器。

将已下线主服务器设置为新的主服务器的从服务器,当这个旧 的主服务器重新上线时,它就会成为新的主服务器的从服务器。

目的:就是在已下线主服务器属下的所有从服 务器中,挑选出一个状态良好、数据完整的从服务器

新的主服务器是怎样挑选出来的

领头Sentinel会将已下线主服务器的所有从服务器保存到一个 列表里面,然后按照以下规则,一项一项地对列表进行过滤:

1)删除列表中所有处于下线或者断线状态的从服务器,这可 以保证列表中剩余的从服务器都是正常在线的。

2)删除列表中所有最近五秒内没有回复过领头Sentinel的INFO 命令的从服务器,这可以保证列表中剩余的从服务器都是最近成功 进行过通信的。

3)删除所有与已下线主服务器连接断开超过down-after- milliseconds*10毫秒的从服务器:down-after-milliseconds选项指定了判断主服务器下线所需的时间,而删除断开时长超过down-after- milliseconds*10毫秒的从服务器,则可以保证列表中剩余的从服务 器都没有过早地与主服务器断开连接,换句话说,列表中剩余的从 服务器保存的数据都是比较新的。

之后,领头Sentinel将根据从服务器的优先级,对列表中剩余 的从服务器进行排序,并选出其中优先级最高的从服务器。

如果有多个具有相同最高优先级的从服务器,那么领头 Sentinel将按照从服务器的复制偏移量,对具有相同最高优先级的 所有从服务器进行排序,并选出其中偏移量最大的从服务器(复制 偏移量最大的从服务器就是保存着最新数据的从服务器)。

最后,如果有多个优先级最高、复制偏移量最大的从服务器, 那么领头Sentinel将按照运行ID对这些从服务器进行排序,并选出 其中运行ID最小的从服务器。

redis cluster 集群

redis cluster节点间通过握手、响应握手,完成之间的通信连接,每个节点保存着clusterNode,clusterState信息,便于互相通信、根据哈希槽查找对应服务器及数据等。

clusterNode:记录自己和通信后缓存的其他服务器的状态,比如节点的创建时间、节点的名字、节点当前的配置纪元、节点的IP地址和端口号等等,clusterNode结构的link属性是一个clusterLink结构,该结构保存了连 接节点所需的有关信息,比如套接字描述符,输入缓冲区和输出缓冲区。

slot数组是根据2048个字节维护,对应16384个二进制位,二进制位1说明当前节点。

clusterState:当前节点的视角下,集群目前所处的状态,维护着一个slot数组,当key请求到节点后,根据slot数组的槽对应节点信息来决定,是自己执行,还是返回给客户端moved ip port,让客户端去找目标节点执行,slot数组由16384个项管理,每个数据项指向着一个clusternode结构,从而可以快速找到槽对应的目标节点。slots_to_keys跳跃表来保存槽和键之间。

哈希槽:cluster存在16384个槽,每个节点分配着一部分槽点,一个节点除了会将自己负责处理的槽记录在clusterNode结构的slots 属性和numslots属性之外,它还会将自己的slots数组通过消息发送给集 群中的其他节点,以此来告知其他节点自己目前负责处理哪些槽。

一致性hash算法:其中CRC16(key)语句用于计算键key的CRC-16校验和,而 &16383语句则用于计算出一个介于0至16383之间的整数作为键key的槽号。

客户端向节点发送请求命令图示:

 重新分片

Redis集群的重新分片操作是由Redis的集群管理软件redis-trib负责 执行的,Redis提供了进行重新分片所需的所有命令,而redis-trib则通过 向源节点和目标节点发送命令来进行重新分片操作。

redis-trib对集群的单个槽slot进行重新分片的步骤如下:

1)redis-trib对目标节点发送CLUSTER SETSLOT<slot>IMPORTING<source_id>命令,让目标节点准备好从源 节点导入(import)属于槽slot的键值对。

2)redis-trib对源节点发送CLUSTER SETSLOT<slot>MIGRATING<target_id>命令,让源节点准备好将属于 槽slot的键值对迁移(migrate)至目标节点。

3)redis-trib向源节点发送CLUSTER GETKEYSINSLOT<slot> <count>命令,获得最多count个属于槽slot的键值对的键名(key name)。

4)对于步骤3获得的每个键名,redis-trib都向源节点发送一个 MIGRATE<target_ip><target_port><key_name>0<timeout>命令,将被选 中的键原子地从源节点迁移至目标节点。

5)重复执行步骤3和步骤4,直到源节点保存的所有属于槽slot的键 值对都被迁移至目标节点为止。

6)redis-trib向集群中的任意一个节点发送CLUSTER SETSLOT<slot>NODE<target_id>命令,将槽slot指派给目标节点,这一 指派信息会通过消息发送至整个集群,最终集群中的所有节点都会知道 槽slot已经指派给了目标节点。

涉及多个槽图示

ASK错误

在进行重新分片期间,源节点向目标节点迁移一个槽的过程中,可 能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里 面,而另一部分键值对则保存在目标节点里面。 当客户端向源节点发送一个与数据库键有关的命令,并且命令要处 理的数据库键恰好就属于正在被迁移的槽时:

1、源节点会先在自己的数据库里面查找指定的键,如果找到的话, 就直接执行客户端发送的命令。

2、相反地,如果源节点没能在自己的数据库里面找到指定的键,那 么这个键有可能已经被迁移到了目标节点,源节点将向客户端返回一个 ASK错误,指引客户端转向正在导入槽的目标节点,并再次发送之前想要执行的命令。

ASK错误和MOVED错误都会导致客户端转向,它们的区别在于:

MOVED错误代表槽的负责权已经从一个节点转移到了另一个节 点:在客户端收到关于槽i的MOVED错误之后,客户端每次遇到关于槽 i的命令请求时,都可以直接将命令请求发送至MOVED错误所指向的节 点,因为该节点就是目前负责槽i的节点。

与此相反,ASK错误只是两个节点在迁移槽的过程中使用的一种 临时措施:在客户端收到关于槽i的ASK错误之后,客户端只会在接下

来的一次命令请求中将关于槽i的命令请求发送至ASK错误所指示的节 点,但这种转向不会对客户端今后发送关于槽i的命令请求产生任何影 响,客户端仍然会将关于槽i的命令请求发送至目前负责处理槽i的节 点,除非ASK错误再次出现。

在一般情况下,如果客户端向节点发送一个关于槽i的命令,而槽i 又没有指派给这个节点的话,那么节点将向客户端返回一个MOVED错 误;但是,如果节点的clusterState.importing_slots_from[i]显示节点正在reply("OK")导入槽i,并且发送命令的客户端带有REDIS_ASKING标识,那么节点 将破例执行这个关于槽i的命令一次。

复制和故障转移

Redis集群中的节点分为主节点(master)和从节点(slave),其中 主节点用于处理槽,而从节点则用于复制某个主节点,并在被复制的主 节点下线时,代替下线主节点继续处理命令请求。从节点不提供服务,只用于高可用,当节点主服务器异常时,选举为主节点提供服务。

集群中的每个节点都会定期地向集群中的其他节点发送PING消 息,以此来检测对方是否在线,如果接收PING消息的节点没有在规定 的时间内,向发送PING消息的节点返回PONG消息,那么发送PING消 息的节点就会将接收PING消息的节点标记为疑似下线。

如果在一个集群里面,半数以上负责处理槽的主节点都将某个主节 点x报告为疑似下线,那么这个主节点x将被标记为已下线(FAIL), 将主节点x标记为已下线的节点会向集群广播一条关于主节点x的FAIL消息,所有收到这条FAIL消息的节点都会立即将主节点x标记为已下 线。

故障转移

当一个从节点发现自己正在复制的主节点进入了已下线状态时,从 节点将开始对下线主节点进行故障转移,以下是故障转移的执行步骤:

1)复制下线主节点的所有从节点里面,会有一个从节点被选中。

2)被选中的从节点会执行SLAVEOF no one命令,成为新的主节点。

3)新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽 全部指派给自己。

4)新的主节点向集群广播一条PONG消息,这条PONG消息可以让 集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且 这个主节点已经接管了原本由已下线节点负责处理的槽。

5)新的主节点开始接收和自己负责处理的槽有关的命令请求,故 障转移完成

从节点选举规则:当从服务器客观认为主节点下线,会给集群广播消息,让其他主节点将自己作为主节点,若主节点配置版本一致,且当前纪元未选举过主服务器,会投票请求过来的runid为主服务器,返回投票信息,当从服务器接受处理返回信息,超过半数的主服务器选举后,该从服务器则被选举成功。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旺仔丷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值