@Alpacadh
2022-09-18T16:54:27.000000Z
字数 4737
阅读 227
Redis
主从同步刚连接的时候进行全量同步,全量同步结束后开始增量同步。
如果有需要,slave 在任何时候都可以发起全量同步,其主要策略就是无论如何首先会尝试进行增量同步,如果失败则会要求 slave 进行全量同步,之后再进行增量同步。
注意:如果多个 slave 同时断线需要重启的时候,因为只要 slave 启动,就会和 master 建立连接发送SYNC请求和主机全量同步,如果多个同时发送 SYNC 请求,可能导致 master IO 突增而发送宕机。所以我们要避免多个 slave 同时恢复重启的情况。
一致性 hash 其实是普通 hash 算法的改良版,其 hash 计算方法没有变化,但是 hash 空间发生了变化,由原来的线性的变成了环。
缓存 key 通过 hash 计算之后得到在 hash 环中的位置,然后顺时针方向找到第一个节点,这个节点就是存放 key 的节点。
当一个 Redis 新节点运行并加入现有集群后,我们需要为其迁移槽和数据。首先要为新节点指定槽的迁移计划,确保迁移后每个节点负责相似数量的槽,从而保证这些节点的数据均匀。
1)首先启动一个 Redis 节点,记为 M4。
2)使用 cluster meet 命令,让新 Redis 节点加入到集群中。新节点刚开始都是主节点状态,由于没有负责的槽,所以不能接受任何读写操作,后续给他迁移槽和填充数据。
3)对 M4 节点发送 cluster setslot { slot } importing { sourceNodeId } 命令,让目标节点准备导入槽的数据。
4)对源节点,也就是 M1,M2,M3 节点发送 cluster setslot { slot } migrating { targetNodeId } 命令,让源节点准备迁出槽的数据。
5)源节点执行 cluster getkeysinslot { slot } { count } 命令,获取 count 个属于槽 { slot } 的键,然后执行步骤 6)的操作进行迁移键值数据。
6)在源节点上执行 migrate { targetNodeIp} " " 0 { timeout } keys { key... } 命令,把获取的键通过 pipeline 机制批量迁移到目标节点,批量迁移版本的 migrate 命令在 Redis 3.0.6 以上版本提供。
7)重复执行步骤 5)和步骤 6)直到槽下所有的键值数据迁移到目标节点。
8)向集群内所有主节点发送 cluster setslot { slot } node { targetNodeId } 命令,通知槽分配给目标节点。为了保证槽节点映射变更及时传播,需要遍历发送给所有主节点更新被迁移的槽执行新节点。
收缩节点就是将 Redis 节点下线,整个流程需要如下操作流程。
1)首先需要确认下线节点是否有负责的槽,如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性。
2)当下线节点不再负责槽或者本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有的节点忘记改节点后可以正常关闭。
先来了解一下消息体传递了哪些数据
typedef struct {
//消息的长度(包括这个消息头的长度和消息正文的长度)
uint32_t totlen;
//消息的类型
uint16_t type;
//消息正文包含的节点信息数量
//只在发送MEET 、PING 、PONG 这三种Gossip 协议消息时使用
uint16_t count;
//发送者所处的配置纪元
uint64_t currentEpoch;
//如果发送者是一个主节点,那么这里记录的是发送者的配置纪元
//如果发送者是一个从节点,那么这里记录的是发送者正在复制的主节点的配置纪元
uint64_t configEpoch;
//发送者的名字(ID )
char sender[REDIS_CLUSTER_NAMELEN];
//发送者目前的槽指派信息
unsigned char myslots[REDIS_CLUSTER_SLOTS/8];
//如果发送者是一个从节点,那么这里记录的是发送者正在复制的主节点的名字
//如果发送者是一个主节点,那么这里记录的是REDIS_NODE_NULL_NAME
//(一个40 字节长,值全为0 的字节数组)
char slaveof[REDIS_CLUSTER_NAMELEN];
//发送者的端口号
uint16_t port;
//发送者的标识值
uint16_t flags;
//发送者所处集群的状态
unsigned char state;
//消息的正文(或者说,内容)
union clusterMsgData data;
} clusterMsg;
当集群内某个节点出现问题时,需要通过一种健壮的方式保证识别出节点是否发生了故障。Redis 集群内节点通过 ping/pong 消息实现节点通信,消息不但可以传播节点槽信息,还可以传播其他状态如:主从状态、节点故障等。因此故障发现也是通过消息传播机制实现的。 主要环节包括:
客观下线
Redis 集群对于节点最终是否故障判断非常严谨,只有一个节点认为主观下线并不能准确判断是否故障。当某个节点判断另一个节点主观下线后,相应的节点状态会跟随消息在集群内传播,通过Gossip消息传播,集群内节点不断收集到故障节点的下线报告。当半数以上持有槽的主节点都标记某个节点是主观下线时。触发客观下线流程。
客观下线流程
故障节点变为客观下线后,如果下线节点是持有槽的主节点则需要在它的从节点中选出一个替换它,从而保证集群的高可用。下线主节点的所有从节点承担故障恢复的义务,当从节点通过内部定时任务发现自身复制的主节点进入客观下线时,将会触发故障恢复流程。