为什么要复制?
多副本的存在是提升一个分布式系统可靠性、可用性、性能以及可扩展性的必要手段。
- 可靠性 : 如果一个文件系统已经实现数据复制,那么当一个副本破坏后,,文件只需要转换到另外一个副本继续运行下去;防止数据破坏,假设有三个文件副本,都可以在各自的副本进行读写操作,这时可以保护数据不会因为一个失败的写操作而受到破坏,因为此时至少有两个副本的值是正确的。
- 性能:当服务器需要进行数量和地域的扩展,需要减少访问的负荷, 这时就需要复制。
复制引发的问题
一致性!!!副本或者缓存都存在过时的问题(无效),副本与副本、副本与缓存之间的一致性问题。
完全同步化所有副本(强一致性):关键思想单个原子操作或事务的形式在所有副本上执行更新,更新本地副本时,需要将其他副本一并更新,才算执行成功。缺点:副本可能扩散在广域网中,快速更新是不可能,性能差。
所有我们需要放宽一致性的要求,避免(瞬间)全局同步,在性能和一致性做出一个平衡(性能提升,付出的代价是各个副本可能不总一致),例如之前数据库的事务隔离等级,所有便有了一致性模型。
一致性模型
这类模型提出了进程与数据存储之间的协议。进程遵守规定,那么就可以进行数据存储。
正常情况下,一个进程在一个数据项上执行读操作时,它期待的应该是该数据最后一次写操作之后的结果。
但是没有全局时钟的情况下,很难精确定义哪次写操作是最后一次。模型就是来限制定义在一个数据项上进行一次读操作所返回的值。
以数据中心为一致性模型
顺序一致性
所有进程看到一个相同的总体读写操作顺序,且每个进程上的操作也依序出现在这个总体操作顺序中,属于强一致性。
顺序一致性包含两层含义<1>进程必须按照程序指定的顺序执行程序,不能重排操作;<2>所有进程上的操作就好像以某种总体顺序执行且所有进程看到的总体顺序均相同,每个进程的操作在总体顺序中出现的顺序和它自身的相同。
顺序一致,因为尽管P3和P4首先读取'x'的值作为a然后b,但它们都具有相同的视图。
因果一致性(Causal Consistency )
所有进程中有因果关系的读写操作必须是顺序一致性的,没有因果关系的操作可以乱序执行,这种一致性强度要弱于顺序一致性。但是在工程实践中确定所有操作间的因果关系并不是一件容易的事情。
cmu440上的:
对于数据存储被认为是因果一致的,必须遵守以下条件:
- 写入可能与因果关系...
- 必须被所有流程看到
- 以相同的顺序。
- 并发写入...
- 可能会以不同的顺序被看到
- 在不同的机器上。
这里有什么因果关系?
进程P1写入一个数据项x。 然后P2读取数据项x,并写入y。 在这个例子中,因为y可能取决于x,所以P1和P2可能是因果相关的。
或者,如果P1和P2正在写入两个同时并且彼此不相关的不同数据项,则它们被认为是并发的。
总结:所有进程必须以相同的顺序看到具有潜在因果关系的写操作,不同的机器上可以以不同的顺序看到并发的写操作。
注意:P1:W(x)c和P2:W(x)b是并发的,所以它并不重要,所有进程都以相同的顺序看到它们
然而,Wx(a)和R(x)a然后W(x)b是潜在的因果关系,因此它们必须是有序的。
P2 W(x)b可能因果关系地表示为W(x)a - 例如,它可能是P2中读取值的结果:R(x)a,因此这两个写入是因果关系的。
如果是这样,那么P3和P4必须以相同的顺序看到它们,而并发输出是不正确的并且违反因果一致的顺序。
在这个图中,P1:W(x)a与P2:W(x)b并发出现,因此它们不是因果相关的,因此P3和P4可以按照不同的顺序看到它们 - 所以可以。
总结:如果是因果关系的话,其他进程读结果必须是一致的顺序;非因果关系即并发 写入,其他进程读结果可以是不同的
以客户为中心的一致性模型(cmu440上没讲,以后补充)
用户级一致性定义中的“进程”可以认为是具体应用场合中的一个会话或客户等参与者。
(1)单调读一致性(monotonic-read):如果一个进程读取数据项X的值,那么该进程后续任何读取X值的操作都将得到那个值或者更新的值。单调读一致性从时间的维度上保证了如果进程在t时刻看到了X的值,那么以后不会在看到较老版本的值。
(2)单调写一致性(monotonic-write):一个进程对数据项X执行的写操作必须在该进程对数据项X执行的任何后续写操作之前完成。单调写一致性同以数据为中心的FIFO一致性类似,本质是同一进程上执行的写操作必须在任何地方以正确的顺序执行。单调写一执行保证在一个副本上执行数据更新时,在此之前(其它副本上执行的)的所有数据更新都将首先执行。
(3)写后读一致性(read-your-write):一个进程对数据项X执行的写操作总是被该进程后续对X的读操作看见。一个写操作总是在同一进程执行的后续读操作之前完成,不管这个读操作是发生在哪个副本。
(4)读后写一致性(write-following-read):同一个进程对数据项X执行的读操作后的写操作,保证发生在与读取的X值相同或更新的值上。