第五章数据复制

数据复制(数据密集型应用系统设计第五章)

一个可能出错的事物与一个不可能出错的事物之间的主要区别是, 当一个不可能出错的事物出错了, 通常也就意味着不可修复.

​ -----Douglas Adams, <<基本无害>> (1992)

为什么需要复制:

  • 使数据在地理位置上更接近用户, 从而降低访问延迟
  • 当部分组件出现故障, 系统依然可以继续工作, 从而提高可用性
  • 扩展至多台机器以同时提供数据访问服务, 从而提高吞吐量

主节点和从节点

引入多副本后, 如何保证所有副本之间的数据是一致的?

常见的解决方案是 主从复制

  1. 指定某一副本为主副本, 当客户端写数据时, 必须将写请求发送给主副本
  2. 其他副本为从副本, 主副本将新数据写入本地存储, 然后将数据更改作为复制的日志发送给所有从副本, 每个从副本将更改日志严格按顺序应用到本地
  3. 客户读取数据时, 可以从主副本或从副本(一般是从副本)获取.

同步复制和异步复制

同步复制指的是主副本如果有写请求, 会将更改日志发送给所有从副本, 当有一个从副本写入成功后, 主副本即可返回客户写入成功, 不会等所有从副本写入成功才返回, 这样做的优势是主节点一旦发生故障, 从节点可以继续访问到最新的数据,缺点是需要等待从节点确认

异步复制

全异步模式如果主节点发生失败并且不可恢复, 那么所有尚未发送到从节点的更改日志会全部丢失, 优点是系统的吞吐性会更好, 这种看起来不靠谱的设计也被广泛使用, 特别是那些从节点数量巨大或分布在广域的地理环境中

加入新的从节点

假设有一个正在运行的系统, 为了提高容错能力考虑添加一个新的从节点, 因为数据是不断的在变化的, 如何确保新的从节点和主节点数据一致呢?

如果是锁定数据库(不让写入数据), 会违法高可用的目标

有一种不停机, 数据服务不中断的前提下完成从节点的加入

  1. 在某个时间点对主节点的数据副本产生一个快照, 这样能避免长时间锁定整个数据库
  2. 将此快照拷贝进新的从节点
  3. 从节点连接到主节点并请求获取快照点以后的更改日志
  4. 获得日志后从节点快速应用这些快照点之后的所有数据变更, 追赶到和主节点一致

节点失效

从节点失效: 追赶式恢复

  1. 从节点都保存了数据变更日志, 如果发生崩溃, 重启后根据日志位置, 从主节点获取之后的日志, 应用到本地

主节点失效: 节点切换

处理主节点故障比较棘手: 选择某个从节点将其提升为主节点, 客户端也要更新请求路由将写入数据发送到新的主节点, 然后其他从节点要接受来自新的主节点上数据变更日志

会遇到的问题:

  1. 如何选出新的主节点(一致性算法)
  2. 客户端如何将写请求发送到新的主节点(请求路由)
  3. 原节点重新恢复, 如何处理老的主节点和新的主节点(脑裂)
  4. 如何设置合理的心跳时间, 太短会导致很多不必要的切换, 太长则意味着总体恢复时间边长

复制日志的实现

  1. 基于语句的复制: 主节点记录所执行的每个写请求, 并将操作语句作为日志发送给从节点, 例如 insert, update, delete, 方式简单, 但是有一些不适用的场景

    1. 任何调用非确定性函数的语句, 例如 NOW() 或 RAND(), 可能在不同的副本上产生不同的值
    2. 如果语句中使用了自增列, 或依赖现有的数据, 例如: Update … Where 某些条件, 如果并发执行, 会产生不同的结果
    3. 有副作用的语句, 例如触发器, 存储过程, 用户定义的函数等

    有一些可以采取措施, 比如当调用非确定性函数时, 将确定值记录在日志中, 但由于不确定性因素很多, 所以目前通常首选其他方案

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

    1. 对于日志结构的存储引擎(LSM-Tree) , 追加写日志, 然后后台合并日志
    2. 对于采用覆盖写的 Btree, 每次修改预先写入日志, 如果发生崩溃, 恢复后以更新索引的方式恢复到此前一致性状态
  3. 基于行的逻辑日志复制

    1. 对于行的插入, 日志包含所有相关列的新值

    2. 对弈行的删除, 日志里有一个标识行删除, 通常是主键

    3. 对于行的更新, 日志有一个值标识更新的行以及更新字段的新值

    4. 如果是一条事务, 则会产生多个上面的记录, 并在后面跟一个提交记录, 表示该事务已提交

      Mysql 的 binlog 使用的就是基于行的复制, 好处是逻辑日志和存储引擎解耦, 能运行不同版本的存储引擎

    复制滞后问题

    上面提到的主从复制, 无论是同步复制还是异步复制, 总会有个别情况用户读从节点时候, 从节点还没来得及应用到主节点发来的更改日志, 虽然最后从节点会追赶上来, 但是用户显然是不高兴的

    读自己的写

    在一些场景中, 可以判断用户写完数据会立马读自己的数据, 例如发表博客, 提交评论等, 可以配置规则使这些用户写完立马查询的是主节点, 但是如果是同一用户多个设备访问数据, 例如 web 端修改完文章, 然后手机端读, 且 web 端连接 wifi, 手机端连接蜂窝移动网络, 这样就比较难判断

    单调读

    在一个从节点很多的集群里, 假定用户对不同的从副本进行了多次读取, 先是看到了用户有一条评论, 然后刷新页面后这条评论消失了, 用户会感到很困惑

    单调读一致性确保不会发生这种异常, 实现方式是

    确保每个用户总是从固定的副本执行读取, 例如基于用户 id 的哈希方法选择副本, 而不是随机选择副本, 但是有一个问题, 假如用户哈希的副本发生失效, 则必须路由到另一个副本

复制滞后的解决方案

多主节点复制: 到目前为止, 发生的问题都是依赖单个主节点的主从架构

这个架构存在一个明显的缺点: 系统只有一个主节点, 如果某种原因主从之间的网络中断, 主从复制方案就会影响所有的写入操作, 可以配置多个主节点, 每个主节点都能接受从写请求, 同时, 每个主节点还是其他主节点的从节点

image-20211028201601922

优势: 多主模型中, 每个写操作都可以在本地数据中心快速响应, 用户体验更好. 如果某个区域的主节点发生故障, 其他数据中心可以继续运行, 网络容忍方面, 数据中心之间的复制是异步复制, 不依赖网络延迟, 会最终写入成功

缺点: 不同的数据中心可能会同时修改相同的数据, 必须要有解决冲突的手段

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值