[分布式系统学习]阅读笔记 Distributed systems for fun and profit 之四 Replication 拷贝

阅读http://book.mixu.net/distsys/replication.html的笔记,是本系列的第四章

拷贝其实是一组通信问题,为一些子问题,例如选举,失灵检测,一致性和原子广播提供了上下文。

同步拷贝

可以看到三个不同阶段,首先client发送请求。然后同步拷贝,同步意味着这时候client还在等待着请求返回。最后,服务器返回。

这就是N-of-N write,只有等所有N个节点成功写,才返回写成功给client。系统不容忍任何服务器下线。从性能上说,最慢的服务器决定了写的速度。

异步拷贝

相对的是异步拷贝。

master节点立即返回。该节点可能在本地做了复制,但是不会向其他服务器发送拷贝。只有在返回以后,异步的任务在开始执行。

相对地,这是1-of-N write。性能上说,快。但是不能提供强一致性保证。

主流拷贝的途径

作者用下面的方式分类:

  • 可防止divergence(单拷贝系统)
  • 存在divergence(多master系统)

第一类途径使系统表现得像“single system”,即使系统部分失效。

单拷贝系统按照一次执行中传递的消息数目,可以做一下分类:

  • 1n messages(异步 主从备份)
  • 2n messages(同步 主从备份)
  • 4n messages(2-phase commit,Multi-Paxos)
  • 6n messages (3-phase commit,Paxos with repeated leader election)

下面的图告诉我们,在不同侧重中选择(折中),我们会得到什么样的结果。

等待,性能就变差,一致性上的保证就更强。

主从备份拷贝(Primary/Backup replication)

最常见最基本的拷贝方式。所有的update发生在primary,并且以log的形式拷贝到backup 服务器。主从备份也分同步和异步两种。

MySQL和MongoDB都使用异步主从备份。同步主从备份保证在返回给client之前,backup节点成功存储了拷贝(Replica)。不过即使这样,同步方式也仅能保证较弱的承诺。考虑下面的场景:

  • 主服务器收到write,发送到backup
  • backup 写成功。返回ACK
  • 主服务器fail,client超时,认为写失败。

client现在认为写失败,但是backup其实成功。如果backup promote成为primary,那么就不对了。

2阶段提交(2PC)

2PC在很多经典的关系型数据库中都使用到了。例如MySQL 集群使用2PC提供同步拷贝。下面是2PC的基本流程

[ Coordinator ] -> OK to commit?     [ Peers ]
                <- Yes / No

[ Coordinator ] -> Commit / Rollback [ Peers ]
                <- ACK

在第一阶段,投票,协调者(Coordinator)给所有参与者发送update。每个参与者投票决定是否commit。如果选择commit,结果首先存放在临时区域(the write-ahead log)。除非第二阶段完成,这部分都只算“临时”的update。

在第二阶段,决策,协调者决定结果,并通知参与者。如果所有参与者都选择commit,那结果从临时区域移除,而成为最终结果。

2PC在最后commit之前,有一个临时区域,就能够在节点失效的时候,从而允许回滚。

之前讨论过,2PC属于CA,所以它没有考虑网络分割,对网络分割并没有容错。同时由于是N-of-N write,所以性能上会有一些折扣。

对网络分割容错的一致性算法

最著名的是Paxos算法,不过比较难理解和实现。所以Raft可以讲讲。

什么是网络分割(Network Partition)

节点本身正常运行,但是网络链路发生问题。不同的Partition甚至还能接收client的请求。

2节点,节点失效 vs 网络分割

3节点,节点失效 vs网络分割

单拷贝一致系统必须找到方法去破坏对称性。否则如果网络分裂成两个独立对等系统,divergence发生,无法保证single-copy。所以必须保证只有一个Partition处于活动状态。

多数的决策

所以,对分割容错的一致性算法依赖多数投票。依赖多数,而不是所有(例如2PC)节点,即可容许少数因为网络分割出现的较慢的,无法到达的节点。只要 (N/2 + 1)of N中的节点正常,系统就可以正常运行。

在对网络分割容错的算法中,系统一般使用奇数数目的节点,例如3个节点的系统,允许1个节点失效。5个允许2个失效。这样发生网络分割,我们总能找到一个“大多数”的Partition。

角色

在系统中,节点要么都扮演同一角色,要么各自担任不同角色。

一致性算法通常使节点扮演不同角色。有一个固定的领导或主节点,可以让算法更加高效。Paxos和Raft都利用了不同角色。在Paxos中,存在Proposer。领导者负责在操作中协调,余下的节点作为followers(Paxos中的Acceptors 或者 Voters)

Epochs(不翻了。。。)

在Paxos和Raft中,每次操作的周期都叫一个Epoch(”term“ in Raft)。在每个epoch,都有一个节点被指定为领导(Leader,后面都用英文吧,免得有歧义)。这个有点类似中国的朝代。

在每一次成功的选举后,一个epoch始终使用一个固定的leader,如上图。一些选举可能失败,那么epoch里面迭代到下一个。

真有点类似前面提到的逻辑时钟,让其他节点可以辨识凹凸的节点。那些分割的节点的epoch计数会比较小。

通过决斗(Duels),改变Leader

在一开始,某节点变成leader,其他节点成为follower。在操作过程中,leader维护心跳消息,这样follower就知道leader是否失灵,或者有网络分割发生。

当某节点发现leader没有响应了,(或者在初始状态,没有leader),该节点就转换成中间模式(在Raft称为candidate),然后将其epoch计数加1,发起leader的选举(election),竞争成为leader。

要成为leader,节点必须接收到足够多的votes,一种获取vote的方式就是谁先到谁取得。这样,最终会选出一个leader。

在epoch内,数字标记提案(Proposal)

在每个epoch,leader提议某值用于投票。提案用一个唯一的递增的数字标记。followers则接受它们收到的第一个提案。

普通操作

普通操作中,所有提案都经过leader节点。当一个client提交提案(client指分布式系统使用者),leader节点联系所有法定人数中的节点,如果在follower的回复中,没有与此冲突的提案,leader就提议某值。如果大多数follower都接受该值,那么该值就被认为正式接收。

当然有可能另外一个节点也在尝试成为leader,我们需要确保一旦提案被接受,该值永不改变。否则一个已经接受的提案可能被另外一个竞争leader推翻。

Lamport对该属性有如下表述:

如果对于值v的某提案被选中,那么每一个有较高数字标记的提案都有该值v。

原文如下:

P2: If a proposal with value v is chosen, then every higher-numbered proposal that is chosen has value v.

这个性质可以理解为一致性,也就是业已提出的提案,对其他后来提案都可见,是一种有效性。

为了保证该属性,proposer(leader)必须首先要求followers出示它们已有的最高数字的提案和值。如果proposer发现某提案已经存在,那么必须首先完成执行而不是重新提出提案。Lamport表述如下。

P2b. If a proposal with value v is chosen, then every higher-numbered proposal issued by any proposer has value v.

更具体地,

P2c. For any v and n, if a proposal with value v and number n is issued [by a leader], then there is a set S consisting of a majority of acceptors [followers] such that either (a) no acceptor in S has accepted any proposal numbered less than n, or (b) v is the value of the highest-numbered proposal among all proposals numbered less than n accepted by the followers in S.

这是Paxos算法的核心。如果之前有多个提案存在,那么数字标记最高的提案会被提出。为了保证在leader在依次询问每个acceptor其最新的value的过程中不出现冲突的提案,leader告知follower不要接受比当前提案数字标记小的提案。

那么在Paxos中要达成一个决策,需要两轮通信。

[ Proposer ] -> Prepare(n)                                [ Followers ]
             <- Promise(n; previous proposal number
                and previous value if accepted a
                proposal in the past)

[ Proposer ] -> AcceptRequest(n, own value or the value   [ Followers ]
                associated with the highest proposal number
                reported by the followers)
                <- Accepted(n, value)

准备阶段,proposer须知道任何冲突或者之前的提案。第二个阶段,一个新的value或者之前被提出的value,在proposer处提出。在某些情况下,比如说同时有两个proposer;比如消息丢失了;或者大多数节点失灵,那么不会有提案被多数节点接受。而这时允许的,因为最终的value还是收敛的。(也就是拥有最高数字标记的那个提案)。

这里非常类似西方民主国家的决策流程。在某项政策需要执行前,首先举行听证会,广泛征求意见。然后根据反馈的结果确定最后的政策。

当然在工程实现上还有不少挑战,这里列举了一些。

网络分割容忍一致性算法的例子:Paxos,Raft和ZAB

强一致下的拷贝算法

总结下各类算法的一些关键特征。

主从备份

  • 单独的,静态的master节点
  • 复制日志,slaves节点并不参与执行具体操作
  • 拷贝操作的延时没有上限
  • 无法容错网络分割
  • 在不一致和错误发生情况下,需要手工干涉

2PC

  • 统一投票:提交或者放弃
  • 静态的master节点
  • 协调者和普通节点同时挂掉情况下无法保证一致性
  • 无法容错网络分割

Paxos

  • 多数投票
  • 动态master节点
  • 允许n/2-1节点挂
  • 对延时并不太敏感
时间: 2024-08-05 15:18:17

[分布式系统学习]阅读笔记 Distributed systems for fun and profit 之四 Replication 拷贝的相关文章

[分布式系统学习]阅读笔记 Distributed systems for fun and profit 之三 时间和顺序

这是阅读 http://book.mixu.net/distsys/time.html 的笔记,是该系列的第三章. 为什么时间和顺序很重要呢?为什么我们关系事件A发生在事件B之前? 因为分布式系统要解决的问题是把单机上的问题通过多机来解决.然而传统单机的程序总是假设确定的顺序.对于分布式程序来说,正确性最简单的定义就是,跑起来像一台单机上运行的程序. 全序和偏序 具体的定义大家可以去翻离散书.简单地说,全序就是在集合里任何两个元素都可以比较,分出大小.偏序中,某些元素是没办法比较大小的. 在单节

[分布式系统学习]阅读笔记 Distributed systems for fun and profit 抽象 之二

本文是阅读 http://book.mixu.net/distsys/abstractions.html 的笔记. 第二章的题目是"Up and down the level of abstraction".这一章里面,作者主要介绍了分布式系统里面的一个重要概念:CAP理论. 什么是CAP理论呢?就是说在任何情况下,分布式系统只能满足下面三项中的两个: 一致性(Consistency),这里指的强一致性. 可用性(Availability). 对网络分割容错(Partition tol

深度学习论文阅读笔记--Deep Learning Face Representation from Predicting 10,000 Classes

来自:CVPR 2014   作者:Yi Sun ,Xiaogang Wang,Xiaoao Tang 题目:Deep Learning Face Representation from Predicting 10,000 Classes 主要内容:通过深度学习来进行图像高级特征表示(DeepID),进而进行人脸的分类. 优点:在人脸验证上面做,可以很好的扩展到其他的应用,并且夸数据库有效性:在数据库中的类别越多时,其泛化能力越强,特征比较少,不像其他特征好几K甚至上M,好的泛化能力+不过拟合于

面对软件错误构建可靠的分布式系统(阅读笔记)

阅读笔记 joe Armstrong 段先德 译 核心问题:如何在存在软件错误的情况下编写具有合理行为的软件 ,如何避免像死锁.死循环等问题 ERLANG的世界观,一切皆进程.将任务分离成层次化的一系列任务,强隔离的进程负责来执行每个具体化的任务,进程之间不共享状态(实际上ETS跨越了这个准则). 只能通过消息传递来通信,必须注意进程消息的堵塞问题 工作者和监督者构成一个完整的系统,监督者的作用就是监控整个系统的运行状况.并对突发情况进行可靠的处理. behaviour库的设计思想就是将程序的并

可扩展的Web系统和分布式系统(Scalable Web Architecture and Distributed Systems)

Open source software has become a fundamental building block for some of the biggest websites. And as those websites have grown, best practices and guiding principles around their architectures have emerged. This chapter seeks to cover some of the ke

Google File System 论文阅读笔记

核心目标:Google File System是一个面向密集应用的,可伸缩的大规模分布式文件系统.GFS运行在廉价的设备上,提供给了灾难冗余的能力,为大量客户机提供了高性能的服务. 1.一系列前提 GFS的系统构建针对其自身使用的特点在传统的分布式系统的基础上又进行了一些创新,基于的前提假设主要包括以下方面: 1.由于系统由廉价的商用机构成,组件失效被认为是一种常态,系统必须可以持续监控自身的状态. 2.系统存储以大文件为主,小文件也支持,但是没有进行特别的优化处理. 3.系统的工作负载主要包含

《STL源码剖析》---stl_alloc.h阅读笔记

这一节是讲空间的配置与释放,但不涉及对象的构造和析构,只是讲解对象构造前空前的申请以及对象析构后空间怎么释放. SGI版本的STL对空间的的申请和释放做了如下考虑: 1.向堆申请空间 2.考虑了多线程.但是这节目的只是讲解空间配置与释放,因此忽略了多线程,集中学习空间的申请和释放. 3.内存不足时的应变措施 4.考虑到了内存碎片的问题.多次申请释放小块内存可能会造成内存碎片. 在C++中,内存的申请和释放是通过operator new函数和operator delete函数,这两个函数相当于C语

《STL源码剖析》---stl_algobase.h阅读笔记

STL标准中没有区分基本算法或复杂算法,单SGI把常用的一些算法定义在<stl_algobase.h>只中,其他算法定义在<stl_algo.h>中. stl_algobase.h中的算法,比较值得学习的是copy(),它"无所不用其极"的改善效率.copy的目的是复制一段元素到指定区间,复制操作最容易想到赋值操作符=,但是有的赋值操作符=是trivial的,可以直接拷贝.关于赋值操作符=是不是trivial的,可以参考"Memberwise copy

《STL源码剖析》---stl_vector.h阅读笔记

在STL中,最常用的就是容器,最常用的容器就是vector了.vector类似内置数组.但是数组是静态的,一旦配置就不能再变大小,而容器的大小事容器本身自己调整的.在实现容器的代码中可以看到,容器可以动态增大,但是不能动态减小. 容器有已用空间和可用空间,已用空间就是容器已经使用了的空间,可用空间就是指vector的大小capacity. 容器是占用一段连续线性空间,所以容器的迭代器就等价于原生态的指针(这是造成我一直以为迭代器就是指针的原因),vector迭代器类型是RandomAccessI