原文地址:http://www.oschina.net/translate/crush-controlled-scalable-decentralized-placement-of-replicated-data
论文概况
论文名称:CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data
论文作者:Sage A. Weil Scott A. Brandt Ethan L. Miller Carlos Maltzahn
论文单位:Storage Systems Research Center
University of California, Santa Cruz
刊物名称:SC
刊物全称:International Conference for High Performance Computing, Networking, Storage, and Analysis (formerly Supercomputing)
出版社:IEEE
出版社地址: http://dblp.uni-trier.de/db/conf/sc/
论文分类:CCF-A类会议(计算机体系结构/并行与分布计算/存储系统)
论文发表时间:2006年,长文12页双栏
译文部分
概要
新兴的的大规模分布式存储系统面临着在数十甚至是数百数千的存储设备之间分发PB这个数量级别数据的艰巨任务. 这样的系统必须能够均匀的分配数据和工作负载,以获取对可用资源的高效使用,和系统性能的最大化, 同时要便于系统的扩展以及对硬件故障的管理. 我们已经开发了CRUSH 这样一个伪随机的数据分发功能,它被设计用于分布式的基于对象的存储系统,这样的系统不依赖于某个中央目录就能够将数据对象映射到存储设备. 因为大型系统先天就是动态的,所以CRUSH被设计成便于增加和移除存储,同时能最小化非必要的数据移动. 该算法可容纳各种各样的数据复制和可靠性机制,并按照用户定义的策略来分发数据,这样的策略会强制执行跨越故障域的备份分离.
1. 简介
新兴的对象存储架构注重提高可管理性,可扩展性以及高性能。与常规磁盘块存储相比,对象存储设备在内部对磁盘进行分配管理,对外暴露一个接口,使得外部可以对任意大小的数据进行读写(称之为对象)。在这样的系统中,每个文件被分割称相对小的对象分散地保存在存储集群中。为了防止可能发生的数据丢失,这样的对象在集群中拥有多个拷贝(或者采用其他的一下冗余策略)。对象存储系统以小对象的列表取代了大的块列表简化了数据的布局,分散了低级别的块分配问题。尽管通过降低文件配置元数据和复杂性将极大地改善可伸缩性,但分发数据的基本任务在成千上万的存储设备中,仍然存在不同的能力和性能特征问题。
大多数系统简单滴写入新数据,这带来基本的问题是数据一旦写入,几乎不会再被移动。当数据存储扩展的时候,及时再完美的系统也会变得不稳定,因为新加入的磁盘要不就是空的要不就是装满了新数据。只有根据系统的工作负载,充分利用其余所有的可用资源的,才能使旧或新的磁盘都得到充分利用。
一个健壮的解决方案是将所有的数据随机的分布到可利用的存储设备上。这导致概率平衡地分布和混淆了新旧数据。当新的存储设备加入进来,原有数据的随机样本将被迁移到新的存储设备以保持系统的平衡。这种方法的关键优势是所有设备将同样加载,系统在任何潜在的工作负载量下都表现良好。此外,在一个大的提供一个高水平的并行性和聚合带宽的存储系统,一个大文件将被随机分布在大量可用的设备上。然而,基于简单的散列的分布数量无法应对变化的设备,导致数据的大规模重组。此外,现有的随机分配方案,当数据副本在集群中传播的时候,由于肯那个存储的设备故障,冒着极大的数据丢失风险。
我们开发了CRUSH算法 (Controlled
Replication Under Scalable Hashing),一个伪随机数据分布算法,高效、强劲跨异构分布对象副本,结构化存储集群。CRUSH被实现为一个伪随机的确定性函数,CRUSH 决定一个输入值(通常是一个对象或对象组标识符)映射到一系列的设备中的某一个来存储对象的副本。这与传统方法的不同之处在于,数据放置是不依赖于任何形式的单个文件或者单个对象的目录-CRUSH只需要一个简洁而层次清晰的设备描述,包括存储集群和副本放置策略。这种方法有两个关键的优点:首先,它是完全分布式的,在这个大系统的中的任何一方都可以独立计算任何对象的位置;第二,无论多小的元数据都是静态的,只有当设备被添加或移除是才被改变。
CRUSH的目的是利用可用资源优化分配数据,当存储设备添加或删除时高效地重组数据,以及灵活地约束对象副本放置,当数据同步或者相关硬件故障的时候最大化保证数据安全。支持各种各样的数据安全机制,包括多方复制(镜像),RAID奇偶校验方案或者其他形式的校验码,以及混合方法(比如RAID-10)。这些特性使得CRUSH适合管理对象分布非常大的(PB级别)、要求可伸缩性,性能和可靠性非常高的存储系统。
2. 相关工作
对象存储作为一种可扩展的存储系统,最近被大量关注。大量的文件系统研究和产品采用了对象存储的方法,例如NASD,Panasas, Lustre等等。其他的块存储分布式文件系统像GPFS,FAB 面临着类似数据分布的挑战。在这些系统中使用半随机或启发式算法分配新的数据到可用的存储设备中,但数据很少被迁移以保证数据的平均分布。更重要的是,所有这些系统定位数据都是通过某种形式的元数据目录,而CRUSH算法是依赖于紧凑的集群描述和确定性的映射方法。CRUSH 算法不需要依赖于任何中枢分布器便可以计算出新数据的存储目的地,这是很有进步性意义的分布式算法。Sorrento存储系统使用一致性哈希的最接近CRUSH,但Sorrento不支持对设备的加权控制,设备的加权控制可以均衡分布数据和失败域,提高数据安全性。
尽管显式分配系统的数据迁移问题已经被广泛的研究,但这样的方法严重依赖于元数据,而CRUSH算法则避免了这样的情况。Choy描述算法在新设备加入的时候也能最优地分布对象数据,但不支持权重,复制,或磁盘删除。Brinkmann使用散列函数能在异构的静态集群中分发数据。SCADDAR声称支持添加和删除存储,但只支持有限子集的复制策略。所有这些方法,包括CRUSH的灵活性或者失败域都不是为了提高可靠性。
CRUSH 最接近于RUSH系列的算法基础。RUSH 目前仍然是唯一的利用一致性数据元映射函数有效支持可添加删除加权控制设备的算法文献。尽管有这些基本性质,RUSH解决方案在实践中依然存在不足。CRUSH 完全包含了RUSHP和RUSHT的有用元素,并且解决了以前的未知可靠性问题和数据复制问题,并且提高了性能,具有灵活性。
3. CRUSH 算法
CRUSH算法根据种每个设备的权重尽可能概率平均地分配数据。分布算法是由集群可用存储资源以及其逻辑单元的map控制的。这个map的描述类似于一个大型服务器的描述:服务器由一系列的机柜组成,机柜装满服务器,服务器装满磁盘。数据分配的策略是由定位规则来定义的,定位规则指定了集群中将保存多少个副本,以及数据副本的放置有什么限制。例如,可以指定数据有三个副本,这三个副本必须放置在不同的机柜中,使得三个数据副本不公用一个物理电路。
给定一个输入x,CRUSH 算法将输出一个确定的有序的储存目标向量 ⃗R 。当输入x,CRUSH利用强大的多重整数hash函数根据集群map、定位规则、以及x计算出独立的完全确定可靠的映射关系。CRUSH分配算法是伪随机算法,并且输入的内容和输出的储存位置之间是没有显式相关的。我们可以说CRUSH 算法在集群设备中生成了“伪集群”的数据副本。集群的设备对一个数据项目共享数据副本,对其他数据项目又是独立的。
3.1 分层集群映射
集群映射由设备和桶(buckets)组成,设备和桶都有数值的描述和权重值。桶可以包含任意多的设备或者其他的桶,使他们形成内部节点的存储层次结构,设备总是在叶节点。存储设备的权重由管理员设置以控制相设备负责存储的相对数据量。尽管大型系统的设备含不同的容量大小和性能特点,随机数据分布算法可以根据设备的利用率和负载来分布数据。
这样设备的平均负载与存储的数据量成正比。这导致一维位置指标、权重、应来源于设备的能力。桶的权重是它所包含的元素的权重的总和。
桶可由任意可用存储的层次结构组成。例如,可以创建这样一个集群映射,用名为“shelf”的桶代表最低层的一个主机来包含主机上的磁盘设备,然后用名为“cabinet”的桶来包含安装在同一个机架上的主机。在一个大的系统中,代表机架的“cabinet”桶可能还会包含在“row”桶或者“room”桶里。数据被通过一个伪随机类hash函数递归地分配到层级分明的桶元素中。传统的散列分布技术,一旦存储目标数量有变,就会导致大量的数据迁移;而CRUSH算法是基于桶四个不同的类型,每一个都有不同的选择算法,以解决添加或删除设备造成的数据移动和整体的计算复杂度。
3.2 副本放置
CRUSH 算法的设置目的是使数据能够根据设备的存储能力和宽带资源加权平均地分布,并保持一个相对的概率平衡。副本放置在具有层次结构的存储设备中,这对数据安全也有重要影响。通过反射系统的物理安装组织,CRUSH算法可以将系统模块化,从而定位潜在的设备故障。这些潜在故障的资源包括物理的,比如共用电源,共用的网络。通过向集群映射编码信息,CRUSH副本放置策略可以将数据对象独立在不同故障域,同时仍然保持所需的分布。例如,为了定位可能存在的并发故障,应该确保设备上的数据副本放置在不同的机架、主机、电源、控制器、或其他的物理位置。
CRUSH算法为了适应千篇一律的脚本,像数据复制策略和底层的硬件配置,CRUSH对于每份数据的复制策略或者分布式策略的部署方式,它允许存储系统或者管理员精确地指定对象副本如何放置。例如,有的会选择两个镜像来存储一对数据对象,有的会选择3个镜像来存储2个不同的数据对象,还有的会选择6个甚至更多的便宜廉价RAID-4硬盘设备来存储等等。
在算法1的伪代码中,每个规则都包含了一系列应用在一个简单运行环境的操作。CRUSH函数的整型输入参数就是一个典型的对象名或者标示符,这个参数就像一堆可以被复制在相同机器上的对象复制品。操作take(a)选择了一个在存储层次的bucket并把这个bucket分配给向量i,这是为后面的操作做准备。操作select(n,t)迭代每个元素i,并且在这个点中的子树中选择了n个t类型的项。存储设备有一个绑定类型,并且每个bucket在系统中拥有一个用于分辨buckets中classes的类型区域(例如哪些代表rows,哪些代表cabinets等)。对于每个i,select(n,t)都会从1到n迭代调用,同时通过任何中间buckets降序递归,它伪随机地选择一个通过函数c(r,x)嵌套的项,直到它找到请求t中的一个项。去重后的结果项n|i|会返回给输入变量i,同时也会作为随后被调用的select(n,t)操作的输入参数,或者被移动到用于触发操作的结果向量中。
如表1中示例所示,该法则是从图1架构中的root节点开始,第一个select(1.row)操作选择了一个row类型的单例bucket。随后的select(3,cabinet)操作选择了3个嵌套在下面row2(cab21, cab23, cab24)行中不重复的值,同时,最后的select(1,disk)操作迭代了输入向量中的三个buckets,也选择了嵌套在它们其中的人一个单例磁盘。最后的结果集是三个磁盘空间分配给了三个块,但是所有的结果集都在同一行中。因此,这种方法允许复制品在容器中被同时分割和合并,这些容器包括rows、cabinets、shelves。这种方法对于可靠性和优异的性能要求是非常有利的。这些法则包含了多次take和emit模块,它们允许从不同的存储池中获取不同的存储对象,正如在远程复制脚本或者层叠式设备那样。
3.2.1 冲突,失败和过载
select(n,t) 操作可能会在多种层次的存储体系中查找以定位位于其起始点下的n个不同的t类型项,这是一个由选择的复制数 r =1,…, n部分决定的迭代过程。在此过程中,CRUSH可能会由于以下三个不同原因而丢弃(定位)项并使用修改后的输入参数 r′来重新选择(定位)项:如果某一项已经位于当前集合中(冲突——select(n,t) 的结果必须互不相同),如果设备出现故障,或者过载。虽然故障或过载设备在集群map中尽可能地被标记出来,但他们还是被保留在体系中以避免不必要的数据迁移。CRUSH利用集群map中的可能性,特别是与过度利用相关的可能性,通过伪随机拒绝有选择的转移过载设备中的一小部分数据。对于故障或过载设备,CRUSH通过在select(n,t) 开始时重启递归来达到项在存储集群中的均匀分布(见算法1第11行)。对于冲突情况,替代参数r′首先在迭代的内部级别使用以进行本地查找(见算法1的第14行),这样可以远离比较容易出现冲突的子树以避免全部数据的分布不均(比如桶(数量)比n小的时候)。
3.2.2 复制排名
奇偶检验和纠删码方案相比复制在配置要求上都有些许不同。在原本复制方案中,出现故障后,原先副本(已经拥有该数据的副本)成为新的原本常常是需要的。在这种情况下,CRUSH可以使用r′ = r + f 重新进行选择并使用前n个合适项,其中 f表示执行当前操作select(n,t)过程中定位失败的次数(见算法1第16行)。然而,在奇偶检验和纠删码方案中,CRUSH输出中的存储设备排名或位置是特定的,因为每个目标保存了数据对象中的不同数据。特别是,如果存储设备出现故障,它应在CRUSH输出列表⃗R 的特定位置被替换掉,以保证列表中的其他设备排名保持不变(即查看图2中 ⃗R的位置)。在这种情况下,CRUSH使用r′=r+frn进行重新选择,其中fr是r中的失败尝试次数,这样就可以为每一个复制排名确定一系列在统计上与其他故障独立的候选项。相反的是,RUSH同其他存在的哈希分布函数一样,对于故障设备没有特殊的处理机制,它想当然地假设在使用前n个选项时已经跳过了故障设备,这使得它对于奇偶检验方案很难处理。
3.3 Map的变化和数据移动
在大型文件系统中一个比较典型的部分就是数据在存储资源中的增加和移动。为了避免非对称造成的系统压力和资源的不充分利用,CRUSH主张均衡的数据分布和系统负载。当存储系统中个别设备宕机后,CRUSH会对这些宕机设备做相应标记,并且会将其从存储架构中移除,这样这些设备就不会参与后面的存储,同时也会将其上面的数据复制一份到其它机器进程存储。
当集群架构发生变化后情况就比较复杂了,例如在集群中添加节点或者删除节点。在添加的数据进行移动时,CRUSH的mapping过程所使用的按决策树中层次权重算法比理论上的优化算法∆w /w更有效。在每个层次中,当一个香港子树的权重改变分布后,一些数据对象也必须跟着从下降的权重移动到上升的权重。由于集群架构中每个节点上伪随机位置决策是相互独立的,所以数据会统一重新分布在该点下面,并且无须获取重新map后的叶子节点在权重上的改变。仅仅更高层次的位置发送变化时,相关数据才会重新分布。这样的影响在图3的二进制层次结构中展示了出来。
架构中数据移动的总量有一个最低限度∆w/w,这部分数据将会根据∆w权重重新分布在新的存储节点上。移动数据的增量会根据权重h以及平滑上升的界限h ∆w决定。当∆w非常小以至于几乎接近W时移动数据的总量会通过这个上升界限进行变化,因为在每个递归过程中数据对象移动到一个子树上会有一个最低值和最小相关权重。
3.4 Bucket类型
一般而言,CRUSH的开发是为了协调两个计算目标:map计算的高效性和可伸缩性,以及当添加或者移除存储设备后的数据均衡。在最后,CRUSH定义了4种类型的buckets来代表集群架构中的叶子节点:一般的buckets、列表式buckets、树结构buckets以及稻草类型buckets。对于在数据副本存储的进程中的伪随机选择嵌套项,每个类型的bucket都是建立在不同的内部数据结构和充分利用不同c(r,x)函数的基础上,这些buckets在计算和重构效率上发挥着不同的权衡性。一般的bucket会被所以具有相同权重的项限制,然而其它类型的bucket可以在任何组合权重中包含混合项。这些bucket的差异总结如下表所示:
3.4.1 一般的Bucket
这些存储设备纯粹按个体添加进一个大型存储系统。取而代之的是,新型存储系统上存储的都是文件块,就像将机器添加进机架或者整个机柜一样。这些设备在退役后会被分拆成各个零件。在这样的环境下CRUSH中的一般类型Bucket会被当成一个设备集合一样进行使用,例如多个内存组成的计算集合和多个硬盘组成的存储集合。这样做的最大好处在于,CRUSH可以一直map复制品到一般的Bucket中。在这种情况下,正常使用的Bucket就可以和不能正常使用的Bucket直接互不影响。
当我们使用c(r,x)=(hash(x)+rp)函数从m大小的Bucket中选择一个项时,CRUSH会给一个输入值x和一个复制品r,其中,p是从大于m的素数中随机产生。当r<=m时,我们可以使用一些简单的理论数据来选择一个不重复的项。当r>m时,两个不同的r和一个x会被分解成相同的项。实际上,通过这个存储算法,这将意味着出现一个非零数冲突和回退的概率非常小。
如果这个一般类型的Bucket大小发生改变后,数据将会在这些机器上出现完全重组。
3.4.2 List类型buckets
List类型的buckets组织其内部的内容会像list的方式一样,并且里面的项都有随机的权重。为了放置一个数据副本,CRUSH在list的头部开始添加项并且和除这些项外其它项的权重进行比较。根据hash(x,r,item)函数的值,每个当前项会根据适合的概率被选择,或者出现继续递归查找该list。这种方法重申了数据存储所存在的问题“是大部分新加项还是旧项?”这对于一个扩展中的集群是一个根本且直观的选择:一方面每个数据对象会根性相应的概率重新分配到新的存储设备上,或者依然像以前一样被存储在旧的存储设备上。这样当新的项添加进到bucket中时这些项会获得最优的移动方式。当这些项从list的中间或者末尾进行移动时,list类型的bucket将比较适合这种环境。
RUSH P算法几乎和两个CRUSH里面的单list功能等同。它可以提高集群的可靠性。
3.4.3 树状 Buckets
像任何链表结构一样,列表buckets对于少量的数据项还是高效的,而遇到大量的数据就不合适了,其时间复杂度就太大了。树状buckets由RUSHT发展而来,它通过将这些大量的数据项储存到一个二叉树中来解决这个问题(时间复杂度过大)。它将定位的时间复杂度由 O(n)降低到O(logn),这使其适用于管理大得多设备数量或嵌套buckets。 RUSHT i等价于一个由单一树状bucket组成的二级CRUSH结构,该树状bucket包含了许多一般buckets.
树状buckets是一种加权二叉排序树,数据项位于树的叶子节点。每个递归节点有其左子树和右子树的总权重,并根据一种固定的算法(下面会讲述)进行标记。为了从bucket中选择一个数据项,CRUSH由树的根节点开始(计算),计算输入主键x,副本数量r,bucket标识以及当前节点(初始值是根节点)标志的哈希值,计算的结果会跟(当前节点)左子树和右子树的权重比进行比较,仪确定下次访问的节点。重复这一过程直至到达(存储)相应数据项的叶子节点。定位该数据项最多只需要进行logn次哈希值计算和比较。
该buckett二叉树结点使用一种简单固定的策略来得到二进制数进行标记,以避免当树增长或收缩时标记更改。该树最左侧的叶子节点通常标记为“1”, 每次树扩展时,原来的根节点成为新根节点的左子树,新根节点的标记由原根节点的标记左移一位得到(比如1变成10,10变成100等)。右子树的标记在左子树标记的基础上增加了“1”,拥有6个叶子节点的标记二叉树如图4所示。这一策略保证了当bucket增加(或删除)新数据项并且树结构增长(或收缩)时,二叉树中现有项的路径通过在根节点处增加(或删除)额外节点即可实现,决策树的初始位置随之发生变化。一旦某个对象放入特定的子树中,其最终的mapping将仅由该子树中的权重和节点标记来决定,只要该子树中的数据项不发生变化mapping就不会发生变化。虽然层次化的决策树在嵌套数据项项之间会增加额外的数据迁移,但是这一(标记)策略可以保证移动在可接受范围内,同时还能为非常巨大的bucket提供有效的mapping。
3.4.4 Straw类型Buckets
列表buckets和树状buckets的结构决定了只有有限的哈希值需要计算并与权重进行比较以确定bucket中的项。这样做的话,他们采用了分而治之的方式,要么给特定项以优先权(比如那些在列表开头的项),要么消除完全考虑整个子树的必要。尽管这样提高了副本定位过程的效率,但当向buckets中增加项、删除项或重新计算某一项的权重以改变其内容时,其重组的过程是次最优的。
Straw类型bucket允许所有项通过类似抽签的方式来与其他项公平“竞争”。定位副本时,bucket中的每一项都对应一个随机长度的straw,且拥有最长长度的straw会获得胜利(被选中)。每一个straw的长度都是由固定区间内基于CRUSH输入 x, 副本数目r, 以及bucket项 i.的哈希值计算得到的一个值。每一个straw长度都乘以根据该项权重的立方获得的一个系数 f(wi),这样拥有最大权重的项更容易被选中。比如c(r,x)=maxi(f(wi)hash(x,r,i)). 尽管straw类型bucket定位过程要比列表bucket(平均)慢一倍,甚至比树状bucket都要慢(树状bucket的时间复杂度是log(n)),但是straw类型的bucket在修改时最近邻项之间数据的移动是最优的。
Bucket类型的选择是基于预期的集群增长类型,以权衡映射方法的运算量和数据移动之间的效率,这样的权衡是非常值得的。当buckets是固定时(比如一个存放完全相同磁盘的机柜),一般类型的buckets是最快的。如果一个bucket预计将会不断增长,则列表类型的buckets在其列表开头插入新项时将提供最优的数据移动。这允许CRUSH准确恰当地转移足够的数据到新添加的设备中,而不影响其他bucket项。其缺点是映射速度的时间复杂度为O(n) 且当旧项移除或重新计算权重时会增加额外的数据移动。当删除和重新计算权重的效率特别重要时(比如存储结构的根节点附近(项)),straw类型的buckets可以为子树之间的数据移动提供最优的解决方案。树状buckets是一种适用于任何情况的buckets,兼具高性能与出色的重组效率。
4. 评价
CRUSH基于各种设计目的,包括异构设备间的平衡加权分配,添加或删除设备(包括磁盘故障)时的最小数据移动量,故障域下副本分开放置提高系统可靠性,以及一个灵活的集群介绍和规则系统描述可用存储和分布数据。虽然RUSH的固定集群表示不需要副本放置策略和故障域下的副本分离(CRUSH用此方法提高数据安全性),我们仍然需要考虑它的性能和数据移动行为。
4.1 数据分布
CRUSH的数据分布应该是随机分布的——与对象标识符x和存储设备都是不相关的——并以相同的权重均匀分布在设备中。我们测量了对象在包含多种buckets类型的设备中的分布情况,并将设备使用中的方差与我们希望从完美的随机过程中获取的理论二项概率分布进行对比。当使用概率密度函数pi = wi /W 分布n 个对象时,每一个对象都将被分配到一个固定的设备i上,根据对应的二次关系b(n, p)所期望的设备使用率为μ = n p,标准差为 σ = √n p(1 − p). 在包好多个设备的大型系统中,我们可以估计 1 − p ≃ 1 ,所以标准差为 σ ≃ √μ ——这就是说,当数据量很大时使用率也是比较平坦的4。 正如所期望的,我们发现CRUSH分布对于同构集群和包含不同设备权重的集群都与均值和二次多项式的方差相匹配。
4.1.1 过载保护
虽然CRUSH对于大规模情况能够保持设备利用率的平衡性,但是在随机的过程中,这会导致某个设备的负载远远大于平均负载的概率非0。不同于现存的概率映射算法(包括RUSH),CRUSH拥有一个过载纠正机制,能够重新分配数据。这使得当一个设备有过载危险时,可以按照过度使用的情况成比例地缩减设备的分配量,有选择地稳定过载设备。当超过1000个设备的集群的使用量量超过99%时,虽然过载设备达到47%,CRUSH算法的映射时间增幅不超过20%,并且方差缩小了4倍(跟预期一样)。
4.1.2 差异性与局部故障
前期研究[Santos et al. 2000]表明随机的数据分布提供了与仔细数据分块相匹配的(稍微有些慢)现实世界系统性能。在我们自己的性能测试中,CRUSH作为分布式面向对象存储系统的一部分,我们发现随机对象分布导致约5%左右的写入性能下降,这主要与OSD工作负载中的差异性有关,反过来讲与OSD使用率的差异性水平有关。然而,在实际情况中,这种差异性主要与需要高效的仔细数据分块的同构工作负载(通常是写入操作)相关。更多情况下,工作负载是混合的,并且当他们到达磁盘时(或至少与磁盘布局无关)已经表现出随机性,这导致在设备工作负载和性能(除了仔细的布局)上存在相似的差异性,并且同样会降低吞吐量。我们发现CRUSH的在任何潜在共奏负载面前表现出的稳定分布要远远重于在小工作负载集合下的性能损失。
本次分析中假设设备性能是一直稳定不变的。然而现实世界中的经验表明,分布式存储系统的性能往往会被少量变慢的、过载的、不完整的或其他情况导致的性能差的设备拖后腿。传统上,明确的定位策略可以人工避免上述问题设备的使用,但是像采用哈希分布函数进行定位的往往不能。CRUSH使用已有的负载校正机制将性能下降的设备当作“局部异常”设备处理,并转移特定的数据和工作负载以避免上述性能瓶颈的出现,同时实时校正负载均衡。
存储系统上的细粒度负载平衡可以通过将读取操作的工作负载分布到数据副本中更深层次地缓和设备工作负载中的差异性,这已经被D-SPTF算法验证过 [Lumb et al. 2004]。这种方法尽管(对我们来说)是互补的,但已经远远超出CRUSH映射方法和本文的讨论范畴了。
4.2 重组与数据迁移
我们在以一个即使用了CRUSH也使用了RUSH的拥有7290个设备的集群中评估了由增加或删除操作带来的数据迁移情况。CRUSH集群的深度为四层:9行,每行9个机柜,每个机柜9层架子,每个架子上10个存储设备,总共7290个设备。RUSHT 和RUSHP与两层的CRUSH相同,分别包含一个树状类型bucket和一个列表类型bucket,每个bucket包含了729个一般类型的buckets,每个一般类型的bucket中包含10个存储设备(译者注:总计也是7290个存储设备) 。将结果与理论上的最优迁移量moptimal= ∆w
/W进行比较,其中∆w是增加或删除存储设备的联合权重,W是系统的总权重。比如,扩大系统容量一倍需要将接近一半的已有数据在最优重组算法下迁移到新设备中。
图5显示了以迁移比movement
factor=mactual /mopt imal 表示的相对重组效率,其中1代表最优的对象迁移数目,大于1表示需要额外的数据迁移。X轴代表增加或删除的OSD数量,Y轴代表取对数的迁移比。在所有的情况下,权重改变(相对于整个系统)越大意味着更高效的重组。RUSHP (具有一个单独的,大的列表类型bucket)是一个极端,其对于设备的增加数据迁移量最少(最优的),而对于设备的删除会带来最多的数据迁移(并会带来严重的性能下降,见下面的4.3节)。具有多层列表类型buckets(仅仅对于增加设备而言)或多层straw类型buckets的CRUSH架构,其数据迁移量是第二最少的。拥有树状类型buckets的CRUSH虽然效率上有些下降,但是迁移比要比普通的RUSHT(由于每个树状类型的bucket中存在稍微不平衡的9项二叉树造成)少25%左右。从拥有列表类型的buckets的CRUSH结构中删除设备表现的非常糟糕,正如预料的一样(见3.3节)。
图6显示了当增加或删除嵌套数据项时不同类型的bucket所表现的重组效率(对立的)。树状类型bucket的移动比在logn范围内变化,n代表其二叉树的深度。向列表类型buckets和straw类型buckets中增加项基本上是最优的。一般类型的bucket中,修改会导致数据的完全重组。修改列表类型bucket末尾的数据(比如删除存储最久的数据)同样会导致整个bucket大小的数据迁移。除了特定的限制外,列表类型的buckets对于那些删除操作极少且在一定范围内性能的影响最小的情形都是非常适用的。将一般类型、列表类型、树状类型和straw类型混合的方式可以将常见重组情形中的数据迁移量降至最小,同时保持良好的映射性能。
4.3 算法性能
对于有n 个OSD的集群,计算CRUSH映射要设计成尽可能快的—O(logn)时间复杂度,使设备可以在群集映射改变后快速找到任何对象,或者为对象重新评估适当的存储目标。我们研究CRUSH的性能,相对于RUSHP和 RUSHT 要超过1百万映射到不同大小的集群。图7显示了映射到一组完全由CRUSH集群的8-item 树和 uniform buckets(层次结构的深度是变化的)与RUSH的固定两层次结构的副本的平均时间(微秒)。X轴是系统中设备的数量,是以对数尺度标注,它对应于存储层次结构的深度。CRUSH性能是对数的,相对于设备的数量。RUSHT比带tree buckets的CRUSH略胜一筹,因为稍微简化了代码的复杂性,紧随其后的是list和straw buck等等。RUSHP线性扩展在这个测试中(32768台设备上比CRUSH花超过25倍的时间),虽然在实际情况下,能料到新部署的磁盘的大小随着时间的推移次线性缩放成倍增加略有改善。[Honicky和米勒 2004年]。这些测试用的是2.8 GHz奔腾4 CPU进行的,在几十微秒内整体映射。
CRUSH的效率依赖于存储层级的深度和CRUSH建立在何种bucket类型上。图8 比较了c(r, x)从每种bucket类型中选择一个单一副本需要的时间 (Y )并将之作为作为bucket (X)尺寸的一个函数。在一个高的等级, CRUSH的规模O(log n)—与层级深度成线性关系—倘若是单独的bucket,或许是O(n)(list型和straw型bucket成线性比例),并不会超过一个固定的最大尺寸。何时何地应该使用单独的bucket取决于添加,删除或调整的期望值。 List型bucket相比于Straw型bucket具有一个轻微的性能优势,但是进行删除操作时List型bucket可能会导致过多的数据转移。Tree型 bucket对于很大或正常地修改bucket而言是一个好的选择,因为它具有合适的计算量和重组花费。
CRUSH性能关键—无论是运行时间还是结果质量—都取决与所用的整型哈希函数。伪随机值都是通过使用一个基于Jenkin的32位哈希混淆的整型多输入哈希函数计算得出的[Jenkins 1997]。在它提出的形式里,用于CRUSH映射函数的时间中的45%是花费在计算哈希值上,这使得哈希成为整体速度和分布质量的关键和成熟优化的目标。
4.3.1 疏忽老化
CRUSH 将故障的设备任然保留在存储层级中不仅因为故障是一个典型的临时条件(故障的硬盘通常会被替换掉)而且它避免了低效率的数据重组。如果一个存储系统长时间疏于管理,发生故障但没有及时替换掉的设备的数目是很显著的。尽管CRUSH将会把数据重新分配到无故障的设备中,由于放置算法中高的回溯概率,任然会存在一个小的性能损失。我们评估了一个具有1000个设备的集群的映射速度,而且采用多个将设备标记为故障的百分比。对于相对极端的故障情境:有一半的设备发生故障, 映射计算时间增加了71%。 (这种使之黯然失色的情况可能是由于每个设备的工作负载加倍而严重降低了I/O性能。)
4.4 可靠性
数据安全对大规模存储系统而言是至关重要的,大量的设备使硬件故障而不是软件异常成为规则失效的主要原因。像CRUSH这样的集群复制尤其对随机分布策略感兴趣,因为它们可以扩展与任意给定设备共享数据的节点的数量。这有两个对立(通常说)相反效应。第一,故障后的恢复可以并行进行,因为复制的数据的小片段分布在一大组节点中,减小了恢复时间并缩小了额外的故障的易损窗口期。第二,一个大的节点组意味着同时发生的二次失效导致损失共享数据的概率增加。双路镜像使这两个因素互相抵消,然而随着两个以上副本的分散技术会增加整体数据的安全性[Xin et al. 2004]。
但是多故障的一个关键问题是:总体上,我们不能不能期望它们是独立的——在许多情况下一个单独事件像电源故障或机械破坏将影响多个设备,与分散复制相关的大规模节点组会增加数据损失的风险。CRUSH的通过用户定义故障域(并不存在与RUSH或基于哈希的方案中)副本分离技术就是为了防止这种并发有关的故障引起的数据损失的而特殊设计的。尽管能够明显的减少风险,但是由于缺乏对特定的存储集群配置和相关的历史失效数据的研究,很难量化对整个系统的提升的数量级。尽管我们希望在未来进行这样一个研究,但那超出了本论文的范围。
5. 未来的工作
CRUSH是作为Ceph的一部分来开发的, Ceph是一个PB级分布式文件系统. 当前的研究包括一个主要基于CRUSH特性的智能可靠的分布式对象存储. 目前CRUSH使用的原始规则结构是足够复杂的, 足以支持我们现在可预见的数据分布策略. 一些系统的特殊需求可以通过一个更强大的规则结构来满足.
虽然数据安全问题相关的同步失败是设计CRUSH主要动机, 对实际系统故障的研究需要确定它们的特性和频率,这项工作要在 Markov 或其他量化模型可以用于评估它们对系统的平均数据丢失时间(MTTDL)的精确影响之前进行.
CRUSH的性能高度依赖于一个合适强度的多输入整型哈希函数. 因为它同时影响算法的正确性(结果分布的质量)和速度, 对高速哈希技术的研究是CRUSH充分强大的保证.
6. 结论
分布式存储系统对数据放置的可伸缩性提出了一系列挑战。CRUSH通过将数据分配作为一个伪随机映射函数来应对这些挑战,通过使用基于加权层级结构描述可用存储空间的分布数据取代和消除了对配置元数据的传统需求。集群映射层级结构可以反映出潜在的物理组织和装置的基础结构,例如将存储设备整合到机架,机柜,和数据中心的排,可用的自定义放置规则,规则可以定义宽泛的策略来将对象的副本分散到不同的用户定义故障域 (换句话说, 独立的电源和网络基础设施)。在这种情况下, CRUSH可以减缓现有典型非集群复制伪随机系统相关设备的易损性。CRUSH同样可以通过选择性地从溢出设备中转移数据来处理随机方法的内在设备溢出的风险,这种方法消耗的计算能力最小。
CRUSH用最高效的方式实现所有的这些, 无论是计算效率还是需求的元数据。映射计算的运行时间是O(log n),只需要十几毫秒就可以完成对上千设备的计算。效率,可靠性,和灵活性的强健组合使CRUSH成为大规模分布式存储系统的最有吸引力的选择.
7.致谢
由于R. J. Honicky在RUSH上的出色工作激发了CRUSH的发展。与Richard Golding,Theodore Wong和学生们讨论,存储系统研究中心有力地激励和细化了算法。这项工作得到了劳伦斯利物摩国家实验室(Lawrence Livermore National Laboratory),洛斯阿拉莫斯国家实验室(Los Alamos National Laboratory),美国桑地亚国家实验室(Sandia National Laboratory)在B520714合约下的部分支持。Sage Weil的部分奖学金来自劳伦斯利物摩国家实验室(Lawrence Livermore National Laboratory)。我们还要感谢SSRC的赞助,这还包括惠普实验室(Hewlett Packard Laboratories),IBM,英特尔,微软研究院,网络设备公司(Network Appliance),安吉星(Onstor),Rocksoft,赛门铁克(Symantec)和雅虎(Yahoo)。
8. 源码下载
CRUSH源码版权为LGPL所有,下载地址为 http://www.cs.ucsc.edu/~sage/crush