🟣 集群¶
约 2791 个字 1 张图片 预计阅读时间 14 分钟
Redis 集群模式有哪些?¶
- 主从:选择一台作为主服务器,将数据到多台从服务器上,构建一主多从的模式,主从之间读写分离。主服务器可读可写,发生写操作会同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令。主从服务器之间的命令复制是 异步 进行的,所以无法实现强一致性保证(主从数据时时刻刻保持一致)
- 哨兵:当 Redis 的主从服务器出现故障宕机时,需要手动进行恢复,为了解决这个问题,Redis 增加了哨兵模式,哨兵监控主从服务器,并且提供 主从节点故障转移的功能
- 切片集群:当数据量大到一台服务器无法承载,需要使用 Redis 切片集群(Redis Cluster)方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,提高 Redis 服务的读写性能
Redis 切片集群的工作原理?¶
切片集群会采用哈希槽来进行数据和节点的映射,一个切片集群一共有 16384 个槽位,每个存储数据的 key 会经过运算映射到 16384 个槽位中,映射关系如下: - 由 key 通过 CRC16 算法计算出一个 16bit 的数字 - 根据上面计算得到的数字对 16384 取模来确定对应的哈希槽
哈希槽和 Redis 节点是如何对应的?¶
主要有 平均分配和手动分配 两种方式。平均分配是集群创建时,Redis 自动将哈希槽平均分配到集群节点上;手动分配是使用命令指定每个节点上面的哈希槽数目,使用手动分配时要把 16384 个槽位给分完,否则集群不会正常工作。
主从模式的同步过程?¶
第一次同步¶
主要分为建立 连接协商、主从数据同步、发送新操作 三个步骤:
- 连接协商:从服务器先发送命令给主服务器表示要进行数据同步,命令内容包括 主服务器的 runID 和 复制进度 两个参数,主服务器收到命令之后会给从服务响应命令,响应包括 主服务器的 runID 和 复制进度。从服务器收到响应之后会记录这两个值
- 主从数据同步:主服务器生成 RDB 文件并发送给从服务器,从服务器收到 RDB 之后先清空自己的数据,再载入 RDB 文件。为了主从数据的一致性,这个期间主服务器后续的写操作会记录到 replication buffer 缓冲区里
- 发送新操作:主服务器发送 replication buffer 里面的写操作给从服务器,从服务器执行这些操作。第一次同步完成
命令传播¶
第一次同步完成之后双方会维护一个 TCP 连接,后续主服务器的写命令通过 TCP 连接发送给从服务器,保证主从一致
压力分摊¶
为了分摊服务器的压力,生成和传输 RDB 的工作可以分摊到经理从服务器上。
增量复制¶
如果服务器网路断开,在恢复之后,会把网络断开期间主服务器接收到的写操作命令同步给从服务器。
主服务器如何知道要将哪些增量数据发送给从服务器?¶
网络断开从服务器重新上线之后,会发送自己的复制偏移量到主服务器,主服务器根据偏移量之间的差距判断要执行的操作:如果从服务器要读的数据在 repl_backlog_buffer 中,则采用增量复制;如果不在,采用全量复制。
repl_backlog_buffer
repl_backlog_buffer 是一个 环形 缓冲区,用于主从服务器断连后,从中找到差异的数据;replication offset 标记缓冲区的同步进度。
如何避免主从数据的不一致?¶
让主从节点处于同一机房,降低网络延迟;或者由外部程序监控主从复制进度:先计算得出主从服务之间的复制进度差,如果复制进度差大于程序设定的阈值,让客户端不再在此节点读取数据,减小数据不一致的情况对业务的影响。
为了避免出现客户端和所有从节点都不能连接的情况,需要把复制进度差值的阈值设置得大一些。
主从架构中过期 key 如何处理?¶
主节点处理一个过期的 key 之后就会发送一条删除命令给从服务器,从节点收到命令后进行删除。
主从模式是同步复制还是异步复制?¶
异步。因为主节点收到写命令之后,先写到内部的缓冲区,然后再异步发送给从节点。
哨兵机制是什么?¶
因为在主从架构中读写是分离的,如果主节点挂了,将没有主节点来响应客户端的写操作请求,也无法进行数据同步。 哨兵作用是实现主从节点故障转移。哨兵会监测主节点是否存活,如果发现主节点挂了,会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端。
哨兵机制的工作原理?¶
判断节点是否存活¶
哨兵会周期性给所有主节点发送 PING 命令来判断其他节点是否正常运行。如果 PING 命令响应失败哨兵会将节点标记为 主观下线,然后该哨兵会向其他节点发出投票命令,当票数达到设定的阈值之后这个主节点就被标记为 客观下线。然后哨兵会从从节点中选择一个作为主节点。
投票¶
哨兵集群中会选择一个 leader 来负责主从切换,选举是一个投票过程:判断主节点为 客观下线 的是候选者,候选者向其他哨兵发送命令表示要成为 leader,其他哨兵会进行投票,每个哨兵只有一票,可以投给自己或投给别人,但是只有候选者才能把票投给自己。候选者之后拿到半数以上的赞成票并且票数大于设置的阈值,就会成为候选者。
选出新主节点¶
把网络状态不好的从节点给排除:先把已经下线的从节点过滤掉,然后把以往网络连接状态不好的从节点排除掉。接下来要对所有从节点进行三轮考察: 优先级、复制进度、ID 号。在进行每一轮考察的时候,哪个从节点优先胜出,就选择其作为新主节点:
- 第一轮考察:哨兵首先会根据从节点的优先级来进行排序,优先级越小排名越靠前。
- 第二轮考察:如果优先级相同,则查看复制的下标,哪个接收的复制数据多哪个就靠前。
- 第三轮考察:如果优先级和下标都相同,选择 ID 较小的那个。
更换主节点¶
选出新主节点之后,哨兵 leader 让已下线主节点属下的所有从节点指向新主节点。
通知客户的主节点已更换¶
客户端和哨兵建立连接后,客户端会订阅哨兵提供的频道。主从切换完成后,哨兵就会向 +switch-master 频道发布新主节点的 IP 地址和端口的消息,这个时候客户端就可以收到这条信息,然后用这里面的新主节点的 IP 地址和端口进行通信了。
将旧主节点变为从节点¶
继续监视旧主节点,当旧主节点重新上线时,哨兵集群就会向它发送 SLAVEOF 命令,让它成为新主节点的从节点。
什么是集群的脑裂?¶
如果主节点的网络突然发生了问题与所有的从节点都失联了,但此时的主节点和客户端的网络是正常的,客户端不知道集群内部已经出现了问题,还在向这个失联的主节点写数据,此时这些数据被主节点缓存到了缓冲区里。哨兵也发现主节点失联了,就会在从节点中选举出一个 leader 作为主节点,会导致集群有两个主节点。
网络恢复后哨兵因为之前已经选举出一个新主节点了,它就会把旧主节点降级,然后从旧主节点会向新主节点请求数据同步, 因为第一次同步是全量同步的方式,旧主节点会清空掉自己本地的数据。客户端在过程之前写入的数据就会丢失了。所以脑裂会导致集群数据的丢失。
如何减少主从切换带来的数据丢失?¶
异步复制同步丢失¶
配置一个阈值,一旦所有的从节点数据复制和同步的延迟都超过了阈值,主节点就会拒绝接收任何请求。对于客户端发现主节点不可写后,可以采取降级措施。将数据暂时写入本地缓存和硬盘中,在一段时间后重新写入主节点来保证数据不丢失,也可以将数据写入消息队列,等主节点恢复正常,再隔一段时间去消费消息队列中的数据,让将数据重新写入主节点。
集群产生脑裂数据丢失¶
当主节点发现从节点下线或通信超时的数量不满足阈值时,禁止主节点写数据,直接向客户端返回错误。Redis 提供两个配置项:
- min-slaves-to-write x:主节点必须至少有 x 个从节点连接,否则不再接收写请求
- min-slaves-max-lag x:主从复制 ACK 延迟不能超过 x 秒,否则不再接收写请求
两者搭配使用(例如 N=1、T=12s):即使原主库假故障(如网络分区),因无法满足「至少 N 个从库在 T 秒内 ACK」,原主库会被限制写请求,客户端无法向旧主写入;等新主上线后只有新主能写,原主降级为从节点并做全量同步时,不会再有新数据丢失。