深入云存储系统Swift核心组件:Ring数据结构及构建、重平衡操作


  在上一篇深入云存储系统Swift核心组件:Ring实现原理剖析中,我们分析了Ring的设计原理,深入探讨了Swift如何通过Ring组件来实现冗余的、可扩展的目的。本文旨在分析在实际swift的运行中,如何来构建Ring文件。

Ring数据结构

  Ring 的数据结构由三个顶层域构成,其中

  1. List of Devices,表示集群中设备的列表
  2. Partition Assignment List表示partitiondevice的指派;
  3. Partition Shift Value,表示计算数据hash的移位量

1.List of Devices

  设备列表在Ring类内部被称为devs。在设备列表中的每一项是带有以下键的字典:

                                          表1:Devs键值说明

id

integer

device列表中的索引

zone

integer

设备所在的zone

weight

float

device与其他device的相对权重。这常常直接与device和其它device的磁盘空间数量的比有关

ip

string

device的服务器IP地址

port

int

服务器进程所使用的TCP端口用来提供该设备的服务请求

device

string

 服务器上device的磁盘名称。例如:sdb1

meta

string

存储设备额外信息的通用字段。该信息并不直接被服务器进程使用,但是在调试时会派上用场。例如,安装的日期和时间和硬件生产商可以存储在这。

 

2.Partition Assignment List

  用于存放每个replicadevice间映射关系。在Ring类内部被称为_replica2part2dev_id,列表中含有replica数量(3)array(I),array(I)的长度等于ringpartition数量,在array(I)中的每个值为List of Devices中的索引id

3.Partition Shift Value

  Partition Shift Value在Ring类内部称为_part_shift。该值用于转换一个MD5 hash值来计算对于哈希值数据所在的partition使用hash值的前4个字节用于计算。例如,为了计算路径/account/container/object的虚节点,Python代码如下:

partition = unpack_from('>I',md5('/account/container/object').digest())[0] >> self._part_shift

 

  其中>表示big-endian byte order,I表示长度为4 byte unsigned int

 

  举例:我们以SAIO安装下的ring文件为例,使用python读取/etc/swift/object.ring.gz存放的数据,获得的是以devs、 part_shift、 replica2part2dev_id keydict类数据,其中:

 devs=

[{'device': 'sdb1',

  'id': 0,

  'ip': '127.0.0.1',

  'meta': '',

  'port': 6010,

  'weight': 1.0,

  'zone': 1},

{'device': 'sdb2',

  'id': 1,

  'ip': '127.0.0.1',

  'meta': '',

  'port': 6020,

  'weight': 1.0,

  'zone': 2},

{'device': 'sdb3',

  'id': 2,

  'ip': '127.0.0.1',

  'meta': '',

  'port': 6030,

  'weight': 1.0,

  'zone': 3},

{'device': 'sdb4',

  'id': 3,

  'ip': '127.0.0.1',

  'meta': '',

  'port': 6040,

  'weight': 1.0,

  'zone': 4}]

 

part_shift=4

replica2part2dev_id=[array(I, [3, 2...]) array(I, [0, 1...]), array(I, [1, 3...])]

 

构建Ring文件

 

  假设我们配置了一个4个node组成的集群,分别为node0、node1、node2、node3,在这个集群中,我们为4个存储节点配置了2^18个partition,平均每个存储节点分配65536个partition。

  需要使用swift-ring-bulider命令来构建ring文件,关于swift-ring-builder命令的详细用法,在shell下直接敲该命令即可获得提示。这里只涉及构建新Ring文件的方法,需要用到两个相关选项:

  1. 构建相关的builder文件:swift-ring-builder <builder_file> create <part_power> <replicas><min_part_hours>
  2. 添加node到builder文件:swift-ring-builder <builder_file> add  z<zone>-<ip>:<port>/<device_name>_<meta> <weight>

例如,该集群目前ring的配置如下:

swift-ring-builder account.builder create 18 3 1

swift-ring-builder account.builder add z1-192.168.1.50:6002/sdc 100

swift-ring-builder account.builder add z2-192.168.1.51:6002/sdc 100

swift-ring-builder account.builder add z3-192.168.1.52:6002/sdc 100

swift-ring-builder account.builder add z4-192.168.1.54:6002/sdc 100

swift-ring-builder account.builder rebalance

 

swift-ring-builder container.builder create 18 3 1

swift-ring-builder container.builder add z1-192.168.1.50:6001/sdc 100

swift-ring-builder container.builder add z2-192.168.1.51:6001/sdc 100

swift-ring-builder container.builder add z3-192.168.1.52:6001/sdc 100

swift-ring-builder container.builder add z4-192.168.1.54:6001/sdc 100

swift-ring-builder container.builder rebalance

 

swift-ring-builder object.builder create 18 3 1

swift-ring-builder object.builder add z1-192.168.1.50:6000/sdc 100

swift-ring-builder object.builder add z2-192.168.1.51:6000/sdc 100

swift-ring-builder object.builder add z3-192.168.1.52:6000/sdc 100

swift-ring-builder object.builder add z4-192.168.1.54:6000/sdc 100

swift-ring-builder object.builder rebalance

 

Ring的Rebalance机制

  当集群中发生存储节点宕机、新增(删)存储节点、新增(删)zone等必须改变partition和node间的映射关系时,就需要对Ring文件进行更新,也就是在swift文档中见到的rebalance一词。

  在基于原有的Ring构造Ring时,swift-ring-builder首先要重新计算每个设备所需的partition数量。然后,将需要重新分配的partition收集起来。取消分配被移除设备partition并把这些partition添加到收集列表。从拥有比当前所需的partition数多的设备上随机地取消分配多出的partition并添加到收集列表中。最后,收集列表中的partition使用与初始化分配类似的方法重新分配。

  在本地执行swift-ring-builder命令行来生成新的ring文件,然后把这些文件复制到集群的每个节点的/etc/swift目录中,所有需要使用ringserver进程会每15秒(默认值)检查一遍ring文件的修改时间mtime,如果发现和内存中的不一致,则重新加载ring文件到内存中去。

  举例说明

  现在再增加一台存储节点node4并作为zone5,使用相同权重的devcie。那么每个存储节点上的partition数是52428.8。需要从每台存储节点上随机地移除13107.2partition到收集列表,然后再重新分配这些parttionnode4上。当有partitionreplica被重分配时,重分配的时间将被记录。在RingBuilder使用min_part_hours来限制在规定时间内,同一个partition不会被移动两次。

  由于收集用来重新分配partition是基于随机rebalacne进程并不能一次就可以完美地重平衡ring。为了达到一个较为平衡的ringrebalacne进程被重复执行直到接近完美(小于1%)或者当rebalacne的提升达不到最小值1%

  具体的操作如下,首先移除旧的ring文件:

rm -f account.builder account.ring.gz backups/account.builder backups/account.ring.gz

.......

 

  然后,重新平衡ring文件:

swift-ring-builder account.builder create 18 3 1

swift-ring-builder account.builder add z1-192.168.1.50:6002/sdc 100

swift-ring-builder account.builder add z2-192.168.1.51:6002/sdc 100

swift-ring-builder account.builder add z3-192.168.1.52:6002/sdc 100

swift-ring-builder account.builder add z4-192.168.1.54:6002/sdc 100

swift-ring-builder account.builder add z5-192.168.1.53:6002/sdc 100

swift-ring-builder account.builder rebalance

 

swift-ring-builder container.builder create 18 3 1

swift-ring-builder container.builder add z1-192.168.1.50:6001/sdc 100

swift-ring-builder container.builder add z2-192.168.1.51:6001/sdc 100

swift-ring-builder container.builder add z3-192.168.1.52:6001/sdc 100

swift-ring-builder container.builder add z4-192.168.1.54:6001/sdc 100

swift-ring-builder container.builder add z5-192.168.1.53:6001/sdc 100

swift-ring-builder container.builder rebalance

 

swift-ring-builder object.builder create 18 3 1

swift-ring-builder object.builder add z1-192.168.1.50:6000/sdc 100

swift-ring-builder object.builder add z2-192.168.1.51:6000/sdc 100

swift-ring-builder object.builder add z3-192.168.1.52:6000/sdc 100

swift-ring-builder object.builder add z4-192.168.1.54:6000/sdc 100

swift-ring-builder object.builder add z5-192.168.1.53:6000/sdc 100

swift-ring-builder object.builder rebalance

 

  最后,复制account.ring.gzcontainer.ring.gzobject.ring.gz到集群的各节点的/etc/swift目录下。这样我们就完成了Ring的重平衡(rebalance)。

posted @ 2012-06-28 18:30 牛皮糖NewPtone 阅读(...) 评论(...) 编辑 收藏