原帖:http://highscalability.com/blog/2009/8/24/how-google-serves-data-from-multiple-datacenters.html
觉得这篇文章很好,尝试翻译了一下,翻得很烂,大家随便看看。
为了避免数据中心成为单点错误节点,当一个数据中心出了严重问题的时候,能很快恢复提供正常服务,双数据中心或者多数据中心是显而易见的解决思路。这种模式一般称为 multihoming (多宿主)。多数据中心有下面一些模式:
1. Backup
2. Master-Slave
3. Multi-Master
4. 2PC ( 两阶段提交 )
5. Paxos
我们将由下面几个方面来分析这些模式之间的差异:
Google App Engine 采取是多数据中心间的 Master-slave replication 。他们采取这种模式,主要是为了达成以下的目标:
没有一个方案能够面面俱到,折中不可避免,你需要根据你认为最重要的需求来选择合适的方案。
仍然有很多概念需要理解,下面我们需要一个一个的来讨论:
在多数据中心上读写数据是最困难的问题之一。用户会期待某种程度的可靠性和一致性。
当我们跨越多个数据中心读写数据时,应该提供哪个级别的一致性保证呢?我们可以放弃一些保证,但是我们应当知道在放弃这些保证的同时我们得到了什么。
Transactions (事务)一种扩展 形式的一致性,特指在一个行为包含多步操作时的一致性
事务的四种属性:正确性,一致性,有效性,原子性
但你一个行为跨越多个数据中心时,你要保证你行为支持事务是很困难的,因为太多的地方可能出错,而且延迟会大大提高。
下面是这些方案的权衡比较:
|
Backup |
Master/slave |
Multi-Master |
2PC |
Paxos |
一致性 |
弱 |
最终一致性 |
最终一致性 |
强一致性 |
强一致性 |
事务 |
无 |
支持 |
本地支持(限于一个数据中心内) |
支持 |
支持 |
延迟 |
低 |
低 |
低 |
高 |
高 |
吞吐量 |
高 |
高 |
高 |
低 |
中等 |
数据丢失 |
多 |
一些 |
一些 |
无 |
无 |
故障转移 |
不能 |
只读 |
读 / 写 |
读 / 写 |
读 / 写 |
选择一个特定的方案我们将得到何种类型的一致性,事务支持,延迟,吞吐量?是否会在出错的时候丢失数据?会丢失多少?我们何时可以故障转移,比如子在维护或者移动东西的时候,或者让一个数据中心废弃?我们怎么可以做到故障转移?这个方案是如何支持故障转移的?
数据写入 Master 导致数据也会被复制到一个或者多个 Slave 。
由于复制是异步的,对降低写延迟和提高吞吐量有利。
除非你非常小心,这种方案只能提高弱一致性或者最终一致性。
由于你的数据在多个数据中心中有多份拷贝,所以当出错时,你会丢失一些数据,但不会太多。故障转移仅仅支持读操作直到你把 Master 角色转移到另一个数据中心上。
Datastore 当前就是使用了这种机制。真正的多数据中心 (Multi-Master ) 会增加延迟,因为你不得不在各个数据中心间增加一些额外的通讯消耗。 App Engine 已经在写操作上比较慢了,所以这种额外的负担更显得痛苦。 Master/Slave 模式会让你得到大多数的好处的同时,还会让写操作延迟较低。
在多个数据中心上同时支持写操作。
你必须设计好如何在写入数据冲突的时候合并结果。这种做法跟异步复制很相像,但是你支持多点写入。你最好选择实现最终一致性。写入数据不会立刻影响到所有的数据中心。但这样的话又貌似回到了原点。我们追求 Backup 和 Master/Slave 所不能提供的强一致性。这种系统运行有了显而易见的变化,因为我们必须考虑写入合并的问题。
为了合并你必须找一个一种方法在写入操作上加入时序性。这里没有全局时钟,而且写操作是并行发生的。你甚至不知道那个动作是最先发生的。因此你需要使用时间戳,本地的时间戳 + 偏斜,本地的版本号,分布式的共识协议( chubby , zookeeper )等手段。
这种方案无法支持全局事务。因为在多点同时写的情况下,你是无法保证事务支持的。你不得不设想接下来怎么做。
App Engine 想要强一致性,因为这会使编写应用更简单,因为他们没有采取这个方案。
半分布式 - 因为一定存在一个主仲裁者( master coordinator ) .
它是同步的。所有的事务会串行的进入 master ,这会减低吞吐量和增加延迟。
如果你很在乎吞吐量的话,你绝对不能考虑这种方案。这种方案没有单点错误。由于额外的协调通讯,它会提高延迟。一个写操作的时间要达到 200 毫秒的级别。
然而这种方案能工作。你将写入所有的数据中心或者什么都没写入。你会得到强一致性和事务支持。
协议:有提案提出和达成共识 2 个步骤。只要有多数的节点同意提案通过,那么提案将会被视为通过。
跟 2PC 不同的是它是完全分布式的。不存在单个的主协调者。
很多事务可以并行执行。
写操作会有高延迟因为这种协议需要 2 轮额外的协调。
要做到如此,不得不为一次写操作付出 150 毫秒延迟,相对关系型数据库一此写入操作大概 5 毫秒来说,这未免有点高。
他们倾向使用物理上很接近的数据中心,然而一些天生的多数据中心开销(路由器延迟等)也会显得太高。就算是在一个数据中心内部也还是显得太慢了。
Paxos 仍然在 goolge 内部使用得很多。特别是在锁服务方面( chubby ),用来协调所有的跨数据中心的一切操作。特别用来协调状态在数据中心间转移。如果你的应用为一个数据中心提供数据,当它需要把数据转移到另外一个数据中心时,这些协调的工作就需要通过 Paxos 。
Paxos 也会用来管理 memcache 和离线处理。
Entity Groups 是 AppEgine 的一致性单元。 Entity Groups 上的操作都是串行化的。同时所有在 Entity Group 上的提交的操作的日志都会有备份。这样做是为了维持一致性和提供事务支持。 Entity Groups 本质上就是分片( shards ) . 分片( sharding )是为了提供伸缩性因为它使你可以处理很多写操作。 Datastore 就是按照 entity group 块大小来分片的。 BuddyPoke 有 4 千万的用户,每个用户都有一个 entity group ,也就是有 4 千万个不同的分片。
Eating your own dog food( 自食其力 ) 在 google 内部是一种常用战略。先让人们在内部反复的使用一个新的功能。反复使用不断改进直到真正发布出去。
AppEngine 把关系型数据库看成竞争者,就像 Azure 跟 SimpleDB 一样。往关系型数据库插入一条数据只需要几毫秒。 AppEngine 写入一条数据需要 30 到 40 毫秒 , 读却很快。他们喜欢这种权衡折中,因为对于 web 应用来说,读往往比写多得多。
我尚有一些事不明。他们是否考虑过 MVCC ( Multi-version concurrent control--- 多版本同步控制)的实现模式?这可能很有趣,但是它未被列为一种选项。显然目前 Google 对于内存中的数据伸缩性实现还不是很适当。
对于强一致性的偏好,以至它被一再列为主要设计目标,主要是让程序员编程更容易。就算如此在 google app engine 上编程已经非常困难了。由于它的局限性和缺乏关系型数据库的编程特性,在编写一个可伸缩的应用的时候,程序员被迫承接了太多的责任。我很好奇,如果放弃了强一致性,那相比而言又会如何呢?
我真的很欣赏那个特性评价矩阵,以及 google app engine 做技术选择的讨论。
对于 Google app engine 来说,写已经相当慢了,因此它没有太多的动态余量用在太多层次之间的协调通讯。这类东西是 Google 的开发人员在设计评审会议上讨论的东西,但是他们通常很少让这类东西流传出来。我貌似听见 Ryan 说道:为什么我们不能得到一切?但是事实就是如此,我们不能得到一切,总得有所取舍。感谢 Ryan 的分享。