Swift 1.8.0(Grizzly) 中region的理解 -> A Globally Distributed Cluster

來源:互聯網
上載者:User

在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))

Folsom版本的ring balancer將同一個對象的副本分配到儘可能遠的位置(as-far-as-possible or as-unique-as-possible)。當然,最完美的方案是將這些副本放置到不同的zones中([zone] tier),但是如果只有一個zone可以使用時,那麼就盡量將副本分配到不同的nodes中([zone ip:port] tier),相似的,當如果只有一個node可以使用時,那麼就盡量將副本分配到這個節點上的不同devices([zone ip:port device] tier)。

這種“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))

從以上代碼中,我們可以清晰的看到region被增加到了最頂層的tier,並作為裝置dev的一個新屬性,實現為dev字典的一個新key-value對。

預設情況下,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

 

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.