前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >『数据密集型应用系统设计』读书笔记(五)

『数据密集型应用系统设计』读书笔记(五)

作者头像
1ess
发布2021-12-28 11:41:06
3290
发布2021-12-28 11:41:06
举报
文章被收录于专栏:0x7c00的专栏0x7c00的专栏

『数据密集型应用系统设计』读书笔记(五)

發佈於 2021-12-26

在前面几章,我们讨论了数据系统的各个方面,但仅限于数据存储在单台机器上的情况。现在我们进入更高的层次,在接下来的几章讨论将数据库分布到多台机器的情况。

复制

复制意味着在通过网络连接的多台机器上保留相同数据的副本。我们希望能复制数据,可能出于各种各样的原因:

  1. 使得数据与用户在地理上接近,从而减少延迟
  2. 即使系统的一部分出现故障,系统也能继续工作
  3. 伸缩可以接受读请求的机器数量

本章假设数据集非常小,每台机器都可以保存整个数据集的副本。之后的章节我们还会讨论对单个机器来说太大的数据集的分割。

如果复制中的数据不会随时间而改变,那复制就很简单: 将数据复制到每个节点一次就可以了。

复制的困难之处在于处理复制数据的变更,这就是本章的重点。我们主要讨论单领导者(single leader)的变更复制算法。

领导者与追随者

存储数据库副本的每个节点称为副本(replica)。 当存在多个副本时,就会出现一个问题: 如何确保所有数据都落在了所有的副本上

每一次向数据库的写入操作都需要传播到所有副本上,否则副本就会包含不一样的数据。最常见的解决方案被称为基于领导者的复制(leader-based replication),也称为主从(master/slave)复制

工作原理如下:

  1. 副本之一被指定为领导者(leader),也称为主库(master|primary)。当客户端要向数据库写入时,它必须将请求发送给领导者,领导者会将新数据写入其本地存储
  2. 其他副本被称为追随者(followers),亦称为从库(slaves)。每当领导者将新数据写入本地存储时,它也会将数据变更发送给所有的追随者,称之为复制日志。每个跟随者从领导者拉取日志,并相应更新其本地数据库副本,方法是按照领导者处理的相同顺序应用所有写入
  3. 当客户想要从数据库中读取数据时,它可以向领导者或追随者查询。但只有领导者才能接受写操作

这种复制模式是许多关系数据库的内置功能,例如,PostgreSQL、MySQL 等。

同步复制与异步复制

复制系统的一个重要细节是: 复制是同步(synchronously)发生还是异步(asynchronously)发生。在关系型数据库中这通常是一个配置项,其他系统通常硬编码为其中一个。

在上图示例中,从库 1 的复制是同步的: 在向用户报告写入成功,并使结果对其他用户可见之前,主库需要等待从库 1 的确认,确保从库1已经收到写入操作。以及在使写入对其他客户端可见之前接收到写入。从库 2 的复制是异步的: 主库发送消息,但不等待从库的响应。

在这幅图中,从库 2 处理消息前存在一个显著的延迟。通常情况下,复制的速度相当快: 大多数数据库系统能在一秒向从库应用变更,但它们不能提供复制用时的保证。

通常情况下,基于领导者的复制都配置为完全异步,异步复制已经被广泛使用了。

设置新从库

有时候我们可能需要设置一个新的从库: 也许是为了增加副本的数量,或替换失败的节点。 如何确保新的从库拥有主库数据的精确副本呢?客户端不断向数据库写入数据,数据总是在不断变化,标准的数据副本会在不同的时间点总是不一样。复制的结果可能没有任何意义。

我们可以通过锁定数据库,使其在该段时间内不可用于写入来使磁盘上的文件保持一致,但是这会违背高可用的目标。 但是通常,拉起新的从库通常并不需要停机。过程如下:

  1. 在某个时刻获取主库的一致性快照,而不必锁定整个数据库。大多数数据库都具有这个功能,因为它是备份必需的
  2. 将快照复制到新的从库节点
  3. 从库连接到主库,并拉取快照之后发生的所有数据变更。这要求快照与主库复制日志中的位置精确关联。该位置在不同数据库有不同的名称: 例如,PostgreSQL 将其称为日志序列号(log sequence number, LSN),MySQL 将其称为二进制日志坐标(binlog coordinates)
  4. 当从库处理完快照之后积压的数据变更,就可以继续处理主库产生的数据变化了

处理节点宕机

系统中的任何节点都可能宕机,可能因为意外的故障,也可能由于计划内的维护。那么即使发生宕机,我们的目标是,即使个别节点失效,也能保持整个系统运行,并尽可能控制节点停机带来的影响。

从库失效: 追赶恢复

在其本地磁盘上,每个从库记录从主库收到的数据变更。如果从库崩溃并重新启动,或者主库和从库之间的网络暂时中断,从库可以从日志中知道,在发生故障之前处理的最后一个事务。因此,从库可以连接到主库,并请求在从库断开期间发生的所有数据变更。等其赶上主库后,就可以像以前一样继续接收数据变更流。

主库失效: 故障切换

主库失效则相对复杂,其中一个从库需要被提升为新的主库,需要重新配置客户端,以将它们的写操作发送给新的主库,其他从库需要开始拉取来自新主库的数据变更。 故障切换可以手动进行或自动进行。

自动故障切换过程通常由以下步骤组成:

  1. 确认主库失效。大多数系统只是简单使用超时判断失效
  2. 选择一个新的主库。一般可以通过选举过程(主库由剩余副本以多数选举产生)来完成。主库的最佳人选通常是拥有旧主库最新数据副本的从库。让所有的节点同意一个新的领导者,是一个共识问题,将在之后章节详细讨论
  3. 重新配置系统以启用新的主库。客户端现在需要将它们的写请求发送给新主库。系统需要确保旧主库意识到新主库的存在,并成为一个从库

节点故障、不可靠的网络、对副本一致性、持久性、可用性和延迟的权衡,这些问题实际上是分布式系统中的基本问题,我们将会在之后章节详细讨论。

复制日志的实现

基于主库的复制底层有好几种不同的复制方式,大概分为:

  1. 基于语句的复制
  2. 传输预写式日志(WAL)
  3. 逻辑日志复制(基于行)
  4. 基于触发器的复制

复制延迟问题

容忍节点故障只是需要复制的一个原因,另一个原因是可伸缩性和延迟。

基于主库的复制要求所有写入都由单个节点处理,但只读查询可以由任何副本处理。所以对于读多写少的场景,我们可以选择创建很多从库,并将读请求分散到所有的从库上去。这样能减小主库的负载,并允许向最近的副本发送读请求。

在这种伸缩体系结构中,只需添加更多的追随者,就可以提高只读请求的服务容量。但是,这种方法实际上只适用于异步复制。如果尝试同步复制到所有追随者,则单个节点故障或网络中断将使整个系统无法写入。

不过,当应用程序从异步从库读取时,如果从库落后,它可能会看到过时的信息。这会导致数据库中出现明显的不一致。同时对主库和从库执行相同的查询,可能得到不同的结果,因为并非所有的写入都反映在从库中。这种不一致只是一个暂时的状态 —— 如果停止写入数据库并等待一段时间,从库最终会赶上并与主库保持一致。出于这个原因,这种效应被称为最终一致性

因为滞后时间不确定而引入的不一致性,不仅是一个理论问题,更是应用设计中会遇到的真实问题。

我们介绍三个由复制延迟问题产生的例子,并简述解决这些问题的一些方法。

读己之写

用户写入后从旧副本中读取数据。需要写后读(read-after-write)的一致性来防止这种异常。这是一个保证,如果用户重新加载页面,他们总会看到他们自己提交的任何更新。它不会对其他用户的写入做出承诺,其他用户的更新可能稍等才会看到。

如何实现读后一致性有各种可能的技术,下面是一些常见方式:

  1. 读用户可能已经修改过的内容时,都从主库读
  2. 如果应用中的大部分内容都可能被用户编辑,在这种情况下可以使用其他标准来决定是否从主库读取。例如可以跟踪上次更新的时间,在上次更新后的一分钟内,从主库读
  3. 客户端可以记住最近一次写入的时间戳,系统需要确保从库为该用户提供任何查询时,该时间戳前的变更都已经传播到了本从库中
单调读

从异步从库读取第二个异常例子是,用户可能会遇到时光倒流 如果用户从不同从库进行多次读取,就可能发生这种情况:

用户首先从新副本读取,然后从旧副本读取。为了防止这种异常,我们需要单调的读取。

单调读保证这种异常不会发生。这是一个比强一致性(strong consistency)更弱,但比最终一致性(eventual consistency)更强的保证。 例如,可以基于用户 ID 的散列来选择副本,而不是随机选择副本。但是,如果该副本失败,用户的查询将需要重新路由到另一个副本。

一致前缀读

第三个复制延迟例子违反了因果律。如果某些分区的复制速度慢于其他分区,那么观察者在看到问题之前可能会看到答案。防止这种异常,需要另一种类型的保证: 一致前缀读。 这个保证是说: 如果一系列写入按某个顺序发生,那么任何人读取这些写入时,也会以同样的顺序出现。 一种解决方案是,确保任何因果相关的写入都写入相同的分区。

复制延迟的解决方案

在使用最终一致的系统时,如果复制延迟增加到几分钟甚至几小时,则应该考虑应用程序的行为。如果答案是可以接受,那就没问题。但如果结果对于用户来说是不好体验,那么设计系统来提供更强的保证是很重要的,例如写后读

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 复制
  • 领导者与追随者
    • 同步复制与异步复制
      • 设置新从库
        • 处理节点宕机
          • 从库失效: 追赶恢复
          • 主库失效: 故障切换
        • 复制日志的实现
          • 复制延迟问题
            • 读己之写
            • 单调读
            • 一致前缀读
          • 复制延迟的解决方案
          相关产品与服务
          数据库
          云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档