同步
①从服务器向主服务器发送SYNC命令
②主服务器收到SYNC后开始执行BGSAVE命令,生成RDB文件,在此期间用缓冲区记录执行的写命令
③把RDB文件发给从服务器,并载入
④把缓冲区的写命令发送给从服务器,从服务器执行,更新至主服务器当前状态
命令传播
主服务器所有写命令都会传播给从服务器
旧版本缺陷
SYNC命令是非常耗费资源的,在初次复制时能很好地完成,但在中途下线后又上线,
缺失的只是一部分信息,不需要所有资源同步,再次执行SYNC就显得低效
2.8版本开始用PSYNC来代替SYNC
该命令有两种模式:
完整重同步,跟SYNC命令基本相同
部分重同步,处理断线后重复制情况,把断线期间没收到的命令同步
①复制偏移量,重连后发送PSYNC命令,上报当前偏移量
②复制积压缓冲区,固定长度先进先出的队列,默认大小为1MB
当字符需要进入满的队列时,队头的元素将弹出
当进行命令传播时,主服务器还会将写命令入队到复制积压缓冲区
如果offset+1开始的数据在复制积压缓冲区中,将进行部分重同步
复制积压缓冲区大小= 2 * 重连平均时间(s) * 每秒产生写的大小。 来保证大部分情况都能部分重同步
③服务器运行ID,初次同步时,从服务器会保存主服务器的ID,重连时会发送ID给主服务器
如果ID相同,则尝试部分重同步,不相同则直接完整重同步
①发送slaveof命令后,设置主服务器的地址和端口
②建立套接字连接,从服务器是主服务器的客户端
③发送PING命令,检查套接字的读写状态是否正常,
④身份验证
⑤发送端口信息
⑥同步
⑦命令传播
从服务器默认每隔一秒向主服务器发送命令
REPLCONF ACK
replication_offset是从服务器当前的复制偏移量
作用
①检测主从服务器的网络连接状态
如果超过1秒没有收到命令,说明连接出现问题
②辅助实现min-slaves配置选项
防止主服务器在不安全的情况下执行写命令
③检测命令丢失
根据偏移量检查有无丢失,后序操作跟部分重同步类似
创建与主服务器的网络连接
一个是命令连接,用于发送接收命令
另一个是订阅连接,专门用于订阅主服务器的__sentinel__:hello频道
当客户端断线为了不丢失hello频道的任何信息,就必须专门订阅该频道
创建与从服务器网络连接
默认每十秒发送一次INFO命令,获取主服务器信息
根据此信息创建与从服务器的连接
创建与其他Sentinel的命令连接
通过频道信息发现新的Sentinel,然后建立命令连接
Sentinel默认每秒对创建了命令连接的实例发送PING命令
在down-after-milliseconds毫秒内没有收到有效信息,Sentinel会修改对应实例结构中flags属性打开
SRI_S_DOWN标识
不同Sentinel配置可能不同,对于判断主观下线时长不一样
当将一个主服务器判断主观下线后,会对其他Sentinel询问,当赞成的数量超过quorum值时,
会认为已经进入客观下线状态。
不同Sentinel判断客观下线的条件可能不同,由于配置的quorum值
当一个主服务器判断为客观下线时,监视这个主服务器的各个Sentinel会选举出领头
选举领头规则和方法:
每个发现主服务器进入客观下线的Sentinel都会要求其他Sentinel将自己设置为局部头领
设置局部头领是先到先得,最先向目标Sentinel发送命令 将会得到目标的支持。
当目标Sentinel已经有了支持的,其他发送过来的命令会被拒绝
超过半数的Sentinel支持,则会被选举为头领Sentinel
如果在限定时间内没有选举出,在一段时间后会再次选举,直到选出为止
①Sentinel系统挑选server1属下的一个从服务器,升级成主服务器
会剔除下线,断开超时,5秒内没有回复过领头Sentinel的INFO命令的从服务器
然后在剩下的从服务器中,先按服务器优先级,再按偏移量,最后按ID
为了保证保存着数据最新
②对其他server1属下的从服务器发送复制命令,称为新主服务器的从服务器
所有从服务器开始复制新的主服务器时,故障转移完毕。
③继续监视server1,上线后把它设置为新主服务器的从服务器
节点与节点之间建立联系
节点A会将节点B的信息通过Gossip协议传播给集群中的其他节点,与B进行握手
集群通过分片来保存数据库中的键值对,分为16384(2^14)个槽,每个节点能处理0-16384个槽
所有槽都有节点在处理时,集群才处于上线状态
clusterNode中slots信息
slots数组长度为16384/8=2048个字节,包含16384个二进制位,图中表示该节点负责0-7槽
clusterState.slots数组记录了集群中所有槽的指派信息,获取槽被指派给哪个节点为O(1)
clusterNode.slots数组记录了clusterNode结构所代表的节点的槽指派信息,节点被指派的节点见图17-9
计算键属于哪个槽
CRC(key) & 16383
CRC用于计算CRC-16校验和
判断槽是否由当前节点负责处理
如果clusterState.slots[i]等于clusterState.myself说明是当前节点负责
否则返回MOVED错误,指引去clusterState.slots[i]指向的节点
节点数据库实现
用跳跃表来保存槽和键之间的关系,用槽的编号来表示节点的score
跟MOVED错误类似,但这个是发生在槽迁移时
客户端收到ASK错误后,会向指引的节点先发送一个ASKING命令,然后重新发送想要执行的命令
如果直接发送会被拒绝执行返回MOVED错误
ASK错误只是临时转向,只限于当前发送ASK错误的命令
而MOVED错误是直接转向。
当半数以上负责槽处理的主节点发现某一主节点疑似下线,就会正式标为下线状态
故障转移
①下线的主节点中的所有从节点里面选出一个,跟选举领头Sentinel类似
②选出的从节点执行SLAVEOF no one,称为主节点
③把下线的主节点槽指派都指派给自己
④广播PONG消息,通知其他节点
⑤新的主节点开始接收处理跟自己负责槽相关的命令请求
MEET消息,请求加入集群
PING消息,默认每隔一秒向已知节点中随机选出5个发送消息,检测是否在线,
长时间没有被选中也会发送PING消息,防止信息更新滞后
PONG消息,确认消息收到
FAIL消息,某节点已经下线的消息
PUBLISH消息,节点会执行这个命令,并向集群广播