Amazon 依靠在电子商务中积累的大量基础性设施和各类先进技术,很早地进入了云计算领域,并在提供计算、存储等服务方面处于领先地位。
Amazon 开发并提供了一系列云计算服务这些云计算服务共同构成了 Amazon Web Service
amazon 提供的服务主要包括:
这些服务涉及云计算的方方面面,用户完全可以根据自己的需要选取一个或多个Amazon云计算服务。所有的这些服务都是按需获取资源,具有极强的可扩展性和灵活性。
Amazon 作为目前世界上最主要的电子商务提供商之一,它的系统每天要接受全球数以百万计的服务请求,髙效的平台架构是保证其系统稳定性的根本。下图是面向服务的Amazon平台基本架构。
从图中可以看出整个Amazon平台的架构是完全的分布式、去中心化的,在Amazon的平台中处于底层位置的存储架构Dynamo也是如此。Amazon平台中有很多服务对存储的需求只是读取、写入,即满足简单的键/值(key/value)式存储即可,例如:常用的购物车、信息会话管理和推荐商品列表等,如果采取传统的关系数据库方式,则效率低下。针对这种需求,Dynamo应运而生,虽然Dynamo目前并不直接向公众提供服务,但是大量的用户服务数据被存储在Dynamo中。可以说它为Amazon的电子商务平台及其云计算服务提供了最基础的支持。
为了保证其稳定性,Amazon的系统采用完全的分布式、去中心化的架构
Dynamo在设计时被定位为一个基于分布式存储架构的,高可靠、高可用且具有良好容错性的系统。下图列举了Dynamo设计时面临的主要问题及所采取的解决方案。
问题 | 采取的相关技术 |
---|---|
数据均衡分布 | 改进的一致性哈希算法 |
数据备份 | 参数可调的弱quorum机制 |
数据冲突处理 | 向量时钟(Vector Clock) |
成员资格及错误检测 | 基于Gossip协议的成员资格和错误检测 |
临时故障处理 | Hinted handoff(数据回传机制) |
永久故障处理 | Merkle哈希树 |
Dynamo中的存储节点呈无中心的环状分布。
两个基本概念:
通常,coordinator 是 preference list 上的第一个节点;一般情况下, preference list 的长度是5,也就是说第一个节点是数据操作节点,后面4个是备份节点。
Dynamo采用了分布式的数据存储架构,均衡的数据分布可以保证负载平衡和系统良好的扩展性。
因此,如何保证各个节点上数据的均衡性是影响Dynamo性能的关键问题。
Dynamo中使用改进后的一致性哈希算法,并在此基础上进行数据备份,以提高系统的可用性。
一致性哈希算法
一致性哈希算法是目前主流的分布式哈希表(Distributed Hash Table,DHT)协议之一,于1997年由麻省理工学院提出。
一致性哈希算法通过修正简单哈希算法,解决了网络中的热点问题,使得DHT可以真正地应用于P2P环境中。
给定一个hash值空间,[0~2^32),假设分布在一个圆环上,对每个结点算出一个固定hash值,将结点置于环上,对新加入的对象的 key 算出hash值,假设落在节点1和节点2之间,那么这个数据项< key,Value >就存在节点2开始的结点上。假定副本数为3,那么就存在节点2和节点2后面两个结点上面。
一致性哈希算法除了能够保证哈希运算结果充分分散到整个环上外,还能保证在添加或删除设备节点时只会影响到其在哈希环中的前驱设备节点,而不会对其他设备节点产生影响。
一致性哈希算法可以大大降低在添加或删除节点时引起的节点间的数据传输开销
改进的一致性哈希算法
因为每台机器的性能不一样,所以我们为了能够充分利用每台机器的性能,我们需要改进一致性哈希算法。于是在Dynamo中引入了虚拟节点的概念
每个虚拟节点都隶属于某一个实际的物理节点,一个物理节点根据其性能的差异被分为一个或多个虚拟节点。
各个虚拟节点的能力基本相当,并随机分布在哈希环上。
Dynamo将整个哈希环划分成Q等份,每个等份称为一个数据分区(Partition)
在存储数据时,每个数据会被先分配到某个数据分区,再根据负责该数据分区的虚拟节点,最终确定其所存储的物理节点。
数据分区的好处有:
在Dynamo中,每个数据的副本备份存储在哈希环顺时针方向上该数据所在虚拟节点的后继节点中。
数据备份在存储数据的同时进行,会使每次写操作的延时变长。
Dynamo中对写操作进行了优化,保证一个副本必须写入硬盘,其他副本只要写入节点的内存即返回写成功。
每个虚拟节点上实际存储了分配给它以及分配它的前N-1个前驱虚拟节点的数据。
分布式系统架构中通常考虑的三个因素:
Dynamo选择通过牺牲一致性来保证系统的可靠性和可用性 ,没有采用强一致性模型 而采用了最终一致性模型。
由于Dynamo中可能出现同一个数据被多个节点同时更新的情况,且无法保证数据副本的更新顺序,这有可能会导致数据冲突。
数据冲突问题如何解决?
Dynamo中采用了向量时钟技术(Vector Clock)
Dynamo中的向量时钟通过[node, counter]对来表示。其中 node 表示操作节点。 counter是其对应的计数器,初始值为 0 节点每进行一次更新操作则计数器加 1
如上图所示,D3 和 D4 的操作有冲突,于是,我们会把 D3 和 D4 同时交给应用层,让应用层来选择合并策略
既然有版本冲突的问题,冲突版本的合并就只能交给上层应用来做,每次读操作Dynamo将返回读到的所有版本,若上层应用无法解决合并,那就只能选择一个最新版本,从而丢失一部分数据,Dynamo论文只举了购物车的例子,每个值为一个购物车物品集合,每次更新可以往购物车添加,删除物品,冲突时合并购物车取并集。这样添加到购物车的操作不会出问题,但是可能会导致删除的物品重新出现。
由于Dynamo采用了无中心的架构,每个成员节点都需要保存其他节点的路由信息。
为了保证每个节点都能拥有最新的成员节点信息,Dynamo中采用了一种类似于Gossip(闲聊)协议的技术
Dynamo中还通过Gossip来实现错误检测任何节点向其他节点发起通信后,如果对方没有回应,则认为对方节点失效
为了避免新加入的节点之间不能及时发现其他节点的存在,Dynamo中设置了一些种子节点(Seed Node)。种子节点和所有的节点都有联系。当新节点加入时,它扮演一个中介的角色,使新加入节点之间互相感知。
错误检测的方法是:
如下图所示:
结论:
临时故障处理机制
为了处理临时失效的节点,Dynamo中采用了一种带有监听的数据回传机制(Hinted Handoff)
当虚拟节点A失效后,会将数据临时存放在节点D的临时空间中,并在节点A重新可用后,由节点D将数据回传给节点A。
永久性故障处理机制
Dynamo采用Merkle哈希树技术来加快检测和减少数据传输量
每个虚拟节点保存三颗Merkle树,即每个键值区间建立一个Merkle树。Dynamo中Merkle哈希树的叶子节点是存储每个数据分区内所有数据对应的哈希值,父节点是其所有子节点的哈希值。下图是两棵不同的Merkle哈希树A和B。
系统比较两棵同一键值区的Merkle哈希树时,首先査看根节点,如果相同则说明数据一致,不需要进行数据同步,否则需要继续比较,直到哈希值不同的叶子节点,快速定位差异。例如,上图中A和B的根节点不同,说明需要进行数据同步。紧接着比较A和B的子节点,发现右子树的根节点2≠5,继续比较右予树根节点的子节点,按同样的步骤一直进行下去,发现需要同步的数据位置。Merkle树最大特点是只要比较某个子树就可以完成数据同步检测和定位,进而进行同步,大大减少了同步过程中所需传输数据量,提高了系统效率。