`
阅读更多
Dynamo 简介

    这个小文打算写成入门级的介绍,所以很多语言不追求准确性。本介绍参考 Amazon 的 Dynamo 论文。需要更详细更准确信息的同学请直接阅读原文。(原文地址http://s3.amazonaws.com/AllThingsDistributed/sosp/amazon-dynamo-sosp2007.pdf) 这篇论文本身没提出什么新的思想,正如论文中所说,贡献在于把非常多的技术结合到了一起,来完成一个系统。



    Dynamo 是个什么东东呢?他是 Amazon 公司的一个分布式 key/value 存储引擎。那么这个什么引擎又是什么?首先,假设一个场景,你的网站要存储用户登陆的ip。这个问题怎么解决呢?传统的方法是用数据库。数据库提供了方便的操作接口,复杂的查询能力以及事物的保证。多好的解决方案啊。尽管应用不需要什么复杂查询,也不需要事物。好,现在假设大家都很喜欢你的网站,访问的人越来越多。一个数据库已经处理不过来了。于是你安装了3台数据库主机,把用户分成了三类(男人,女人,it人;总是有某种方法把用户分成数目大致差不多的几个部分吧)。每次访问的时候,先看用户属于哪一类,然后直接访问存储那类用户数据的数据库。于是处理能力增加了三倍。这个时候你已经实现了一个分布式的存储引擎,Dynamo 就是一个类似的东西。只是它的可靠性,可用性等方面更好一点而已。下面我们看看那个简单的分布式存储系统有什么不方便的地方,而Dynamo是如何解决的。

    先列举一下简单的分布式系统可能存在的问题吧:

    1 很难扩容:如果现在业务发展迅速,3台主机撑不住了,需要加到5台主机,那要如何处理呢?首先要更改分类方法,把用户分成5类,然后重新迁移已经存在的数据。你要在网站上贴个条子,“系统维护中”,然后开始伟大的迁移工程,等到终于迁移完成,发现其实3台也不用了,用户都走光了。

    2 数据可靠性无法保证:有一天,发现有一台数据库服务器的硬盘坏了。麻烦了,本来网站就不赚钱,没用什么高档机器,只有一个定期的增量备份而已。经过一天复杂的恢复工作,你还要对部分用户说,麻烦你们把做过的事情再做一遍啊

    3 单点问题:负责把用户分类,然后决定使用哪个数据服务器的那台主机是网站的命根子啊,它如果宕机,所有的数据都不能访问了,它如果满负荷了,增加数据服务器也不会对整体性能有帮助。我好像看到一台贴满着驱邪保平安符咒的pc server。



    这几个问题,看似不大,解决起来还真的不容易呢。尤其是想到自己的网站也许有一天也会和google有一样多的用户(可能因为你是天才或者google快倒闭了)。现在我们看看 Dynnamo 是怎么解决的吧。



    1 扩容问题:这个问题实际上是数据分布方式的问题(怎么分组)。最简单最容易想到的就是根据资源数目对数据进行哈希分布,比如算出一个哈希值,然后对资源数取模。这种简单处理的结果就是当资源数变化的时候,每个数据重新取模后,其分布方式都可能变化,从而需要迁移大量的数据。举个简单的例子来说明一下,假设我的数据是自然数(1-20),资源现在是三台主机(A,B,C),采用取模分配方式,那么分配后A主机的数据为(1,4,7,10,13,16,19),B为(2,5,8,11,14,17,20) C(3,6,9,12,15,18)  现在增加一台主机D,重新分布后的结果是A(1,5,9,13,17) B(2,6,10,14,18) C(3,7,11,15,19) D(4,8,12,15,20) 可以看到,有大量的数据需要从一台主机迁移到另外一台主机。这个迁移过程是很消耗性能的。需要找到一种方式来尽可能减少对现存数据的影响(没有影响当然也不可能,那说明新添加的主机没有数据)。Dynamo 采用的是 consistent hashing 来解决这个问题的。那么我们先来了解一下什么是consistent hashing。先想象一个圆,或者你自己的手表表面,把它看成是一个首尾相接的数轴,现在我们的数据,自然数,已经分布到这个圆上了,我们可以把我们的资源采用某种方式,随机的分布到这个圆上(图1-1)。







现在我们让每一个资源负责它和上一个资源之间的数据,就是说A来负责区间(C,A],B来负责区间(A,B],C负责区间(B,C]。采用这种策略,当我们增加一个资源主机的时候,比如D(图1-2),那么我们只需要影响新节点相邻的节点A所负责的范围(只需要将A中(C,D]这个区间的数据迁移到D上)就可以了。因为资源节点是随机分布到数据圆上的,所以当资源节点的数量足够多的时候,可以认为每个节点的负载基本是均衡的。这是原始的consistent hashing,Dynamo并没有采用这个模型。这个理想的理论模型跟现实之间有一个问题,在这个理论模型上,每个资源节点的能力是一样的。我的意思是,他们有相同的cpu,内存,硬盘等,也就是有相同的处理能力。可现实世界,我们使用的资源却各有不同,新买的n核机器和老的奔腾主机一起为了节约成本而合作。如果只是这么简单的把机器直接分布上去,性能高的机器得不到充分利用,性能低的机器处理不过来。这个问题怎么解决呢?Dynamo 使用的方法是虚节点。把上面的A B C等都想象成一个逻辑上的节点。一台真实的物理节点可能会包含几个虚节点(逻辑节点),也可能只包含一个,看机器的性能而定。等等,好像我们的网站还没发展成 google 呢,我们能使用的硬件资源还不多,比如就4台主机。这个时候采用上面的方式,把资源随机分布上去,几乎一定会不均衡。这要怎么办呢?我们可以把那个数据圆分成Q等份(每一个等份就是一个虚节点),这个Q要远大于我们的资源数。现在假设我们有S个资源,那么每个资源就承担Q/S个等份。 当一个资源节点离开系统的时候,它所负责的等份要重新均分到其他资源节点上, 一个新节点加入的时候,要从其他的节点”偷”到一定数额的等份。 这个策略下,当一个节点离开系统的时候,虽然需要影响到很多节点,但是注意,迁移的数据总量只是离开那个节点的数据量。同样,一个新节点的加入,迁移的数据总量也只是一个新节点的数据量。之所以有这个效果是因为Q的存在,使得增加和减少机器的时候不需要对已有的数据做重新哈希。这个策略的要求是Q>>S(其实还有存储备份的问题,现在还没介绍到,假设每个数据存储N个备份 则要满足Q>>S*N)。如果业务快速发展,使得不断的增加主机,从而导致Q不再满足Q>>S,那么这个策略将不断的退化。(Dynamo 论文在 section 6。2 比较了三种策略的状况 ,本文只是简单介绍其思想,不是详细翻译)



    2 数据的可靠性:因为我们使用的是廉价的pc机,硬盘损毁或者是其他原因导致的主机不可用是很经常的事情。做这样一个估算,假设一台pc机平均三年就会有一次失效,不可用。那么当一个一千台机器的集群,基本上每天都有机器坏掉,所以某主机不可用是常态,系统必须可以在这样的情况下继续提供服务(哦 虽然你的网站现在刚刚只需要4台主机,可是别忘了,它要成长成为google的)。当然,廉价pc的好处就是便宜。所以我们可以增加系统中数据的备份来使得系统在某台机器挂掉的时候仍旧可用。大家最先想到的方案可能就是对每个节点,建立一个备份节点,如果主节点坏掉了,备份节点可以立刻顶上去(双机热备)。但是仔细想一下,这个方案是让人不放心的。因为当一主一备中的某一台机器坏掉,另外一台就成了一个单点运行的节点。这个时候另外一个节点一旦发生错误,服务就变得不可用,数据也有可能丢失。在一个要求高可靠性的系统上,这是不可忍受的。我们刚刚估算了一个大的集群每天都有机器挂掉。而这种错误,一定要人工介入才能解决。想想系统管理员每天在机房里更换主机的情景以及其他不可预料情况(系统管理员休假或者新买的主机没按时到货等),再想想系统每天都有节点在单点运行,真的是很可怕的事情。事实上,一般工业界认为比较安全的备份数应该是3份。好,那么我们看看做这个备份的时候需要注意的问题。首先,如何选择备份节点。我们可以简单的选择顺序上的后两个节点为备份节点,比如存在节点A的数据,备份到节点B和C。但是当我们前面引入了虚节点的概念的时候就要注意了,有可能C节点和A节点在同一台物理机器上,这个时候就不能选择C做为A的备份了。下一个问题,当一个节点离开系统的时候,比如宕机,这个节点上存储的信息需要继续备份到其它节点上。虽然节点离开了系统,但是因为备份的存在,我们通过其他节点可以恢复出本节点的所有信息,因为该节点的离开,这部分信息的备份数会比要求的备份数少一,所以需要把这部分数据做再备份。同样,当一个节点加入系统,从其他节点偷了数据后,其他节点也需要相应减少备份数。而一个节点如果只是暂时性的不可达,也就是失效一个很短的时间(这种情况是最常发生的),那么需要其他节点暂时接管这个节点的工作,在其可用的时候,把数据增量传送回该节点。在设计上述需求的解决方案的时候,还要考虑一个问题,各个节点间数据备份是同步还是异步。假设我们要求写请求总是尽可能的成功,那么我们的策略是写任何一个节点成功就认为成功。节点之间的数据通过异步形式达成一致。这个时候读请求可能读不到最新写进去的信息,比如我们一个数据在A B C 三个节点各存一份(系统中有三个备份的时候,下面的讨论都是基于这个假设的),那么当写A成功后,另外一个进程从节点C读数据,这个时候C还没收到最新的数据,只能给读请求一个较老的版本。这个可能会带来大问题;同样,如果我们希望读请求总能读到正确的数据,那我们的策略是写的时候要等A B C三个节点都写成功了才认为写成功。这个时候写请求可能要耗较多的时间,甚至根本不能完成(如果有节点不可达)也就是说,系统的一致性,可靠性,原子性,隔离性的问题(ACID)是无法同时达到的。只能在其中做出取舍。Dynamo 的处理方式是把这个选择权交给用户,这就是它的N W R模型。N代表N个备份,W代表要写入至少W份才认为成功,R表示至少读取R个备份。配置的时候要求W+R > N。 因为W+R > N, 所以 R > N-W 这个是什么意思呢?就是读取的份数一定要比总备份数减去确保写成功的倍数的差值要大。也就是说,每次读取,都至少读取到一个最新的版本。注1 从而不会读到一份旧数据。当我们需要高可写的环境的时候(论文中举例,amazon的购物车的添加请求应该是永远不被拒绝的)我们可以配置W = 1 如果N=3 那么R = 3。 这个时候只要写任何节点成功就认为成功,但是读的时候必须从所有的节点都读出数据。如果我们要求读的高效率,我们可以配置 W=N R=1。这个时候任何一个节点读成功就认为成功,但是写的时候必须写所有三个节点成功才认为成功。大家注意,一个操作的耗时是几个并行操作中最慢一个的耗时。比如R=3的时候,实际上是向三个节点同时发了读请求,要三个节点都返回结果才能认为成功。假设某个节点的响应很慢,它就会严重拖累一个读操作的响应速度。

        这里我们需要讨论一下数据版本问题,这个问题不仅仅存在于分布式系统,只是分布式系统的一些要求使得这个问题更复杂。先看个简单的例子,用户x对key1做了一次写入操作,我们设值是数字3。然后用户y读取了key1,这个时候用户y知道的值是3。然后用户x对值做了一个+1操作,将新值写入,现在key1的值是4了。而用户y也做了一次+1操作,然后写入,因为用户y读到的值是3,y不知道这个值现在已经变化了,结果按照语义本应该是5的值,现在还是4。解决这个问题常用的方法是设置一个版本值。用户x第一次写入key1 值3的时候,产生一个版本设为v1。用户y读取的信息中包括版本编号v1。当x做了加1把值4写入的时候,告诉server自己拿到的是版本v1,要在v1的基础上把值改成4。server发现自己保存的版本的确是v1所以就同意这个写入,并且把版本改成v2。这个时候y也要写入4,并且宣称自己是在版本v1上做的修改。但是因为server发现自己手里已经是版本v2了,所以server就拒绝y的写入请求,告诉y,版本错误。这个算法在版本冲突的时候经常被使用。但是刚才我们描述的分布式系统不能简单采用这个方式来实现。假设我们设置了N=3 W=1。现在x写入key1 值3,这个请求被节点A处理,生成了v1版本的数据。然后x用户又在版本v1上进行了一次key1值4的写操作,这个请求这次是节点C处理的。但是节点C还没有收到上一个A接收的版本(数据备份是异步进行的)如果按照上面的算法,他应该拒绝这个请求,因为他不了解版本v1的信息。但是实际上是不可以拒绝的,因为如果C拒绝了写请求,实际上W=1这个配置,这个服务器向客户做出的承诺将被打破,从而使得系统的行为退化成W=N的形式。那么C接收了这个请求,就可能产生前面提到的不一致性。如何解决这个问题呢?Dynamo 的方法是保留所有这些版本,用vector clock记录版本信息。当读取操作发生的时候返回多个版本,由客户端的业务层来解决这个冲突合并各个版本。当然客户端也可以选择最简单的策略,就是最近一次的写覆盖以前的写。这里又引入了一个vector clock算法,这里简单介绍一下。可以把这个vector clock想象成每个节点都记录自己的版本信息,而一个数据,包含所有这些版本信息。来看一个例子:假设一个写请求,第一次被节点A处理了。节点A会增加一个版本信息(A,1)。我们把这个时候的数据记做D1(A,1)。 然后另外一个对同样key(这一段讨论都是针对同样的key的)的请求还是被A处理了于是有D2(A,2)。这个时候,D2是可以覆盖D1的,不会有冲突产生。现在我们假设D2传播到了所有节点(B和C),B和C收到的数据不是从客户产生的,而是别人复制给他们的,所以他们不产生新的版本信息,所以现在B和C都持有数据D2(A,2)。好,继续,又一个请求,被B处理了,生成数据D3(A,2;B,1),因为这是一个新版本的数据,被B处理,所以要增加B的版本信息。假设D3没有传播到C的时候又一个请求被C处理记做D4(A,2;C,1)。假设在这些版本没有传播开来以前,有一个读取操作,我们要记得,我们的W=1 那么R=N=3,所以R会从所有三个节点上读,在这个例子中将读到三个版本。A上的D2(A,2);B上的D3(A,2;B,1);C上的D4(A,2;C,1)这个时候可以判断出,D2已经是旧版本,可以舍弃,但是D3和D4都是新版本,需要应用自己去合并。如果需要高可写性,就要处理这种合并问题。好假设应用完成了冲入解决,这里就是合并D3和D4版本,然后重新做了写入,假设是B处理这个请求,于是有D5(A,2;B,2;C,1);这个版本将可以覆盖掉D1-D4那四个版本。这个例子只举了一个客户的请求在被不同节点处理时候的情况, 而且每次写更新都是可接受的,大家可以自己更深入的演算一下几个并发客户的情况,以及用一个旧版本做更新的情况.

        上面问题看似好像可以通过在三个节点里选择一个主节点来解决,所有的读取和写入都从主节点来进行.但是这样就违背了W=1这个约定,实际上还是退化到W=N的情况了.所以如果系统不需要很大的弹性,W=N为所有应用都接受,那么系统的设计上可以得到很大的简化.Dynamo 为了给出充分的弹性而被设计成完全的对等集群(peer to peer),网络中的任何一个节点都不是特殊的.



    3 单点问题:这个问题的解决要求系统构建的时候是去中心化的。在我们最初的简单系统里有一个中心节点,这个单点的存在使得系统在这一点上变得很脆弱。解决方法就是让系统的每个节点都可以承担起所有需要的功能。这个问题的解决涉及到事情比较多,大和尚在这方面也是刚刚起步,就不打算做过多的介绍了。Dynamo有Seed节点的概念。



    最后再次强调,这个东东只是对原文的部分主题做了一些简化的解释,也许有理解错误的地方,请感兴趣的同学阅读原文。

    注1,最近发现这个地方是有问题的, 这里所说的实际上是一个理想情况, 系统对外提供了强一致性, 实际上在实现的时候, 为了各种均衡的考虑, 并没有真正这样实现, Dynamo提供最终一致性.也就是说, 并不能保证立刻就可以读到新版本, 而是有一定的时间窗.



原文地址:http://rdc.taobao.com/blog/cs/?p=52

分享到:
评论

相关推荐

    uthash开源的hash函数实现

    UTHASH 是一个开源的 C 语言库,提供了一种简单且高效的哈希表实现,用于在 C 代码中快速查找和管理数据结构。这个库的主要功能是提供一个宏定义的集合,可以方便地将结构体转化为哈希表,进而进行添加、删除、查找...

    HASHIN.rar_ABAQUS_Hashin失效准则 abaqus_abaqus hashin_abaqus 三维Hashi

    标题中的"HASHIN.rar_ABAQUS_Hashin失效准则 abaqus_abaqus hashin_abaqus 三维Hashi"表明这是一个关于ABAQUS软件中应用Hashin失效准则进行三维分析的示例或教程。ABAQUS是一款广泛应用的有限元分析软件,尤其在结构...

    3d.zip_3维hashin准则_Hashin 3D_hashin_失效准则_层合板 hashin

    在复合材料领域,Hashin失效准则是一个非常重要的理论模型,尤其在分析三维层合板的强度和稳定性时。Hashin准则由Stanley Hashin在20世纪60年代提出,用于预测多向复合材料的破坏行为。这个准则考虑了内部微裂纹的...

    hashin-strain-3d_hashin_三维hashin_三维hashin失效_失效准则_3D—Hashin_

    **三维Hashin失效准则详解** 在复合材料领域,失效分析是至关重要的,它关系到材料的性能预测和结构安全。Hashin失效准则是一种广泛应用的多向复合材料失效理论,由Shlomo Hashin于1962年提出,主要用于评估多向受...

    UMAT_Hashin3D_hashin

    标题 "UMAT_Hashin3D_hashin" 指涉的是一个专门针对复合材料损伤分析的三维子程序,该程序基于Hashin破坏准则。在有限元分析(FEA)中,用户自定义材料(User-Defined Material,UMAT)是实现特定材料行为建模的一种...

    hashin失效vumat,hashin失效准则介绍,Fortran

    在IT行业中,尤其是在科学计算和工程模拟领域,Hashin失效准则和VUMAT(User-Defined Material subroutine for Nonlinear Analysis in ABAQUS)是两个非常重要的概念。这两个概念主要应用于复合材料、土木工程等领域...

    HASH_hash_stm32hash_stm32hash表_stm32f407_

    在STM32F407上实现的哈希(Hash)算法是数字签名、数据完整性验证等安全应用中的关键组成部分。哈希算法能够将任意长度的输入数据转化为固定长度的输出,通常称为哈希值或消息摘要。 哈希算法的主要特性包括: 1. *...

    GEOHASH Javascript的实现

    2. `geohash-demo.js`:包含`GEOHASH`的JavaScript实现代码,可能包括编码、解码以及相邻`GEOHASH`的计算功能。 3. `labeledmarker.js`:可能是一个辅助库,用于在地图上绘制带有标签的标记,用于展示`GEOHASH`对应...

    hashin失效vumat_hashin破坏准则_vumatfailure_vumathashin失效_hashin_vumat

    在IT行业中,尤其是在模拟仿真和材料科学领域,Hashin失效准则是一种广泛应用的理论,用于预测多相复合材料的破坏行为。VUMAT(User-Defined Viscoplasticity and Damage Material Subroutine)是ABAQUS软件中的一个...

    hashcat for windows

    Hashcat is the self-proclaimed world's fastest password recovery tool. It had a proprietary code base until 2015, but is now released as free software. Versions are available for Linux, OS X, and ...

    Hash值查看以及修改软件(Hash_1.0.4_0523.exe以及HashModifier.exe)

    在IT领域,Hash值是一种广泛使用的数据校验方式,它能够为任何大小的文件生成一个固定长度的唯一标识,这个标识通常称为哈希值或散列值。Hash值查看及修改软件,如"Hash_1.0.4_0523.exe"和"HashModifier.exe",是...

    HASHIN_hashin子程序_imagehashing_Fortran_ABAQUSvumat_

    标题中的"HASHIN_hashin子程序_imagehashing_Fortran_ABAQUSvumat_" 提到了几个关键概念:HASHIN子程序、imagehashing、Fortran编程语言以及ABAQUS的VUMAT(用户材料子程序)。这些元素共同构成了一个在ABAQUS环境下...

    各种Hash函数(JAVA版)

    RS-Hash Function Value: " + ghl.RSHash(key)); System.out.println(" 2. JS-Hash Function Value: " + ghl.JSHash(key)); System.out.println(" 3. PJW-Hash Function Value: " + ghl.PJWHash(key)); System....

    hash字符串函数总结

    在计算机科学中,哈希(Hash)函数是一种用于将任意长度的数据映射为固定长度输出的算法。这种输出通常称为哈希值,它在数据结构(如哈希表)、密码学、数字签名等领域有着广泛的应用。本文将对几种常见的字符串哈希...

    geohash:一个解决计算附近距离的php类库

    5. **整合进业务逻辑**:将`geohash`与你的应用程序结合,例如在用户注册时记录他们的位置,然后在搜索或推荐场景中使用`geohash`进行高效的定位服务。 总的来说,`geohash`为PHP开发者提供了一种强大的工具,它...

    vumat_hashin损伤实体_VUMAT-failure-model_hashin_vumat_abaqus子模型

    本话题聚焦于“vumat_hashin损伤实体_VUMAT-failure-model_hashin_vumat_abaqus子模型”,这是一个基于Hashin渐进损伤准则的用户子程序(VUMAT)实现,用于模拟材料的破坏行为。以下是关于这个主题的详细解释: ...

    Hash工具,小巧绿色hash校验工具,免费hash工具

    常见的哈希算法有MD5(Message-Digest Algorithm 5)、SHA-1(Secure Hash Algorithm 1)、SHA-256等。这些算法的特点是:即使输入数据微小的变化也会导致输出的哈希值显著不同,这就使得哈希值成为验证数据完整性的...

    oracle分区表之hash分区表的使用及扩展

    Oracle分区表中的Hash分区是一种基于哈希算法的分区策略,适用于处理无法清晰定义分区范围的大型数据表。这种分区方式通过计算分区键的哈希值来决定数据存储在哪个分区,以此达到数据分散和负载均衡的目的。Hash分区...

    Nginx安装url_hash插件.doc

    **Nginx与url_hash插件** Nginx是一个高性能的HTTP和反向代理服务器,以其轻量级、高并发处理能力以及丰富的模块扩展性而闻名。然而,Nginx本身并不内置支持url_hash功能,这是一个用于负载均衡的策略,通过将特定...

    geohash-1.3.0.jar

    1)GeoHash用一个字符串表示经度和纬度两个坐标,比如我现在所在位置的GeoHash值为 wx4sv61q; 2)GeoHash标识的并不是一个点,而是一个区域,比如 wx4sv61q 对应的就是一个矩形区域; 3)编码的前缀可以标识更大...

Global site tag (gtag.js) - Google Analytics