乐趣区

关于面试:Redis高可用总结Redis主从复制哨兵集群脑裂

越致力,越侥幸,
本文已珍藏在 GitHub 中 JavaCommunity, 外面有面试分享、源码剖析系列文章,欢送珍藏,点赞
https://github.com/Ccww-lx/Ja…

在理论的我的项目中,服务高可用十分重要,如,当 Redis 作为缓存服务应用时,缓解数据库的压力,进步数据的访问速度,进步网站的性能,但如果应用Redis 是单机模式运行,只有一个服务器宕机就不能够提供服务,这样会可能造成服务效率低下,甚至呈现其绝对应的服务利用不可用。

因而为了实现高可用,Redis 提供了哪些高可用计划?

  • Redis 主从复制
  • Redis 长久化
  • 哨兵集群

Redis基于一个 Master 主节点多 Slave 从节点的模式和 Redis 长久化机制,将一份数据放弃在多个实例中实现 减少正本冗余量 ,又应用哨兵机制实现主备切换,在master 故障时,自动检测,将某个 slave 切换为 master,最终实现Redis 高可用。

Redis 主从复制

Redis主从复制,主从库模式一个 Master 主节点多 Slave 从节点的模式,将一份数据保留在多 Slave 个实例中,减少正本冗余量 ,当某些呈现宕机后,Redis 服务还能够应用。

然而这会存在数据不统一问题,那 redis 的正本集是如何数据一致性?

Redis为了保证数据正本的统一,主从库之间采纳读写拆散的形式:

  • 读操作:主库、从库都能够执行解决;
  • 写操作:先在主库执行,再由主库将写操作同步给从库。

应用读写拆散形式的益处,能够防止当主从库都能够解决写操作时,主从库解决写操作加锁等一系列巨额的开销。

采纳读写拆散形式,写操作只会在主库中进行后同步到从库中,那主从库是如何同步数据的呢?

主从库是同步数据形式有两种:

  • 全量同步:通常是主从服务器刚刚连贯的时候,会先进行全量同步
  • 增量同步:个别在全同步完结后,进行增量同步,比方主从库间网络断,再进行数据同步。

全量同步

主从库间第一次 全量同步,具体分成三个阶段:

  • 当一个从库启动时,从库给主库发送 psync 命令进行数据同步(psync 命令蕴含:主库的 runID 和复制进度 offset 两个参数),
  • 当主库接管到 psync 命令后将会保留 RDB 文件并发送给从库,发送期间会应用缓存区(replication buffer)记录后续的所有写操作,从库收到数据后,会先清空以后数据库,而后加载从主库获取的 RDB 文件,
  • 当主库实现 RDB 文件发送后,也会把将保留发送 RDB 文件期间写操作的 replication buffer 发给从库,从库再从新执行这些操作。这样一来,主从库就实现同步了。

另外,为了分担主库生成 RDB 文件和传输 RDB 文件压力,提高效率,能够应用 “主 – 从 – 从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的形式扩散到从库上。

增量同步

增量同步,基于环形缓冲区 repl_backlog_buffer 缓存区实现。

在环形缓冲区,主库会记录本人写到的地位 master_repl_offset,从库则会记录本人曾经读到的地位 slave_repl_offset, 主库并通过master_repl_offsetslave_repl_offset 的差值的数据同步到从库。

主从库间网络断了,主从库会采纳增量复制的形式持续同步,主库会把断连期间收到的写操作命令,写入 replication buffer,同时也会把这些操作命令也写入 repl_backlog_buffer 这个缓冲区,而后主库并通过 master_repl_offsetslave_repl_offset 的差值数据同步到从库。

因为repl_backlog_buffer 是一个环形缓冲区,当在缓冲区写满后,主库会持续写入,此时,会呈现什么状况呢?

笼罩掉之前写入的操作。如果从库的读取速度比较慢,就有可能导致从库还未读取的操作被主库新写的操作笼罩了,这会导致主从库间的数据不统一。因而须要关注 repl_backlog_size参数,调整适合的缓冲空间大小,防止数据笼罩,主从数据不统一。

主从复制,除了会呈现数据不统一外,甚至可能呈现主库宕机的状况,Redis 会有主从自主切换机制,那如何实现的呢?

Redis 哨兵机制

当主库挂了,redis 写操作和数据同步无奈进行,为了防止这样状况,能够在主库挂了后从新在从库中选举出一个新主库,并告诉到客户端,redis 提供了 哨兵机制,哨兵为运行在非凡模式下的 Redis 过程。

Redis 会有主从自主切换机制,那如何实现的呢?

哨兵机制是实现主从库主动切换的要害机制,其次要分为三个阶段:

  • 监控:哨兵过程会周期性地给所有的主从库发送 PING 命令,检测它们是否依然在线运行。
  • 选主(抉择主库):主库挂了当前,哨兵基于肯定规定评分选选举出一个从库实例新的主库。
  • 告诉:哨兵会将新主库的信息发送给其余从库,让它们和新主库建设连贯,并进行数据复制。同时,哨兵会把新主库的信息播送告诉给客户端,让它们把申请操作发到新主库上。

其中,在监控中如何判断主库是否处于下线状态?

哨兵对主库的下线判断分为:

  • 主观下线:哨兵过程会应用 PING 命令检测它本人和主、从库的网络连接状况,用来判断实例的状态, 如果单哨兵发现主库或从库对 PING 命令的响应超时了,那么,哨兵就会先把它标记为“主观下线”
  • 主观下线:在哨兵集群中,基于多数遵从少数,少数实例都断定主库已“主观下线”,则认为主库“主观下线”。

为什么会有这两种 ” 主观下线 ” 和“主观下线”的下线状态呢?

因为单机哨兵很容易产生误判,误判后主从切换会产生一系列的额定开销,为了缩小误判,防止这些不必要的开销,采纳 哨兵集群,引入多个哨兵实例一起来判断,就能够防止单个哨兵因为本身网络情况不好,而误判主库下线的状况,

基于多数遵从少数准则,当有 N 个哨兵实例时,最好要有 N/2 + 1 个实例判断主库为“主观下线”,能力最终断定主库为“主观下线”(能够自定义设置阙值)。

那么哨兵之间是如何相互通信的呢?

哨兵集群中哨兵实例之间能够互相发现,基于 Redis 提供的公布 / 订阅机制(pub/sub 机制),

哨兵能够在主库中公布 / 订阅音讯,在主库上有一个名为“\__sentinel__:hello”的频道,不同哨兵就是通过它来互相发现,实现相互通信的,而且只有订阅了同一个频道的利用,能力通过公布的音讯进行信息替换。

哨兵 1 连贯相干信息(IP 端口)公布到“\__sentinel__:hello”频道上,哨兵 2 和 3 订阅了该频道。

哨兵 2 和 3 就能够从这个频道间接获取哨兵 1 连贯信息,以这样的形式哨兵集群就造成了,实现各个哨兵相互通信。

哨兵集群中各个实现通信后,就能够断定主库是否已主观下线。

在已断定主库已下线后,又如何选举出新的主库?

新主库选举依照 肯定条件 筛选出的符合条件的从库,并依照 肯定规定 对其进行打分,最高分者为新主库。

通常 肯定条件 包含:

  • 从库的以后在线状态,
  • 判断它之前的网络连接状态,通过down-after-milliseconds * num(断开连接次数),当断开连接次数超过阈值,不适宜为新主库。

肯定规定包含

  • 从库优先级,通过slave-priority 配置项,给不同的从库设置不同优先级,优先级最高的从库得分高
  • 从库复制进度,和旧主库同步水平最靠近的从库得分高,通过 repl_backlog_buffer 缓冲区记录主库 master_repl_offset 和从库slave_repl_offset 相差最小高分
  • 从库 ID 号,ID 号小的从库得分高。

全都都基于在只有在肯定规定中的某一轮评出最高分从库就选举完结,哨兵发动主从切换

leader 哨兵

选举完新的主库后,不能每个哨兵都发动主从切换,须要选举成 leader 哨兵,那如何选举 leader 哨兵执行主从切换?

选举 leader 哨兵,也是基于多数遵从少数准则 ” 投票仲裁 ” 选举进去,

  • 当任何一个从库断定主库“主观下线”后,发送命令 s-master-down-by-addr命令发送想要成为 Leader 的信号,
  • 其余哨兵依据与主机连贯状况作出绝对的响应,赞成票 Y,反对票 N,而且如果有多个哨兵发动申请,每个哨兵的赞成票只能投给其中一个,其余只能为反对票。

想要成为 Leader 的哨兵,要满足两个条件:

  • 第一,取得半数以上的赞成票;
  • 第二,取得的票数同时还须要大于等于哨兵配置文件中的 quorum 值。

选举完 leader 哨兵并新主库切换结束之后,那么 leader 哨兵怎么告诉客户端?

还是基于哨兵本身的 pub/sub 性能,实现了客户端和哨兵之间的事件告诉,客户端订阅哨兵本身音讯频道,而且哨兵提供的音讯订阅频道有很多,不同频道蕴含了:

事件 相干频道
主库下线事件 +sdown(实例进入“主观下线”状态)
-sdown(实例退出“主观下线”状态)
+odown(实例进入“主观下线”状态)
-odown(实例退出“主观下线”状态)
新主库切换 + switch-master(主库地址发生变化)

其中,当客户端从哨兵订阅音讯主从库切换,当主库切换后,端户端就会接管到新主库的连贯信息:

switch-master <master name> <oldip> <oldport> <newip> <newport>  

在这样的形式哨兵就能够告诉客户端切换了新库。

基于上述的机制和原理 Redis 实现了高可用,但也会带了一些潜在的危险,比方数据缺失。

数据问题

Redis 实现高可用,但实现期间可能产出一些危险:

  • 主备切换的过程,异步复制导致的数据失落
  • 脑裂导致的数据失落
  • 主备切换的过程,异步复制导致数据不统一

数据失落 - 主从异步复制

因为 master 将数据复制给slave 是异步实现的,在复制过程中,这可能存在 master 有局部数据还没复制到 slave,master 就宕机了,此时这些局部数据就失落了。

总结:主库的数据还没有同步到从库,后果主库产生了故障,未同步的数据就失落了。

数据失落 - 脑裂

何为脑裂?当一个集群中的 master 恰好网络故障,导致与 sentinal 通信不上了,sentinal 会认为 master 下线,且 sentinal 选举出一个 slave 作为新的 master,此时就存在两个 master 了。

此时,可能存在 client 还没来得及切换到新的 master,还持续写向旧 master 的数据,当 master 再次复原的时候,会被作为一个 slave 挂到新的 master 下来,本人的数据将会清空,从新从新的 master 复制数据,这样就会导致数据缺失。

总结:主库的数据还没有同步到从库,后果主库产生了故障,等从库降级为主库后,未同步的数据就失落了。

数据失落解决方案

数据失落能够通过正当地配置参数 min-slaves-to-write 和 min-slaves-max-lag 解决,比方

  • min-slaves-to-write 1
  • min-slaves-max-lag 10

如上两个配置:要求至多有 1 个 slave,数据复制和同步的提早不能超过 10 秒,如果超过 1 个 slave,数据复制和同步的提早都超过了 10 秒钟,那么这个时候,master 就不会再接管任何申请了。

数据不统一

在主从异步复制过程,当从库因为网络提早或执行复杂度高命令阻塞导致滞后执行同步命令,这样就会导致数据不统一

解决方案:能够开发一个内部程序来监控主从库间的复制进度(master_repl_offsetslave_repl_offset),通过监控 master_repl_offsetslave_repl_offset 差值得悉复制进度,当复制进度不合乎预期设置的 Client 不再从该从库读取数据。


总结

Redis 应用主从复制、长久化、哨兵机制等实现高可用,须要了解其实现过程,也要明确其带了危险以及解决方案,能力在理论我的项目更好优化,晋升零碎的可靠性、稳定性。

谢谢各位点赞,没点赞的点个赞反对反对
最初,微信搜《Ccww 技术博客》观看更多文章,也欢送关注一波

退出移动版