近来研究副本结构,稍微总结一下,以后继续补充:
在Swift 1.8.0(Grizzly)的新特性中有这么一条:Added support for a region tier above zones,即swift可以答应开发者将zones组织成一个组停止管理了,这个组就是region。
这两天在看Swift G版Ring部分的源码的时候,也发现device字典中增长了region属性,因此决定细心的理解一下这个层次观点。
首先推荐两篇文章,我对region的理解从这两篇文章中获益颇多:
第一篇是Swift的主要贡献者、region特性的贡献者SwiftStack的文章:A Globally Distributed OpenStack Swift Cluster;
第二篇不止介绍了region的观点,更将region层次下的proxy server等工作流程停止了具体描述。(这篇需要翻墙-。-)
The Ring without Multi-regions
标准的Swift ring是一个答应你将存储设备划分为buckets或者zones的数据结构。在介绍包含regions观点的Ring之前,让我们先来回想一下没有添加region观点版本的Ring结构:
在Essex版本中,Ring builder严格的保障同一个对象的不同的副本分布在不同的zones中,否则Ring的创建过程没法完成。因此,Swift developer就必须在集群中部署至少和副本数一样多的zones以保障Ring可以被胜利创建。
在Folsom版本中,Ring文件的结构被停止了改动,并重新定义了ring balancing的算法,从而极大的提高了Ring创建的效率。在这个版本中,原本严格的保障副本分布在不同zones中的策略被替换成了另一种更为灵活的算法,这个新的算法将zones、nodes、devices组织,从而形成tiers的结构停止分配。
The Ring with Multi-tiers
以下代码是swift 1.7.6(Folsom)中结构tiers结构的代码(common.ring.utils.py)。
def tiers_for_dev(dev): """ Returns a tuple of tiers for a given device in ascending order by length. :returns: tuple of tiers """ t1 = dev['zone'] t2 = "{ip}:{port}".format(ip=dev.get('ip'), port=dev.get('port')) t3 = dev['id'] return ((t1,), (t1, t2), (t1, t2, t3))
这种“as-unique-as-possible”的算法,具有支撑 geographically distributed cluster 的潜质(每向上一层,就增大了一个地理范围),它可以便利的将一个小的集群扩展成一个大集群。因此,我们可以通过增长另一个region tier到这个层次中实现集群的地理分布支撑。一个region本质上是一组共享雷同位置的zones,这组zones可所以一个机架,也可所以一个数据中心。
下图是“as-unique-as-possible”策略下,不同规模Swift中副本寄存策略的示意图,其中绿色圆点代表一个副本,椭圆代表一个disk,一个立方体代表一个node...
The Ring with Multi-regions -> A Globally Distributed Cluster
通过量tiers结构的Ring的介绍,region的观点就非常好理解了。
为了创建一个global cluster,SwiftStack为swift增长了region的观点。Region扩展了Tier的层次,是一个比zone更大的区域,一组zones构成的tier是一个region。
一个寰球的、支撑副本的集群可以通过将storage nodes部署在不同的region中停止创建。同一个region中的zones之间的延迟是绝对较低的,Proxy nodes会对距离它近的region具有亲和性(local affinity,优先拜访),并根据storage nodes所在的region采用“悲观写”的方法将数据写入近来region的storage nodes。如果需要的话,客户端可以通过选项执行一个跨区域(疏忽local affinity)的读/写操作。
如下,为swift 1.8.0 中结构tiers结构的代码(common.ring.utils.py)。
def tiers_for_dev(dev): """ Returns a tuple of tiers for a given device in ascending order by length. :returns: tuple of tiers """ t1 = dev['region'] t2 = dev['zone'] t3 = "{ip}:{port}".format(ip=dev.get('ip'), port=dev.get('port')) t4 = dev['id'] return ((t1,), (t1, t2), (t1, t2, t3), (t1, t2, t3, t4))
默认情况下,swift集群的region为1,从而保障cluster中一定存在一个region,并用“()”表明一个region,作为tier tree的root。以下代码为tier tree的构建过程,代码的doc string将包含region层次的tier tree结构描述的非常清晰,为了便于理解,所以我就一并贴上来了。
def build_tier_tree(devices): """ Construct the tier tree from the zone layout. The tier tree is a dictionary that maps tiers to their child tiers. A synthetic root node of () is generated so that there's one tree, not a forest. Example: region 1 -+---- zone 1 -+---- 192.168.101.1:6000 -+---- device id 0 | | | | | +---- device id 1 | | | | | +---- device id 2 | | | +---- 192.168.101.2:6000 -+---- device id 3 | | | +---- device id 4 | | | +---- device id 5 | +---- zone 2 -+---- 192.168.102.1:6000 -+---- device id 6 | | | +---- device id 7 | | | +---- device id 8 | +---- 192.168.102.2:6000 -+---- device id 9 | +---- device id 10 region 2 -+---- zone 1 -+---- 192.168.201.1:6000 -+---- device id 12 | | | +---- device id 13 | | | +---- device id 14 | +---- 192.168.201.2:6000 -+---- device id 15 | +---- device id 16 | +---- device id 17 The tier tree would look like: { (): [(1,), (2,)], (1,): [(1, 1), (1, 2)], (2,): [(2, 1)], (1, 1): [(1, 1, 192.168.101.1:6000), (1, 1, 192.168.101.2:6000)], (1, 2): [(1, 2, 192.168.102.1:6000), (1, 2, 192.168.102.2:6000)], (2, 1): [(2, 1, 192.168.201.1:6000), (2, 1, 192.168.201.2:6000)], (1, 1, 192.168.101.1:6000): [(1, 1, 192.168.101.1:6000, 0), (1, 1, 192.168.101.1:6000, 1), (1, 1, 192.168.101.1:6000, 2)], (1, 1, 192.168.101.2:6000): [(1, 1, 192.168.101.2:6000, 3), (1, 1, 192.168.101.2:6000, 4), (1, 1, 192.168.101.2:6000, 5)], (1, 2, 192.168.102.1:6000): [(1, 2, 192.168.102.1:6000, 6), (1, 2, 192.168.102.1:6000, 7), (1, 2, 192.168.102.1:6000, 8)], (1, 2, 192.168.102.2:6000): [(1, 2, 192.168.102.2:6000, 9), (1, 2, 192.168.102.2:6000, 10)], (2, 1, 192.168.201.1:6000): [(2, 1, 192.168.201.1:6000, 12), (2, 1, 192.168.201.1:6000, 13), (2, 1, 192.168.201.1:6000, 14)], (2, 1, 192.168.201.2:6000): [(2, 1, 192.168.201.2:6000, 15), (2, 1, 192.168.201.2:6000, 16), (2, 1, 192.168.201.2:6000, 17)], } :devices: device dicts from which to generate the tree :returns: tier tree """ tier2children = defaultdict(set) for dev in devices: for tier in tiers_for_dev(dev): if len(tier) > 1: tier2children[tier[0:-1]].add(tier) else: tier2children[()].add(tier) return tier2children
更多的关于在multi-regions下swift中各个操作的算法细节,可以拜见我在文章开头处给出的两个blogs链接,其中都有非常具体、图文并茂的介绍,我就不重复造轮子啦 =D
文章结束给大家分享下程序员的一些笑话语录: 联想——对内高价,补贴对外倾销的伟大“民族”企业。