分布式存储系统的数据分布
Dynamo在一致性Hash上的负载均衡
本节主要参考自Amazons Dynamo中文
在副本数目为N的情况下,Hash空间中的每个分区上的数据要保存到N个物理节点。例如上图中,假设N=3并且B\C\D都是物理节点,那么分区[A, B]上的数据要保存到B\C\D三节点中。为保证数据可靠性,副本必须保存在物理节点,但是虚拟节点会导致Hash环上连续的N个节点中存在多个节点对应同个物理节点的情况。为此,Dynamo使用preference list来跳过这类节点,保证副本所在的节点是不同的物理节点。
Dynamo在一致性Hash上对负载均衡的考虑:
-
分离分区和分区位置。在Dynamo的第一个方案,Token不仅决定分区对应的节点(也就是分区位置)还决定分区的大小。这种策略的缺点是当节点加入时,分区分裂成两部分,其中一部分的数据要从原有节点中迁移到新加入的节点。由于分区分裂所以原有节点要扫描本地数据以确定哪部分数据要迁移到新节点上,这个过程很费时。此外,每个分区对应一棵Merkle树,分区分裂后需要重新计算Merkle树。Dynamo的第二个方案将hash空间划分成固定的Q个分区,而Token只负责确定分区的位置。如此,当节点加入时,分区不会分裂因而不需要重新计算分区的Merkle树,并且原节点以分区为单位将数据迁移到新节点不需要扫描本地数据确定哪些数据迁入新节点。
-
维持总的Token数目和分区数目相同。Dynamo的第二种方案,每个物理节点的Token随机分布在Hash环上,因此每个Token负责的分区数目也是随机的,这不能实现较好的均衡性。它的第三种方案将维持Token数目和分区数目相同,每个Token对应一个分区,这样在均衡性上是最好的。假设分区数目为Q,系统中物理节点数目为S, 那么每个物理节点的Token数目为Q/S。当节点加入时,原有节点的Token数目从Q/S减少到Q/(S+1),所有减少的Token都分配给了新加入节点的Token(注意:一个Token对应一个分区)。
疑问 负载均衡方面至少应该考虑每个物理节点的磁盘容量以及如何将副本分布在不同的机架。Dynamo论文中提到可以通过设置每个物理节点的Token数目来表示磁盘容量,磁盘容量大的Token数目多,反之,Token数目少。但论文中提到的第三个优化方案中每个物理节点的Token数目是相同的,都为Q/S,也就是说没有采用这种方法来表征磁盘容量。对于副本如何分布到不同机架的问题,论文也只字未提。
针对上面的疑问,我们可以参考OpenStack中Swift组件的实现。Swift组件同Dynamo一样也是用于提供Key-Value存储的,并且都采用一致性Hash来确定数据在物理节点的分布。如下图所示,数据在名字空间中使用“账户名/容器名/对象名”来索引,读写数据时将该索引通过Hash函数映射到Hash空间的分区上。每个分区由一组物理节点来负责,接下来的问题就是,如何保证这个分区上的数据的副本在物理节点的分布可以同时考虑到故障区域以及磁盘的利用率。
每个物理节点都具有一些属性,比如全局唯一的ID号,权重(weight),区域(zone)等。物理节点的权重的大小考虑到了节点磁盘容量的因素,磁盘容量越大权重越大,反之越小;物理节点的区域代表物理节点所在的空间位置,例如区域可以机房或则机架。那么将副本分布到这组物理节点时,可以通过节点的区域属性将副本分布到不同的区域实现故障域的隔离,通过设备的权重属性将副本分布到磁盘利用率低的节点从而实现负载均衡。
最后,介绍下上图中,将数据对象通过MD5散列后,将散列值向右移除得到分区索引的做法: 假设Hash空间为32位(即空间大小为2^32 ),分区大小为 2^m ,那么分区数目为2^(32-m)。对给定的散列值只要向右移动m位就得到了分区的索引, 也就是将散列值除以分区大小2^m。关于OpenStack中Swift组件架构方面的内容可以参考Openstack Swift 原理、架构与 API 介绍一文。
GFS对负载均衡的考虑
GFS除了在创建和拷贝Chunk时考虑负载均衡外,还周期性地调整副本分布以实现负载均衡(同FusionStro的策略相同)。GFS主要考虑以下三个因素:
- 将副本分布在不同机架。这个因素几乎是所有的分布式存储都会考虑的,因为它不仅可以实现负载均衡,更重要的是隔离了故障区域。
- 在磁盘利用率低的Chunk Server上创建Chunk。顺便提下,Dynamo论文中提出的通过控制物理节点的Token数目来考虑磁盘容量的方法在它第三种优化方案中是无法实现的,因为这种方案中每个物理节点的Token数目是相同的。
- 限制Chunk Server最近拷贝或者创建Chunk的数目。如果Chunk Server上最近创建Chunk数目越多就意味着会有越多的数据写入,也就是Chunk Server的负载越大。
在拷贝副本时,GFS基于几个因素对要拷贝Chunk的任务设置了优先级。这些因素包括 1)现有副本数目和复制因子间的差距,例如复制因子为3,但当前只有1个副本,那么拷贝这个副本的优先级要设置高些;2) 拷贝热点数据的优先级要高于冷数据;3) 会阻塞应用程序的拷贝的优先级要高。此外,为防止拷贝产生的流量大大超过客户机流量,GFS对每台Chunk服务器可同时进行拷贝的数目进行了限制(FusionStor在Reblance的时候也有类似的命令行)。
本节主要参考自Google File System中文版
CEPH对负载均衡的考虑
CRUSH算法
副本机架分布、磁盘利用率
(待续)
----------------------------------------------- 独学而无友,则孤陋而寡闻
-----------------------------------------------