• 分布式数据库难题(二):数据复制


    1. 为什么需要复制

        复制主要指通过互联网在多台机器上保存相同的数据副本,通过复制的方案,主要希望达成一下目的:

    (1)使数据在地理位置上更接近用户,从而降低访问延迟;

    (2)当部分组件出现故障,系统依然可以继续工作,从而提高可用性;

    (3)扩展至多台机器以同时提供数据访问服务,从而提高读吞吐率;

    2. 主从复制

    2.1 主节点和从节点

      对于每一笔数据写入,所有副本都需要随之更新,否则,某些副本将出现不一致。最常见的解决方案是基于主节点的复制,也称为主从复制。主从复制的原理如下:

    (1)指定某一个副本为主节点,客户端写数据库时,必须要写请求发送给主副本,主副本首先将新数据写入本地存储。

    (2)其它部分称为从节点,主节点将数据写入本地存储后,需要将数据更改作为复制的日志或更改流发送给所有的从节点。每个从节点获得更改日志后将其应用到本地,并且严格保持与主副本相同的写入顺序。

    (3)客户端读数据时,可以从主节点或者从节点上执行查询,只有主节点可以接受写请求,从节点都是只读的。    

    2.2 同步复制和异步复制

    (1)同步复制:主节点需要等待所有从节点确认完成了写入,然后才会向用户报告完成。

    •  优点:一旦向用户确认,从节点可以明确完成了与主节点的更新同步,数据已经处于最新版本。
    •  缺点:如果同步的从节点无法完成确认,例如从节点崩溃或者发生网络故障,写入就不能成功,这会阻塞其后的所有写操作,直到同步副本完成确认。

    (2)异步复制:主节点发送完消息后立即返回,不用等待从节点完成确认。

    •  优点:所有的请求立即得到响应,响应速度快,吞吐性能好。
    •  缺点:主从之间的数据会出现延迟,会出现主从数据不一致的情况。

        实践中,可以让一个从节点是同步的,而其它节点则是异步模式。万一同步的从节点变得不可用或者性能下降,则将另一个异步的从节点提升为同步模式。这样至少保证有两个节点,一个主一个从拥有最新的数据副本,这种配置有时称为半同步。    

    3. 配置新的从节点

        如果需要增加副本数以提高容错能力,或者替换失败的副本,就需要考虑增加新的从节点,但是如何确保新的从节点和主节点保持一致呢?逻辑上主要的步骤如下:

    (1)在某个时间点对主节点的数据副本产生一个一致性快照;

    (2)将快照拷贝到新的从节点;

    (3)从节点连接到主节点并请求快照点之后所发生的数据更改日志;

    (4)获得日志后,从节点来应用这些快照点之后的所有数据变更,这个过程称之为追赶。

    4. 处理节点失效

    (1)从节点失效:追赶式恢复

        从节点失效时,恢复比较容易。从节点重启后,根据副本的复制日志,从节点可以知道发生故障之前所处理的最后一笔事务,然后连接到主节点,并请求那笔事务之后中断期间内所有的数据变更。

    (2)主节点失效:节点切换

        处理主节点故障的情况比较复杂,需要选择某个从节点将其提升为主节点,客户端也需要更新,这样之后的写请求会发送给新的主节点,然后其它从节点要接受来自新的主节点的变更数据。故障切换可以手动执行,也可以自动切换,自动切换的步骤如下:

    •  确认主节点失效:绝大数多系统都采用基于超时的机制确认节点是否失效,即节点间频繁互相发送心跳存活消息,如果发现某一个节点在一段比较长的时间内没有响应,则认为该节点发生失效。这里要注意,超时时间设置越长意味着总体恢复时间就越长,但是如果超时时间越短,可能会导致很多不必要的切换。
    •  选举新的主节点:可以通过选举的方式来选举新的主节点,或者由之前选定的某种控制节点来指定新的主节点。让所有节点同意新的主节点是个典型的共识问题。
    •  重新配置系统使主节点生效:客户端现在需要将写请求发送给新的主节点,需要确保原主节点重新上线后,降级为从节点,并且认可新的主节点。

    5. 复制日志的实现

    (1)基于语句的复制

        基于语句的复制是最简单的复制方法,即主节点记录所执行的每个写请求并将该操作语句作为日志发送给从节点。从节点收到后,每个从节点都会执行这些操作语句,如同它们是来自客户端的一样。但是这种方式有如下一些不适用的场景:

    •  任何调用非确定性的语句,如NOW获取当前时间,RAND随机获取一个随机数,可能在不同副本上产生不同的值
    •   如果使用了自增列,或者依赖于数据库的现有数据,则所有副本必须按照完全相同的执行语句执行,否则可能会带来不同的结果。
    •  有副作用的语句(例如触发器、存储过程、用户定义的函数等),可能在每个副本上产生不同的副作用。   

    (2)基于预写日志(WAL)传输

        存储引擎(B+树或者LSM树)存数据的时候,通常每个写操作都是以追加写的方式写入到日志中,因此可以使用完全相同的日志在另一个节点上构建副本:除了将日志写入磁盘之外,主节点还可以通过网络将其发送给从节点。

        基于WAL预写日志的这种复制方式,主要缺点是日志描述的数据结果非常底层:一个WAL包含了哪些磁盘的哪些字节发生改变,诸如此类的细节。这使得复制方案和存储引擎紧密耦合。如果数据库的存储格式从一个版本改为另一个版本,那么系统通常无法支持主从节点上运行不同版本的软件。

    (3)基于行的逻辑日志复制

        第三种方法是复制和存储引擎采用不同的存储格式,这样复制和存储逻辑剥离,这种复制日志称为逻辑日志,以区分物理存储引擎的数据表示。关系数据库的逻辑日志通常是指一系列记录来描述表行级别的请求:

    •  对于行插入,日志里包含所有相关列的新值
    •  对于行删除,日志里有足够的信息来唯一标识已删除的行,通常是靠主键。如果表没有定义主键,就需要记录所有列的旧值。
    •  对于行更新,日志包含足够的信息来唯一标识更新的行,以及所有列的新值。

    (4)基于触发器的复制

        以上几种方法都是数据库系统来实现的,而基于触发器的复制则是由应用程序来控制。触发器支持注册自己的应用层代码,使得当前数据库系统发生数据更改时自己执行上述自定义代码,通过触发器技术,可以将数据更改记录到一个单独的表中,然后外部处理逻辑访问该表。

  • 相关阅读:
    【华为机试真题 JAVA】最长连续的数字串-200
    翻译 | Kubernetes Operator 对数据库的重要性
    SpringBoot整合Activiti7——流程变量(五)
    rabbitmq多个消费者消费同一个队列中的同一条消息。
    昇思25天学习打卡营第5天|数据变换 Transforms
    通过bat命令启动jar后缀软件
    爬虫知识--01
    PyTorch 中张量运算广播
    Unity中的【格式化数据】进行【系列化】后传到服务器再【反系列化】操作(二)
    3分钟看懂NPDP| 超全版
  • 原文地址:https://blog.csdn.net/MOU_IT/article/details/126078506