第15章 复制
在redis中可以通过slaveof命令或者选项,让一个服务器取复制另一个服务器
- 旧版复制功能的实现
- 两个操作:
- 同步(sync)
- 命令传播(command propagate)
- 两个操作:
- 旧版复制功能的缺陷
- 初次复制
- 断线后重新复制 (效率低)
- sync是一个非常耗费资源的操作
- 新版复制功能的实现
- 使用psync,它的两种模式:
- 完整重同步
- 部分重同步
- 使用psync,它的两种模式:
- 部分重同步的实现
- 主服务器的复制偏移量
- 从服务器的复制偏移量
- 主服务器的复制积压缓冲区
- 固定长度的先进先出队列,默认1MB
- 可以根据公式
second * write_size_per_second
来估算
- 服务器的运行id
- PSYNC命令的实现
- 复制的实现
- 设置主服务器的地址和端口
- 建立套接字连接
- 发送ping命令
- 身份验证
- 发送端口信息
- 同步
- 命令传播
- 心跳检测
- 在命令传播阶段,从服务器默认以每秒一次的频率,向主服务器发送命令
replconf ack <replication_offset>
- 该命令有三个作用:
- 检查主从服务器的网络连接状态
- 辅助实现min-slave选项
- min-slaves-to-write和min-slaves-max-lag两个选项可以防止主服务器在不安全的情况下执行写命令
- 检测命令丢失
- 检测到写命令丢失,则部分同步
- 在命令传播阶段,从服务器默认以每秒一次的频率,向主服务器发送命令
第16章 Sentinel
由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主从服务器
- 启动并初始化Sentinel
- 初始化服务器
- 使用Sentinel专用服务器
- 将一部分普通redis服务器的代码替换为Sentinel专用代码
sentinel.c/REDIS_SENTINEL_PORT
sentinel.c/sentinelcmds
- 将一部分普通redis服务器的代码替换为Sentinel专用代码
- 初始化Sentinel状态
sentinel.c/sentinelState
- 初始化Sentinel状态的masters字典
- key: 被监视主服务器的名字
- val:
sentinel.c/sentinelRedisInstance
结构
- 创建连向主服务器的网络连接
- 每个被Sentinel监视的主服务器都会创建两个异步网络连接:
- 命令连接:专门用于向主服务器发送命令、接收命令并回复
- 订阅连接:连接专门用于订阅主服务器的
__sentinel__:hello
屏幕 - 同时解释了为什么
- 每个被Sentinel监视的主服务器都会创建两个异步网络连接:
- 获取主服务器信息
- Sentinel默认十秒一次向被监视的主服务器发送INFO命令
- 获取从服务器信息
- 十秒一次
- 向主服务器和从服务器发送信息
- Sentinel会以两秒一次的频率向所有主从服务器发送
publish __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"
- Sentinel会以两秒一次的频率向所有主从服务器发送
- 接收来自主服务器和从服务器的频道信息
- intro
- 当Sentinel与一个主从服务器建立订阅连接后,就会发送
subscribe __sentinel__:hello
- 通过
命令连接
发送信息到频道 - 通过
订阅连接
从频道中接收信息 - 如果有多个Sentinel监视同一个服务器,那么只要一个Sentinel发送了一条消息,所有其他Sentinel都会收到
- 当Sentinel与一个主从服务器建立订阅连接后,就会发送
- 更新Sentinels字典
- 为主服务器创建的一个数据结构,保存了除自己以外的其他Sentinel
- 创建连向其他Sentinel的命令连接
- 当Sentinel通过频道信息发现了一个新的Sentinel时,它们会互相建立起命令连接,使得整体形成一个网络
- 注意,Sentinel之间不会创建订阅
- intro
- 检测主观下线信息
- Sentinel以每秒一次的频率向所有与它创建命令连接的主从服务器、Sentinel发送ping命令,判断是否在线
- 配置选项
down-after-milliseconds
- 检查客观下线信息
- 当监视主服务器的其他Sentinel也认为该主服务器下线了(需要一定数量),则认为该主服务器客观下线
- 发送
SENTINEL is-master-down-by-addr
命令询问其他Sentinel是否同意主服务器已下线 - 接收
SENTINEL is-master-down-by-addr
命令 - 发送
SENTINEL is-master-down-by-addr
命令的回复
- 选举领头Sentinel
- 当一个主服务器被判定为客观下线时,监视它的各个Sentinel会选举出一个leader对服务器进行故障转移:
- 每个监视服务器的Sentinel都有机会成为leader
- 不论是否成为leader,所有的Sentinel epoch都加1
- 每个配置纪元里,所有Sentinel都有一次将某个Sentinel设置为局部leader的机会,并且设置后不可更改
- 每个发现主服务器进入客观下线的Sentinel都会要求其他Sentinel将自己设置为局部leader
- 优先原则:谁先申请成为leader谁优先成为leader,那么之后拒绝其他Sentinel的申请
- 获得半数以上投票的Sentinel将成为真leader
- 若在给定时限内没有产生leader,那么将重新选举
- 当一个主服务器被判定为客观下线时,监视它的各个Sentinel会选举出一个leader对服务器进行故障转移:
- 故障转移
- 如何在从服务器中挑选?
- 删除下线或断线的从服务器
- 删除5秒内没有回复leader Sentinel info命令的从服务器
- 删除所有与已下线主服务器连接断开超过
down-after-milliseconds*10
毫秒的从服务器 - 选择剩下中优先级最高的
- 若优先级相同,则选择复制偏移量最大的
- 若偏移量仍旧相同,那么选择id最小的
- 如何在从服务器中挑选?
第17章 集群
- 节点
cluster meet <ip> <port>
将当前节点加入到指定ip:port的集群中- 启动节点
cluster-enabled
- 单机模式和集群模式下,单个节点的差异
- 集群数据结构
clusterNode, clusterLink, clusterState
cluster meet
命令实现
- 槽指派
- 16384
cluster addslots
将指定范围内的槽指派给某个节点- 记录节点的槽指派信息
clusterNode
- 传播节点的槽指派信息
- 一个节点需要通知其他节点自己的槽信息
- 记录集群所有槽的指派信息
clusterState.slots -> clusterNode*[16384] -> clusterNode
cluster addslots
命令的实现- 如果存在一个槽已经被指派,则返回错误
- 在集群中执行命令
- 流程
- 检查命令要处理的数据库属于那个槽
- 如果正好是当前节点负责,那么直接执行
- 否则返回一个MOVED错误,重定向至正确节点
- 计算键属于哪个槽
CRC16(key)
- 判断槽是否由当前节点负责处理
- 节点数据库的实现
- 节点只能使用0号数据库
- 流程
- 重新分片
cluster-trib
- ASK错误
- 目标键正在被迁移,若不在当前节点,则响应ASK错误
cluster setslot importing
命令的实现cluster setslot migrating
命令的实现asking
命令- ASK错误和MOVED错误的区别
- 复制与故障转移
- 设置从节点
- 故障检测
- 定期发送ping消息
- 故障转移
- 选举新的主节点
- 集群的配置纪元是一个从0开始的计数器,每当某个节点发生一次故障转移,计数器加1
- 对于每个配置纪元,集群里每个负责处理槽的主节点都有一次投票的机会,而第一个向主节点要求投票的聪姐点将获得主节点的投票
- 当从节点发现主节点下线,会向集群广播一条
clustermsg_type_failover_auth_request
消息,要求所有收到并且具有投票权的主节点向这个从节点进行投票。遵守优先原则 - 大于半数
- 消息
- 五种消息
- MEET消息
- PING消息
- PONG消息
- FAIL消息
- PUBLISH消息
- 消息头
- MEET、PING、PONG消息的实现
- FAIL消息的实现
- PUBLISH消息的实现
- 五种消息