《Redis设计与实现》3.多机数据库的实现

一、复制SLAVEOF

  1. 旧版本复制功能:sync同步、command propagate命令传播
    1. 同步:当客户端像从服务器发送SLAVEOF
      1. 从服务器向主服务器发送SYNC命令
      2. 主服务器收到SYNC命令,执行BGSAVE,并使用一个缓冲区缓存从现在开始的命令
      3. BGSAVE完成,将文件发送给从服务器
      4. 主服务器将缓冲区的命令发送到从服务器执行
    2. 命令传播
      1. 主服务器将执行的写命令发送到从服务器执行
  2. 旧版本复制功能缺陷
    1. 初次复制:旧版本没有问题
    2. 断线后重新复制:虽然旧版本可以完成,但效率很低。SYNC命令是非常消耗资源
      1. SYNC会导致主服务器执行BGSAVE,消耗CPU、内存、磁盘I/O
      2. 主服务器将RDB发送从服务器消耗网络资源
      3. 从服务器加载RDB文件期间,不能处理请求
  3. 新版本复制功能:PSYNC命令
    1. 完整重同步,与SYNC基本一样
    2. 部分重同步,主服务器将断线期间的写明令发给从服务器
      1. 复制偏移量:主服务器、从服务器都维护了一个偏移量
      2. 复制积压缓冲区:固定长度FIFO队列,默认1MB
      3. 服务器运行ID
    3. 部分同步
      1. 从服务器重连上主服务器,发送PSYNC 自己偏移量
      2. 主服务器判断该ID的从服务器偏移量数据是否在复制积压缓冲区,不在则进行全量同步;在缓冲区,则回复+CONTINUE
      3. 发送复制缓冲区偏移量之后的数据到从服务器
  4. 复制的实现
    1. 设置主服务器的地址、端口:SLAVEOF ip port
    2. 建立套接字连接
    3. 发送PING命令
    4. 身份验证
    5. 发送端口信息:REPLCONF listening-port 22222
    6. 同步:从服务器发送PSYNC命令到主服务器
    7. 命令传播:主服务器每次执行完写命令,将其发送到从服务器
  5. 心跳检测
    1. 检测主从服务器的网络连接状态:REPLCONF ACK检测连接
    2. 辅助实现min-slaves配置:min-slaves-to-write 从服务器至少几个,min-slaves-max-lag 从服务器的延迟大于该数值
      1. 例如min-slaves-to-write 1  min-slaves-max-lag 5,从服务器数量少于1或者有1个从服务器的延迟大于5s,则主服务器拒绝请求。

二、Sentinel

  1. 启动并初始化Sentinel
    1. 初始化服务器:不需要载入RDB或AOF文件
    2. 将普通的Redis服务器代码替换成Sentinel专用:服务器端口、redisCommandTable替换为sentinelcmds
    3. 初始化Sentinel状态
    4. 根据配置文件,初始化Sentinel的监视主服务器列表
    5. 创建连想主服务器的网络连接
sentinel选举:
  • S1向S2、S3发送选举,S2与S3接收到后,发现均没有记录自己的选择,则将自己的选择设置为S1,并返回S1,然后S1判断返回是不是自己,记录选票数2,判断过半,则将自己选择为主sentinel;
  • S2向S1与S3发送选举,S1发现自己未选举,则将自己的选举设置成S2,并返回S2,S3发现自己已经选了S1,则返回S1,S2收到回复,得1票,未过半。
  • S3同理,得0票。
  • 最差的情况,均同时发出选举请求,S1选S2,S2选S3,S3选S1,则判断选举失败;等下下次重新选举;选举时,每个sentinel中都会有个计数器,每次选举完(无论成功还是失败)均自增1,用来判断是否为同一轮选举。
redis master选举:
  • 将所有slave保存到一个列表中
  • 删除下线、断线的slave
  • 删除近5秒没有回复sentinel的slave
  • 删除与master断开超过down-after-milliseconds*10毫秒的slave
  • 选出优先级最高的slave
  • 优先级一样,则选择复制偏移量大的slave
  • 偏移量也一致,则选取ID小的slave
 

三、集群

  1. 节点
    1. CLUSTER MEET ip port将节点加入到集群
    2. 节点运行在集群模式参数cluster-enabled
    3. CLUSTER MEET命令:客户端连接A,发送CLUSTER MEET B.ip port
      1. 节点A为节点B创建clusterNode结构,并将该结构添加到自己的clusterState.nodes中
      2. 向B发送MEET
      3. B为A节点创建clusterNOde,并添加到自己的clusterState.nodes中
      4. B向A发送PONG
      5. A向B回复PING
  2. 槽:整个集群被分为16384(2的14次方)
    1. 每个节点会向其他节点通知自己负责的槽
    2. 集群执行命令
      1. 客户端向节点发送命令
      2. 节点判断该key是否为自己所处理的槽,是则直接执行命令
      3. 不是自己处理的槽,则向客户端返回MOVED错误
      4. 客户端根据MOVED的信息,转向正确的节点
    3. 判断槽的方法:利用key计算出所在的槽X(CRC16(key) & 16383),然后判断clusterState.slots数组的X项是否为clusterState.myself,是则为自己负责,不是则取出存储的clusterNode的ip与port,返回MODVED错误。
    4. 重新分片:redis-trib
      1. 让目标节点准备好从源节点导入槽的键值对
      2. 让源节点准备好将槽的键值对迁移到目标节点
      3. 获取定量个键值对
      4. 将键值对迁移到目标节点,循环3-4步骤,直到槽的键值对都迁移完成
      5. 像集群广播迁移信息(槽迁移到了哪)
    5. ASK错误:槽迁移过程中的错误
      1. 客户端发送命令
      2. 源服务端接收到key,判断key是否还在,若key存在,则执行命令
      3. key不存在,判断源节点是否正在迁移,不是正在迁移,返回key不存在
      4. 若源节点正在迁移,则向客户端返回ASK错误,带上迁移信息(目标节点)
      5. 客户端先像目标节点发送ASKING,然后将命令发送到目标节点
  3. 复制与故障处理
    1. 故障检测
      1. 集群中的每个节点都会定期向其他节点发送PING,如果规定时间内没有回复PONG,则标记该节点PFAIL疑似下线
      2. 然后会与集群其他节点交换节点信息状态,并将其他节点疑似下线的信息添加到自己维护的clusterState.nodes中该疑似下线节点的clusterNode的下线报告中
      3. 一个节点被认为疑似下线的主节点过半,则向所有其他节点发布节点下线通知FAIL
    2. 故障转移
      1. slave得知自己的master下线了,则会从多个slave中选择一个slave(该主节点有多个从节点时)
      2. slave执行SLAVEOF no one,变为master
      3. 该master撤销所有原master的槽指派,并将这些槽指派给自己
      4. 该master向集群广播PONG消息,通知自己升级为了master,并接管了原有的槽处理
    3. 主节点选举
      1. FAIL的主节点的所有从节点向其他主节点发起投票请求
      2. 每个主节点可以投一票,每个从节点会收到投票结果
      3. 从节点判断超过半数,胜出,若没有选择出来,则继续下一轮,重新投票(每个节点里维护了一个计数器,类似于版本号或者那一轮,同一轮的票才可生效)
  4. 消息
    1. MEET消息:将一个节点加入到集群中。
    2. PING消息:每隔一定时间,节点就会随机选取5个节点发送PING消息,来检测选中的节点是否在线。
    3. PONG消息:用来回复PING消息或者MEET消息。
    4. FAIL消息:新的主节点判断老的主节点已经进入FAIL状态,会向集群广播旧节点FAIL消息。
    5. PUBLISH消息:一个节点接收到PUBLISH命令,会广播该消息,其他节点执行PUBLISH。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值