在云计算的时代,Dynamo可以说是一本实现分布式存储的红宝书,借鉴Dynamo实现的产品如雨后春笋般冒出。前段时间本人曾在Twitter上戏称
这年头,如果一个号称有“海量数据”的互联网公司,不做一个自己的Dynamo, 出去都不好意思跟人打招呼
(http://twitter.com/xmpp/status/8023241449)
另外一方面对于Dynamo设计思想也有不少反对的声音,比如2009/11/1在Hacker News上链接的一篇文章Dynamo: A flawed architecture引起不少争议,最后竟引起Amazon CTO Werner Vogels在Twitter上回应
Darn, someone figured out that Dynamo is a flawed architecture. Luckily its only use is storing hundreds of millions of shopping carts
(http://twitter.com/Werner/statuses/5345892061)
汗,有人发现Dynamo是一个缺陷的架构,幸运的是,我们只用它来存储了成百上亿的购物篮数据。:-)
以下是这篇批判Dynamo文章大部分中心观点,所翻译的观点并不代表Tim立场。
–译文开始–
Dynamo: A flawed architecture
在发表此文章之前,我也争论过Dynamo是否适合我们的系统。但是我很清楚这篇论文充满缺陷,它将错误的引导了读者让大家相信其设计,它的很多设计前后自相矛盾。下文会详细介绍这些缺陷。
Dynamo的最终一致性
首先,最终一致性对开发者意味什么呢?
- 写入的数据不能在后续的读操作中获取到。
- 写入的数据也有可能在后续的读操作中获取到,但读到后可能下一次又读不到。
- 因此对写操作后面的读取没有SLA(Service Level Agreement)保证。
举例说明,由于Dynamo是一个key value存储,我们假设value中存储的是一个list, 当list写入数据之后另外一个client却未读取到,这时候它需要写入数据的话只能重新构建一个新的list,添加要存的值并将新list存入,这就会导致老的list数据丢失。
(Update: 论坛上一些人指出,由于Vector Clock机制,数据丢失的场景不可能出现,我同意,不过我再提出几个其他问题。)
- Cassandra未用vector clock, 而只用client timestamps也达到了同样效果。
- Dynamo依赖合并冲突来解决此问题,一些场合下冲突很难解决。比如从list中错误的截取操作。(if deletion from the list is a valid operation – then how would one reconcile after mistaken truncation?)
- 另外一个场景,读取到脏数据后可能会影响后续的写入。(a stale read may end up affecting writes to other keys)
一般的常识是读取脏数据是需要避免的,但是Dynamo中无任何措施来避免读取脏数据以及避免读取脏数据的客户端再次写入,这个在单IDC环境其实是完全可以避免的。
Quorum一致性
(译者注:Quorum是Dynamo的一个核心特性,主要思想是 写最小节点数W + 读最小节点数R > 所有节点数N)
Dynamo开始就提到系统按最终一致性设计,但是在4.5中却提出用Quorum的方法来实现一定程度的一致性,意思是如果R+W>N, 则读操作就具备(强)一致性了。明显是误导。由于节点会出现不可用的情况,尤其在跨IDC情况下,任一节点随时都有可能离开quorum组,当它离开再加入的时候,R个节点返回的数据就是不一致的,因为故障节点的数据只具备“最终一致性”,而在当时返回的只能是脏数据。
这就带来一个明显的问题,为什么要让未同步到最新数据的节点加入组?答案是Dynamo中无任何方法来判断一个节点是否数据同步,也无法判断有哪些数据不同步。因此只能做一个完全数据比较才能判断,Dynamo中用一种叫Merkle Tree的方法来实现,这个当然是一个代价昂贵且不灵活的操作,因为为了不影响Dynamo正常的读写业务,同步需要在后台执行。
实现强一致性也可以用读取所有节点(R=N)的方式来达到,不过有2个问题。
- 一旦有一个节点未同步,读取就会失败。
- 读取的代价极高。
我并不是第一个发现这些问题的人,比如另一知名的Cassandra产品Cassandra-225中就提到用一个中心commit log的方法来解决此问题。
WAN considerations 跨IDC的问题
值得指出的是,如果将Dynamo部署到多个机房,节点的断续情况会很容易发生。当一个节点连接不到,Dynamo的”hinted handoff”策略会使用一致性哈希算法将数据放入下一个节点。在多IDC环境下,下一节点通常在另一机房,因此会造成异地数据传输增加。当异地整个IDC都连不上网络分裂情况发生时,数据需要很长时间才能完全恢复。
Disaster Recovery 灾难恢复
Dynamo最终一致性及同步的设计对于是节点故障是有价值的,但是却无法估算有多少数据未同步。如果改用常规的commit log方式的话,很容易就能实现故障恢复并且计算未同步的数据量。
未使用时间一致性(译者:基于timestamp的合并?)在某些场合下很难合并冲突。
一致性还是可用性 Consistency versus Availability
一般认为Dynamo选择了CAP理论中的AP,而BigTable选择了CA。不幸的是,Dynamo并没有搞清什么是A(availability)和P(Partition Tolerance)。读者被误导只能在C和P中做一个取舍,这个当然是错的。我们很容易在单IDC实现一致性及高可用性。大部分商业数据库就是如此,HBase/HDFS也是如此。
很多人误以为即使在单IDC架构中,Dynamo方式比BigTable/GFS架构更合理。但Dynamo的优势其实是在多IDC。
中心化还是去中心化
Dynamo中提到
In the past, centralized control has resulted in outages and the goal is to avoid it as much as possible. This leads to a simpler, more scalable, and more available system.
过去,中心化设计导致了很多灾难,我们意识到要远离中心化。去中心化后,系统会更简洁,更具有可扩展性及高可用性。
中心化确实会形成瓶颈,但是没有证据说明中心化就低可用性。大部分专业的存储系统通过双机热备的方式都具备高可用性。简单的说,只需要所有中心模块(电源,主板,RAID,交换机等)都按双份的方式来设计,只需要额外增加一点硬件成本,这些系统基本可以达到5个9的可用性。
值得讽刺的是Dynamo其实在部分情况下还是一个中心化的体系,如交换机故障发生了网络分片,服务器分成2个独立的小网,这时候Dynamo对客户端是不可用的,尽管客户端可以连接上Dynamo。
更讽刺的是我们看到Dynamo很多一致性问题都是去中心化设计所导致。
–译文完–
此文的讨论也非常精彩,对于想深入了解Dynamo的朋友是不可多得的资料。可参看http://news.ycombinator.com/item?id=915212