【Redis】---【选举,渐进式Rehash,Copy On Write】


前言

总结Redis中理论,面试总结

集群选举原理

当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点

  1. slave发现自己的master变为FAIL
  2. 将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST 信息
  3. 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack
  4. 尝试failover的slave收集FAILOVER_AUTH_ACK
  5. 超过半数后变成新Master
  6. 广播Pong通知其他集群节点。

从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票
延迟计算公式:

 DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms

SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举(理论上)。

渐进式Rehash

Redis 默认使用两个全局Hash表X,Y,先使用Hash表X,此时另一个Hash表Y并未分配内存空间。随着HashX的数据增多,会有多个key存入hash table的同一个槽位中,这样就会产生Hash冲突。产生冲突并不是马上进行扩容rehash.而是每个槽位都使用一个链表存储key,数据量的增大,链表会越来越长。
在这里插入图片描述

注意,Hash桶的每个元素记录的是entry中的key和value的指向地址,每个Hash桶及其连续的数组占用的内存空间和存储的数据大小并无关系。

使用负载因子来描述hash table整体的冲突情况

负载因子: loader_factor:哈希表中键值对数量 / 哈希表长度
当hash表中键值对数量很少是,负载因子也会很小。
当负载因子大于1,则说明一定出现了hash冲突,负载因子阅读冲突的键值对越多。

只有满足条件的时候才会进行扩容

  • 没有子线程时(没有执行 BGSAVE 命令或者 BGREWRITEAOF 命令),并且哈希表的负载因子大于等于 1
  • 有子线程时(有执行 BGSAVE 命令或者 BGREWRITEAOF 命令),并且哈希表的负载因子大于等于 5

开始进行Rehash操作:

  1. Hash表Y申请较大的空间,如hash桶数组容量是hash表X的两倍。
  2. 将hash表X中的元素重新计算hash和取模运算,映射到hash表Y中。
  3. 清理hash表X。

以redis存储数据的数量级,并不是一次性的完成整个数据的重新copy。(这样会导致主线程阻塞)

  • 在Rehash开始时,两个Hash表维持一个索引计数器变量 rehashidx , 并将它的值设置为 0 , 表示 rehash 工作正式开始。
  • 在 rehash 进行期间,每次对字典执行添加、删除、查找或者更新操作时,程序除了执行指定的操作以外,还会将HashX上的键值对Rehash到HashY上面,并将rehashidx+1.
  • 随着不断的操作,直至所有的节点数据copy完成;将 rehashidx 属性的值设为 -1 , 表示 rehash 操作已完成。

在这里插入图片描述

渐进式 rehash 的过程中,同时使用HashX,HashY两个表,删除(delete)、查找(find)、更新(update)等操作会在两个哈希表上进行,查找一个键的话, 程序会先在 X里面进行查找, 如果没找到的话, 就会继续到 Y里面进行查找。如果新增键值对,一律会被保存到 Y里面, 而 X则不再进行任何添加操作.

写时复制 Copy On Write

首先在redis进行持久化的时候,执行bgsave或者bgrewriteaof命令就会fork出一个子进程读取数据,从而写到磁盘中。

fork子进程阻塞

fork时并不会一次性拷贝所有内存的数据给到子进程,fork采用操作系统的写时复制(copy-on-write)机制,就是为了避免一次性拷贝大量备份数据给子进程造成的长时间阻塞。但是fork子进程需要拷贝进程必要的数据结构,比如内存页表(虚拟内存和物理内存的映射索引表).拷贝内存页表完成后,子进程与父进程指向相同的内存地址空间,也就是说此时虽然产生了子进程,但是并没有申请与父进程相同的内存大小

在这里插入图片描述

CopyOnWrite实现原理

fork()之后,kernel把父进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷入kernel的一个中断例程。中断例程中,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份

这样可以减少分配和复制资源的瞬时延迟,避免了不必要的资源浪费。但是在QPS较高,父子进程都需要进行大量的写操作,会产生大量的分页错误(页异常中断page-fault)。

  • 如果子进程存在期间,发生了大量的写操作,那可能就会出现很多的分页错误(页异常中断page-fault),这样就得耗费不少性能在复制上。
  • Rehash阶段,写操作是无法避免的。所以Redis在fork出子进程之后,负载因子阈值会提高,减少扩容和ReHash.减少不必要的内存写入操作。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

理论点

  • Redis 迁移过程中同步写入时,如果写的是正在迁移的槽位就会阻塞等待迁移完成。
  • Redis集群重启,不需要重新cluster create,只要重启节点就可以。
  • 3主3从,一个slave和master网络异常,slave发起选举,尽量把节点超时时间设置长避免这种情况。
  • 在重写aof 文件时,刚好有新操作的数据,新操作会存在内存里,等到aof重写完再最加到aof文件的末尾
  • hash冲突后不是马上进行rehash,是redis扩容后之前的元素再做rehash重新定位,扩容是根据redis内部的扩容因子来计算的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Abner G

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

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

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

打赏作者

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

抵扣说明:

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

余额充值