Amazon Dynamo – 纠结的设计

从09年第一次阅读Dynamo论文,到最近阅读Amazon S3的一篇专利,一路过来对论文的理解可以简单归结为两个字 – 纠结。第一次看到Amazon Dynamo论文,有一种眼前一亮的感觉,Dynamo通过巧妙地组合一些P2P技术在Amazon构建了一个工程上可行的系统,CAP,NWR, Vector Clock一时成为流行词,更为神奇的是,Dynamo号称能够让用户设置不同的NWR策略从而在CAP三者之间获得一个很好的权衡,鱼和熊掌亦可兼得。而Amazon S3系统的核心基本可以分为两个部分:Blob系统存储对象(Object) + 类似Dynamo的系统存放Keymap,即”Key => Object在Blob系统中的存放位置”之间的映射关系。Amazon Dynamo论文获得OSDI最佳论文奖,这个系统也在Amazon的购物车和S3上有应用,似乎是个卓越的设计。然而,随着我接触越来越多的分布式系统,我发现Dynamo系统设计本身相当纠结,应用场景比较有限,其中的某些设计具有误导性。

1, 一致性考虑。”Eventually Consistency”是从Dynamo这个系统开始流行起来的。高可用性系统必然涉及到Replication,假设数据存储三份,为了保证性能,可以通过”Quorum Commit”的方式,即两份写成功就返回客户端,同一份数据同一时刻有一个主节点(称为Master节点)提供写服务。如果Master节点宕机,其它Slave同步节点可能没有最新的数据,但是Slave和Master上的数据是最终一致的,某些对一致性要求弱的应用可以读取Slave上的数据,Master和Slave的数据同步时间窗口为秒级。然而,Dynamo中的”Eventually Consistency”感觉有点挂羊头卖狗肉的意思,虽然Dynamo的多个副本最终会是一致性,但是可能需要处理冲突。Dynamo设计允许同一份数据同一时刻被多个节点修改,并且没有类似Paxos这样的协议进行协调,因此可能出现如下的问题:

  • 写入的数据不能再后续的读操作中获取到
  • 写入的数据有可能在后续的读操作中获取到,但读到后可能下一次又读不到
  • 对写操作后面的读操作没有SLA保证

我不清楚为什么Dynamo不采用通常的commit log的方式进行Replication。由于Dynamo中没有任何方式保证一定能够读取到写入的数据,因此,复杂的冲突合并工作只能留给客户端,我想,也只有Amazon购物车的同学才有这个时间和兴趣来把玩这样的系统。Dynamo中的Vector Clock方法虽然能在一定程度上缓解这个问题,但不能从根本上避免冲突。从理论上讲,多个节点保持操作顺序完全一致只有两种思路:第一种思路是主备,同一时刻只有一个节点提供更新服务并复制到其它节点;第二种思路就是Paxos-based replication。

由于Amazon Dynamo的冲突合并实在是过于复杂,后来的系统,包括Cassandra以及Amazon S3,都倾向于采用”Last-write wins”,即根据更新时间戳来自动处理冲突。另外,即使是”Last-write wins”,理论上仍然不能解决问题,因为,不管采用什么算法,多机之间的系统时间都是不可能做到完全同步的。从理论上将,Amazon Dynamo是一个弱一致的系统,任何读操作都不完全保证读到最新的数据。因此,实际应用中很多非常有用的操作,比如事务,CAS操作,在Dynamo的设计中是不可能得到支持的。这就是为什么Dynamo只适用于Amazon的购物车应用和S3,购物车应用的客户端可以处理冲突,而且客户端同学也愿意花时间适应Dynamo古怪的设计,S3是一个功能单一的Key-Value系统,只支持根据主键Get, Put和Delete三种最为基本的操作。在单数据中心内部设计一个功能如此受限的系统有很多简单并且更为有效的选择,完全没有必要做成Dynamo这样。Amazon后来有一个Simpledb的云存储服务,虽然它的实现没有公开,但是Simpledb需要支持类似CAS的乐观锁机制,我认为和Dynano对于一致性和Replication的考虑是不同的,后续会有专门的文章猜测Simpledb的内部实现。

2, 分区可容忍性。有的同学也许会说,Dynamo是一个AP的系统,分区可容忍性解决得好,适用多数据中心的场景,适合提供云服务。刚开始我也是这么认为的,并且极力说服自己接受Dynamo的设计。我们可以试着把分区可容忍性具体化,网络分区的情况我想主要有几种:第一种是交换机故障,第二种是数据中心之间的网络故障。首先,网络分区很多时候是可以通过硬件冗余的方式解决的。传统的解决方法,比如Bigtable最初采用数据中心内部强同步,数据中心之间异步复制的一致性策略,那么如果数据中心之间发生故障,要么停止写服务,要么牺牲一致性,以后再同步commit log进行补偿操作。而在Dynamo中似乎可以在发生网络分区的时候仍然接受更新服务,比如整个集群被网络分区为两个数据中心A和B,两个数据中心同时提供读写服务,对同一个Key的更新互相不可见,等到网络恢复后再进行冲突合并。但是,数据中心A和B的数据有哪些不一致没有人能够回答,只有上帝会告诉你:”网络恢复后数据中心A和B最终会是一致的”。这种设计太不可控,我认为不如Bigtable跨数据中心采用异步复制的方式。

3,种子节点设计。种子节点的设计也挺纠结的。我想,Dynamo最初希望做成一个P2P系统,但是,做着做着大家就发现如果没有节点知道全局的数据分布信息会使得设计变得非常复杂,一致性也很难保证,因此,引入种子节点(Seed)。这就像我们设计一个软件,开始以为找到了一种创新的方法可以解决困扰无数人的难题:总控节点的可扩展性问题,但是,做到后来发现想错了,于是打了一个补丁。

4, 系统测试。我不是测试人员,但是我想,当测试人员拿到这个的系统时一定相当郁闷。不保证一致性的系统将大大增加系统测试的复杂度,假设测试人员发现一个正确性问题,开发人员定位了很长时间告诉他:这是系统的行为,系统允许某些情况,比如机器时钟不同步,有宕机发生的时候丢数据。我不知道测试的同学此时做何感想。

总而言之,Amazon Dynamo组合运用了很多P2P的技术,确实设计出了一个可用的系统,但是这个系统的应用场景有限,工程上可以有很多更为简单有效的替代方案。”爱之深,恨之切”,虽然上面说了很多Dynamo的种种不是,但是,Dynamo系统中确实有很多方法值得我们学习,比如分布式Hash如何进行负载均衡,虽然系统总体上有一些缺陷,但Amazon Dynamo团队的工作仍然是卓越的,这里也非常感谢他们的分享。另外,这个系统也给了我一些关于云服务的一些思考:虽然云服务最为核心的技术是分布式存储,但是技术只是一个方面,产品定价,商业策略等往往更加重要,并且云服务包含的技术很多,虚拟机,云安全,等等,远远不只是分布式存储和计算。即使核心技术只能拿到80分,其它方面如果做得足够好,整个云服务产品也能拿到95。

【以上观点和某些同学可能有冲突,欢迎批评指正!】

Leave a comment

25 Comments.

  1. Google有bigtable、perculator、megastore,是否能够满足dynamo的使用场景呢?

      • 能不能专门发篇博文讨论一下这个问题?期待ing,呵呵
        个人感觉如果能够把互联网应用归类分析出几个大的需求场景(例如:按照对数据模型的要求、事务模型的要求、读写延时的要求等,给出场景分类,可能某个场景适合blog、email应用,某个场景适合SNS、微博应用,某个场景适合电子商务应用等),针对每个需求场景来讨论就很清楚了。博主有没有想法总结一下?

        • 这个事情可以做,不过目前我的能力还达不到可以把这些应用完全掌握的程度,如果有人合作一起总结我想是可以的。我们也会在淘宝推广系统的过程中总结经验,一个一个应用总结,以后逐步发布到blog中吧。

  2. 呵呵,总算有人懂了Dynamo …
    因为架构不行,弄了好多不合时宜的小窍门来弥补,误导不少人啊 …
    后来的Cassandra号称Dynamo+Bigtable,其实都是忽悠人的,开发者其实没搞懂 …

    • 我的感觉是这个系统确实很有创新,不过有的地方不怎么优雅,有点误导性。我的观点还不成熟,如果能和Dynamo的开发者探讨下我想应该能够学到很多东西。

  3. 1.dynamo主要强调AP,各节点在极端隔离情况下,还能继续为购物车提供服务,购物车不强调一致性。dynamo的节点估计分布在多个IDC
    2.dynamo只是一个简单的kv。大多数Web应用存储模型不会只是kv,它们的操作可能有先后依存关系,数据的合并不能只看时间戳

  4. 和amazon的人聊过,Dynamo早被扔进垃圾堆里了。。。(原话),而且基本上也只有shopping cart用了。。。

  5. 受教了。之前看dynamo论文时也隐隐有这种感觉,这个系统只适合做购物车这类一致性要求不高的存储。看了博主的文章茅塞顿开。

  6. 貌似Dynamo论文没得过OSDI的best paper,没查到啊,可有链接呢?

    想请教一下博主,你说的常用的commit log来做replication是个什么方式啊?可否大致描述一下?谢谢啦。

  7. 博主分析的很到位啊。去中心化得做法确实带来了更大的复杂性,我也猜到simpleDB肯定是参考了bigtable的思想的

  8. Dynamo的vector clock理论上还是能确定一个分布式的时序性的,从而达到最终一致性的。只不过可用性比较差
    参看这篇文章
    http://blog.basho.com/2010/04/05/why-vector-clocks-are-hard/

  9. 假设amazon的程序员都足够牛, 他们虑驾的了dynamo, 仍然存在两个问题:
    运维复杂
    请求时间不靠谱

  10. 这个文章是翻译的吧。。Tim yang也翻译过,你这文章的内容至少得标明一下原文出处 :???: 。。。。

  11. 看了你的文章收益很多,我想请教个Dynamo负载均衡的问题。
    我觉得负载均衡应该像GFS那样,至少要考虑磁盘利用率以及将副本分布在不同的机架。Dynamo论文中提到可以通过控制每个物理节点的Token数目来反映物理节点的磁盘容量,但是在它的第三个优化方案中,每个物理节点的Token数目都是Q/S,也就是说不能通过这种方法来表示物理节点的磁盘容量的差异了。另外,我也没看到它是如何在不同机架上分布副本的。

发表评论

电子邮件地址不会被公开。


您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackbacks and Pingbacks: