Dynamo: Amazon’s Highly Available Key-value Store

这篇文章主要用来记录学习 DynamoDB这篇paper的笔记。paper link: http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf

因为现在所在公司的后台是run 在 AWS上,所以有很多地方用到了DynamoDB, 然而除了知道怎么用,对实现细节并不是很清楚,所以觉得花时间研究一下应该很值得,因为本人并不在AWS工作,所以只能通过上述的paper来学习了。这篇paper发布已经十年来, 不难想象这十年DynamoDB的实现可能已经改动很多了,这些改动不得而知,但我觉得这篇paper所提到的理论还是比较通用的,因此是值得学习的。

 

设计初衷

Amazon之前是一个online retailer,为了满足自己内部业务的需求需要设计一个high availability/scalability key-value store,熟悉CAP理论的同学知道,这三者不能兼得,因此consistency 作为设计的trade off。

这个store就是DynamoDB。后来因为Bezos的高瞻远瞩,DynamoDB作为AWS的一个key service,任何人都可以使用,当然是要付钱的。

 

使用场景

显然不是所有的场景都应该用DynamoDB, 我们公司是典型的Micro service 架构,所以各个service根据不同的需求使用了很多不同的数据库,比如PostgresSql, MangoDB, Cassandra, DynamoDB, Oracle... 所以要清楚需求是什么,再决定用什么DB。比如你如果需要strong consistency,需要transaction support ... 这种情况应该优先考虑relational db。对于Nosql 的应用场景,我们一边就在Cassandra 和 DynamoDB 里面选择, 如果不需要cross region replication support,我倾向于选择DynamoDB,因为优点很显然,zero operation cost。和DBA打过交道的人可能会知道,能避免和他们打交道最好就避免。

 

DynamoDB 使用的技术

Paper里面总结的很清楚,我就照抄了。

 

 

 这里面有些名词可能比较熟,有些可能不太熟,比如gossip 所以我花了一些时间学了一下,但是发现和networking相关的东西越看越发现不知道的东西更多,所以也只是浅浅的了解一下。下面的文章就记录我学习具体每个技术的体会。

 

Consistent hashing

 这个名词比较出名,以前我也听说过,很多地方都会用到这个东西。因此很值得学习。

 这个网站讲的还不错,下图也是从那copy过来的 https://www.toptal.com/big-data/consistent-hashing。

 Consistent hashing解决的是如何高效的partition data的问题。就是CAP 最后的那个P。在分布式系统中, P往往是永远存在的,因为之所以用分布式系统是因为一台机器handle不了业务需求了。所以如何解决P是至关重要的。DynamoDB是key value store, 一般用户需要指定两个key,一个是partition key, 类似于primary key, 另一个是sort key。Partition key就是用来partition的,consistent hashing的hash function的输出是一个fixed circular space, 可以把所有的key space想象成一个ring,然后一个physical server比如A (node),她会被assign这个ring上 multi position which is also called a token, 比如 A3 (virtual node),那么A3所负责的key space就在(C4,A3]。A 因为被分成multi virtual node,所以 A会负责multi key space。这里负责的意思是,如果有一个记录的key 经过hash之后是在(C4,A3]之间,那么这个记录就会被存在A这个node上。为什么要分成multi virtual node呢,这是为了尽量让load 均匀分布在每台physical server上。Consistent hashing最大的优点是什么了,就是在Add/Remove node 的时候对整个系统影响最小,因为Remove node的时候这个load负责的key space会自动交给下一个相邻的node,对其它不相邻的node没有任何影响。Add node的时候也是类似的。

有一个问题就是这个ring/node 的信息具体是怎么存的呢,paper里面有提到共有两种方式:

1. 存在load balancer上面,所有的inbound request通过这个load balancer就能找到具体的node了。

2. 用DynamoDB提供的partition-aware client library,我在网上没有找到具体这个client library是如何实现的。这个的好处是省掉了额外的hop,不需要经过load balancer。

 

 

 High availability/durability 

在分布式系统中,想要满足high availability/durability,数据只存在一个server上显然是不行的,因为这个server随时会出问题,对于DynamoDB和其它绝大多数data store都需要实现一个很重要的功能:replication。 

在DynamoDB中每个data会被记录一共N份,这个N是可以config的。当某个coordinate node收到put request的时候,除了local会存储一份记录,这个node会把这个记录replicate到顺时针相邻的N-1个virtual node上,因为这些virtual node可能会对应同一个physical node,所以在选取相邻的virtual node时会skip掉某些个node,最终要保证选取的这些virtual node实际对应是不同的physical server。这些负责存储某个key的data的nodes 叫做 preference list。

你有可能会想在一台server上数据是怎么存的呢,paper里指出DynamoDB支持不同数据库engine,Engines that are in use are Berkeley Database (BDB) Transactional Data Store2 , BDB Java Edition, MySQL, and an in-memory buffer with persistent backing store. 可以理解为DynamoDB是构架于这些数据库上面的数据库。

另外很重要的一点是,为了保证high availability,DynamoDB会保证这些replicas在不同的AZ, data center...所以即使某个data center down 了,系统还能工作。

 

Vector clocks with reconciliation during reads 

当data被存储到multi servers时,一个需要解决的问题就是 consistency。DynamoDB的设计选择是eventual consistency,而且optimize for writes。这些的设计选择会导致在某些时候data并不是strong consistent的,特别是某些failure mode,比如某个server down掉。为了保证eventual consistency, 需要track数据的version。 DynamoDB用一种叫vector clock的技术,vector clock 是一组 <node, counter> pair, 很多情况下根据counter的大小可以决定哪个data copy的version最新,某些时候则需要用户自己去决定如何reconciliation。这篇paper后面提供的一些数据表明,绝大部分时候不需要用户reconciliation。下图显示了一个数据reconciliation的过程。

 

 

 

Sloppy Quorum and hinted handoff

因为一个数据一共会有N个replicas,即N个不同的servers,如果说put 需要至少写到W个servers才能返回success, read需要R个servers,那个选取R W 以保证 R + W > N,这样就形成了一个Quorum的系统。R W选择的越大越有利于数据的consistency,但因此会提高latency,也因此降低availability。 而DynamoDB更强调availability,导致by default会选择较小的R W值。DynamoDB的quorum system之所以叫Sloppy Quorum是因为和严格的Quorum系统不同,如果ring上最相邻的N个server其中有些不healthy时,为了保证availability,DynamoDB会skip这些unhealthy nodes, 然后把update replicate到更远的nodes,在这些updates 的message中会提示原本需要replicate 的目标server,当这个目标server back online时,系统会把这些message传回到原来的目标server,这个行为叫做hinted handoff。如上所述,Sloppy Quorum and hinted handoff 这两个技术的主要目的是handle failure,特别是transient failure。

通过调节N R W 三个参数,可以调节consistency vs availability,简单说R W越小availability越高,但是consistency会越低。反之亦然。一般的默认值是(3, 2, 2).

 

Anti-entropy using Merkle trees

这个技术主要用来handle permanent failure。当某一个node出现较长时间故障时或者某些其它情况时,需要一种高效的手段检查数据的inconsistentce已经尽量减少需要sync 的data,因此DynamoDB使用了一种叫做Merkle trees的数据结构,它的定义是: A Merkle tree is a hash tree where leaves are hashes of the values of individual keys. Parent nodes higher in the tree are hashes of their respective children. 通过它的定义就不难理解这个数据结构如何能高效的比较数据之前的inconsistency了。当然trade off是在key range变化时,需要重新calculate这个tree。Paper中虽然没有提到,但是 我认为当key增加或减少或者value有update的时候这个tree的部分需要被重新calculate,但是如果这个tree比较平衡,理论上只需要重新计算logN个节点的hash值,所以可能cost不会很高。

 

Gossip-based membership protocol and failure detection.

DynamoDB 实现选择了一种叫做Decentralize 的架构,核心理念就是没有一个中心master node,这种架构的优点是减少了因为一个master node可能fail而导致整个系统崩溃的几率,另外master node可能会成为hot spot,因此成为bottle neck。然而没有了这个master node,那这个系统的共享信息以及管理该如何调度呢。比如这个ring/node,也就是membership如何保持以及动态更新呢。DynamoDB使用了一种叫gossip based membership protocal,简单的说gossip就像是人之间传递八卦一样,每个node随机把某些information传递到其它一些node上,然后这些node再传递到其它node上。有很多文章具体介绍gossip, 比如这个视频https://www.youtube.com/watch?v=Vw7UxHlyDyA&list=PLFd87qVsaLhOkTLvfp6MC94iFa_1c9wrU ,gossip传递信息是很快的,因为基本上是成级数级别传递的,大概需要logN的数量级就可以传遍所有node。数学分析可以见上面视频。如上所述,Gossip 是一种peer to peer的信息传递的protocol。

具体实现上,比如在增加或减少node的时候,这个行为需要通过管理工具调用,这个membership 的更改会在某个node上存储,然后这个node会把membership 的update通过gossip的方式propagate到其它node上。这个过程并不需要一个master node来调度。同样的partition更改也是通过gossip去propagate的。上面提到membership的更改会在某个node先执行,一般这个node是指定的,叫做seed,这样可以减少membership 短期不consistent的可能性。

 DynamoDB node failure detection同样通过gossip实现,每个node会随机给其它node发送hearbeat信息,如果这个信息没有得到响应时,经过特定的延时(可能是transient failure),如果还是没有响应的话,发送信息的node会把未响应的node标记成failure,然后把这个information 通过gossip propagate出去。

从上面可以看出,gossip在DynamoDB里面起到很重要的作用,gossip是一种简单高效的peer to peer 信息交换系统。

 

总结

这篇paper 信息量非常大,设计到非常多的方面,每个方面都可以深入的研究。因为精力有限,暂时先写到这。下一步的计划是学习Google的3篇重要paper: Map-Reduce, GFS, BigTable.  希望到时候也能分享经验给大家。

posted @ 2017-11-05 04:58  逸朵  阅读(2040)  评论(0编辑  收藏  举报