分布式

分布式数据

于各种各样的原因,将数据库分布到多台机器上:

  • 可伸缩性:读取负载、写入负载超出单台机器的处理能力,可以将负载分散到多台计算机上
  • 可用性:使用多台机器,以提供冗余。一台故障时,另一台可以接管
  • 延迟:让每个用户可以从地理上最近的数据中心获取服务

共享架构:通过共享数据存储的方式来进行扩展

无共享架构:通过水平扩展来提升性能

分区与复制:

20213516167

复制

主从复制

20213995359

同步复制或是异步复制:

2021399563

新从库加入:通过读取快照 + 快照后的变更方式来达到可用性与一致性的折中

节点宕机:

  1. 从库挂了:重连主库后追赶恢复
  2. 主库挂了:故障切换
    • 使用超时判定主库是否宕机
    • 共识算法选举出新主库
    • 老主库重新上线变成从库

故障切换带来的问题:

  • 异步复制造成新老主库数据冲突
  • 脑裂问题
  • 丢弃写入内容造成一些其他问题

复制日志实现

  • 基于语句的复制:直接发送SQL语句,但这种方式如果语句中含有非确定性函数,则这种方式不能保证数据的正确性
  • 传输预写式日志:直接传输字节序列,但这种方式跟具体的数据库引擎绑定
  • 逻辑日志复制:使用独立的存储格式来表达数据的增删改
  • 基于触发器的复制:开销更大

复制延迟

如果停止写入数据库并等待一段时间,从库最终会赶上并与主库保持一致。出于这个原因,这种效应被称为 最终一致性(eventually consistency)

为了保证读己之写一致性(read-your-writes consistency),使用这么样几个方法:

  • 如果某些数据只能由用户自己更新,则这份数据直接从主库读取
  • 用户记录最后一次写入时间戳,如果去读取从库,则要保证自这个时间戳之后的数据已经同步到从库
  • 如果数据分布在多个数据中心,则要保证同一用户请求路由的同一性

单调读

一个比强一致性(strong consistency)更弱,但比最终一致性(eventually consistency)更强的保证,保证每次读取的数据不会比上一次读取的老。

202139101821

一致前缀读(consistent prefix reads):如果一系列写入按某个顺序发生,那么任何人读取这些写入时,也会看见它们以同样的顺序出现

多主复制

应用场景:

  • 数据中心
  • 离线多客户端数据同步

写入冲突:

202139103032

为了解决这个问题,写入时使用一个主库来避免冲突

如果无法避免冲突,则使用冲突合并:

  1. 丢弃比较老的写入
  2. 参考git,记录冲突并在应用层处理

冲突解决逻辑:

  1. 写时执行:测到复制更改日志中存在冲突,就会调用冲突处理程序
  2. 读时执行:当检测到冲突时,所有冲突写入被存储。下一次读取数据时,会将这些多个版本的数据返回给应用程序。应用程序可能会提示用户或自动解决冲突

多主复制拓扑结构:

202139143850

前两种拓扑结构会出现单点故障,而最后一种虽然不会单点故障,但是如果不特别处理,很容易就会出现写入顺序不一致的问题

无主复制

客户端可以自由选择节点进行写入,这个被选择的节点充当协调者,将数据写入到自身或者其他节点

为了解决旧节点重新上线造成的新老节点数据不一致问题,不仅写需要写入到所有节点,同时读也要读多个节点,以此来判定数据的最新值

为每个写入附加一个时间戳,挑选最“最近”的最大时间戳,并丢弃具有较早时间戳的任何写入。这种冲突解决算法被称为最后写入胜利(LWW, last write wins)

分区

202131015533

键值数据分区

如果分区不公平,则会产生偏斜(skew),进而出现高负载的热点(hot spot)。避免这个问题的最简单方式是随机分配数据的节点,但这样的话必须并行查询所有节点以获取数据。

  • 根据键的范围分区
  • 根据键的散列值分区

2021310151228

如果单纯使用散列值进行分区会无法进行范围查询,所以一种折中的方式是使用多个列,主键进行散列,次键用来进行范围查找

哈希能有效帮助减少热点,但还不够,为了消除某些极端情况诸如单个键的数据热点,可以对散列键加上随机数,让其继续分布存储在不同的分区中。

次级索引

2021310153810

分区再平衡

将负载从集群中的一个节点向另一个节点移动的过程称为再平衡(reblancing)

几个最低要求:

  • 平衡之后,负载在各个节点也要平衡
  • 平衡时,应也能同时对外提供服务
  • 节点之间只移动必须的数据,以便快速再平衡

最差的方案:hash mod N 这种方案一旦节点数量发生变化,所有数据都得全部移动

固定数量分区:

2021310154640

动态分区:

按键的范围进行分区的数据库会动态创建分区。当分区增长到超过配置的大小时,会被分成两个分区,每个分区约占一半的数据。与之相反,如果大量数据被删除并且分区缩小到某个阈值以下,则可以将其与相邻分区合并

按节点比列分区:

当一个新节点加入集群时,它随机选择固定数量的现有分区进行拆分,然后占有这些拆分分区中每个分区的一半,同时将每个分区的另一半留在原地

完全自动化的再平衡可能会出现问题,如某些节点过载被认为宕机,此时将其的负载分摊到其他节点上面,这可能会导致节点和网络造成额外的负载,从而使情况变得更糟。再平衡的过程中有人参与是一件好事。这比完全自动的过程慢,但可以帮助防止运维意外

请求路由

2021310155412

为了获取整个集群的元数据情况,有两种方式:

  1. 通过如zk这样的元数据管理服务
  2. 使用如gossip这种协议

为什么要分布式

  • 模块耦合过高很可能造成牵一发动全身
    • 代码发布成本很高
  • 提高开发效率

分布式系统解决了什么问题

  1. 单机性能瓶颈导致的成本问题 小型机器不够用 大型机器又很贵
  2. 用户量以及数据量增大不得不使用分布式
  3. 业务高可用的要求

分布式理论

CAP

批注 2019-10-31 194221

  • 一致性(Consistency):服务A、B、C三个结点都存储了用户数据, 三个结点的数据需要保持同一时刻数据一致性。
    • 对系统的一个数据更新成功之后,如果所有用户都能够读取到最新的值,该系统就被认为具有强一致性
  • 可用性(Availability):服务A、B、C三个结点,其中一个结点宕机不影响整个集群对外提供服务,如果只有服务A结 点,当服务A宕机整个系统将无法提供服务,增加服务B、C是为了保证系统的可用性。
    • 对于用户的每一个操作请求总是能够在有限的时间内返回结果
  • 分区容忍性(Partition Tolerance):分区容忍性就是允许系统通过网络协同工作,分区容忍性要解决由于网络分区导致数据的不完整及无法访问等问题。

最多只能同时满足其中两项

202031017918

  • 如果放弃分区容错性(CA without P),意味着我们将假设节点之间通讯永远是可靠的。永远可靠的通讯在分布式系统中必定不成立的
  • 如果放弃可用性(CP without A),意味着我们将假设一旦网络发生分区,节点之间的信息同步时间可以无限制地延长
  • 如果放弃一致性(AP without C),意味着我们将假设一旦发生分区,节点之间所提供的数据可能不一致

分布式系统中,分区容忍性必不可少,因为需要总是假设网络是不可靠的,所以CAP理论实际上是要在可用性和一致性之间做权衡

  • 保证一致性(CP),不能访问未同步完成的节点,也就失去了部分可用性

批注 2020-06-23 090444

脑裂

n/2+1 过半! 使用奇数台!

  • 保证可用性(AP),允许读取所有节点的数据,但是数据可能不一致

批注 2020-06-23 090512

BASE

  • BA:(Basically Available ),基本可用
    • 分布式系统在出现故障的时候,保证核心可用,允许损失部分可用性
  • S:( Soft State),软状态,状态可以在一段时间内不同步
    • 允许系统不同节点的数据副本之间进行同步的过程存在时延
  • E:(Eventually Consistent ),最终一致,在一定的时间窗口内, 最终数据达成一致即可

批注 2020-06-23 090544

分布式系统的麻烦

系统的某些部分可能会以某种不可预知的方式被破坏。这被称为部分失效(partial failure)。这种失效重点在于由于分布式系统通过网络来进行协作,所以是不确定性的

分布式系统的故障处理原则:

  • 真理由多数所定义:当一个数据的值被多数节点所认可时,这个值才是正确的,多数节点被称为法定人数,最常见的法定人数是超过一半的绝对多数
  • 非拜占庭故障:所谓分布式系统的网络大都由某个组织所控制

网络不可靠

分布式系统大都通过节点之间发送消息来协作。但网络是不可靠的,有时消息发没发到,接没接到,这些都是不确定的。处理这个问题的通常方法是超时(Timeout):在一段时间之后放弃等待,并且认为响应不会到达

为了检测分布式系统节点的故障,一些机制可以知道节点是否关闭了,比如TCP协议中发送FIN或者RST,通过探测整个网络拓扑结构来发现网络是否故障。但这些仍无法百分百确保能接收到节点关闭的消息,所以可以通过重试,无论是TCP层的重试,还是应用层的重试,来进行等待,超时则声明节点死亡。

既然超时是唯一的解决方案,那超时应该超多久?这个时间应该是动态调整的,由于网络是通过动态分配流量来提升资源利用率,所以只能通过实验方式选择超时:测量延长的网络往返时间和多台机器的分布,以确定超时时间

不同于电话网这种事先为每个用户预留一定资源的网络,以太网这种网络更像一种抢占性的网络,所以电话网这种网络更有可能达到可预测的延时时间目标。

时钟不可靠

计算机中的石英钟不够精确:它会漂移(drifts)(运行速度快于或慢于预期)

单调钟:单调钟的绝对值是毫无意义的:它可能是计算机启动以来的纳秒数,或类似的任意值

时钟:有意义的时间,通常与NTP同步

为了解决时钟漂移带来的不同节点时间不一致的问题,可以使用:

逻辑时钟(logic clock):类似于事务版本号

另外一个需要注意额是进程暂停问题,无论是JVM的STW或者操作系统的进程重新调度,可能都会造成进程被冻结一段时间,然后会来重新执行,此时如果没有对时间做特殊处理,可能就会出现问题。分布式系统中的节点,必须假定其执行可能在任意时刻暂停相当长的时间

为了达到相应时间的保证,一些实时系统可能会通过降低吞吐量的方式来提升实时性。

一致性与共识

线性一致性

在一个线性一致的系统中,只要一个客户端成功完成写操作,所有客户端从数据库中读取数据必须能够看到刚刚写入的值

线性一致性背后的基本思想很简单:使系统看起来好像只有一个数据副本。

202131917318

网络分区迫使我们在一致性与可用性之间进行选择

顺序保证

分布式事务与共识

results matching " "

No results matching " "

results matching " "

No results matching " "