数据复制系统设计(3)-配置新的从节点及故障切换

举报
JavaEdge 发表于 2022/07/31 14:28:12 2022/07/31
【摘要】 配置新的从节点有时需考虑新增一个从节点:如需增加副本数以提高容错能力或替换失败的副本节点。那如何确保新的从节点和主节点数据一致?简单地将数据文件从一个节点复制到另一个节点通常不够。主要因为客户端仍不断向DB写新数据,数据总在变化,因此常规的文件拷贝方式会导致不同节点上呈现出不同时间点的数据,这显然非我所欲也。或许我们该考虑锁数据库(使其不可写)来使磁盘文件保持一致,但这违背高可用设计。幸好...

配置新的从节点

有时需考虑新增一个从节点:如需增加副本数以提高容错能力或替换失败的副本节点。

那如何确保新的从节点和主节点数据一致?

简单地将数据文件从一个节点复制到另一个节点通常不够。主要因为客户端仍不断向DB写新数据,数据总在变化,因此常规的文件拷贝方式会导致不同节点上呈现出不同时间点的数据,这显然非我所欲也。

或许我们该考虑锁数据库(使其不可写)来使磁盘文件保持一致,但这违背高可用设计。幸好,可做到在不停机、数据服务不中断前提下完成从节点的设置:

  1. 在某时刻获取主节点的一个一致性快照,避免长时间的锁整个数据库。大多数数据库都支持该功能,因为它是系统备份所必需的。某些场景,可能需第三方工具,如MySQL的innobackupex

  2. 将此快照复制到新的从节点

  3. 从节点连接到主节点并请求快照之后发生的数据变更日志。因为在第一步建快照时,快照与系统复制日志的某个确定位置相关联,该位置信息在不同系统有不同的叫法,PostgreSQL称其为log sequence number(日志序列号),MySQL称binlog coordinates

  4. 获得日志后,从节点来应用这些快照点之后的所有数据变更,该过程称为追赶。接下来,它可以继续处理主节点上新的数据变化。并重复1~4

1.4 处理节点宕机

系统中的任何节点都可能宕机,对运维而言,能在系统不中断服务的情况下重启单个节点可太妙了。目标是即使个别节点失效,也能保持系统总体持续运行,并尽可能减小节点宕机的影响。

1.5 主从复制实现高可用

1.5.1 从节点失效:追赶恢复

从节点的本地磁盘都保存了副本收到的数据变更日志。若从节点崩溃并重启或主、从节点之间网络中断,则比较容易恢复:从节点可从日志中知道,在发生故障之前处理的最后一个事务。因此,从节点可以连接到主节点,并请求在从节点断开连接时发生的所有数据变更。当应用完所有这些变化后,它就赶上了主节点,并可以像以前一样继续接收数据变更流。

1.5.2 主节点失效:故障切换

主节点故障则处理很棘手:

  • 选择某个从节点提升为新的主节点
  • 重新配置客户端,以将它们之后的写请求发给新的主节点
  • 其他从节点开始接收来自新主节点的变更数据

该过程就是故障切换(failover)。

故障切换可手动进行,如:

  • 通知管理员主节点宕机,采取必要步骤创建新的主节点
  • 或自动进行

自动切换过程

  1. 确认主节点失效。有很多可能性:系统崩溃、停电或网络问题等。没有万无一失方法能确切检测到底啥问题,所以大多数系统都采用基于超时的机制:节点间频繁互发心跳存活消息,若发现某节点在一段时间内(如30s)无响应,就认为它挂了(因为计划内的维护目的而故意下线主节点的场景不算)

  2. 选一个新的主节点。可通过选举(剩余节点多数达成共识)或由之前选定的控制器节点(controller node)来指定新的主节点。最佳候选节点是拥有与原主节点的数据差异最小,以最小化数据丢失风险

  3. 重新配置系统以启用新的主节点

    客户端现在需将写请求发给新主节点。若原主节点重归,可能仍认为自己是主节点,没意识到其他节点已达成共识迫使其下台。这时,系统要确保老领导认可新领导,并降级为一个从节点

故障切换的变数

若使用异步复制,则新主节点可能没收到老主节点宕机前的所有数据。选出新主节点后,若原主节点重新上线并加入集群,新主节点在此期间可能收到冲突的写请求,因为原主节点未意识到角色变化,还会尝试同步其他从节点,但其中的一个现在已接管成为新任主节点了。对此,常见解决方案:原主节点上未完成复制的写请求就此丢弃,但这可能会违背数据更新持久化的承诺。

若DB需和其他外部存储协作,则丢弃写入的内容是很危险的操作。如GitHub的一场事故,某个数据并非完全同步的MySQL从节点被提升为主节点,DB用自增计数器将主键分配给新

建的行,但因新主节点计数器落后于原主节点( 即二者并非完全同步),它重新使用已被原主节点分配出去的某些主键,而这些主键恰好已被外部Redis所使用,导致MySQL和Redis之间数据不一致,最后一些私有数据被错误地泄露给其他用户。

某些故障场景下可能会出现两个节点同时以为自己是主节点,即脑裂,很危险哦:两个主节点都可能接受写请求,且没有冲突解决机制,最好数据就可能丢失或损坏。某些系统对此采取安全措施:当检测到两个主节点同时存在时,会强制关闭其中一个节点[^ii],但设计粗糙的机制可能最后会导致两个节点都被关闭。

[^ii]: 这种机制称为 屏蔽(fencing),充满感情的术语是:爆彼之头(Shoot The Other Node In The Head, STONITH)

如何设置合适的超时来检测主节点失效呢?主节点失效后,超时时间越长,意味着总体恢复时间也越长。但若超时设置太短,又可能会频繁出现不必要的故障切换,如:

  • 临时负载峰值可能导致节点响应时间超时
  • 或网络故障可能导致数据包延迟

若系统已是高负载或网络拥塞,则不必要的故障切换可能让情况变得更糟。

这些问题其实都没简单解决方案。因此,即使软件支持自动故障切换,不少运维团队还是更愿意手动执行。

节点故障、不可靠的网络、副本一致性,持久性,可用性和延迟的各种权衡正是分布式系统核心问题。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。