Swift作为分布式对象存储,为了解决分布式带来的一系列热点问题,引入了一致性哈希算法。Ring,顾名思义就是环形空间,用于记录存储对象到物理设备之间的映射关系。
Swift通过'Account/Container/Object'来标识一个存储对象,针对Account、Container和Object各有一个Ring,这些Ring默认是存放在各个节点的/etc/swift下,分别是account.ring.gz、container.ring.gz、object.ring.gz,这些都是2进制文件并使用gzip进行压缩。下面学习下这些文件的格式:
首先,使用gzip打开其中一个ring文件:
>>> from gzip import GzipFile
>>> from io import BufferedReader
>>> ring_file = '/etc/swift/object.ring.gz'
>>> gz_file = GzipFile(ring_file)
>>> gz_file = BufferedReader(gz_file)
前4个字节是magic字符串“R1NG”
>>> gz_file.read(4)
'R1NG'
接着2个字节是一个以大端模式存放的无符号短整数,代表版本,如下版本为1
>>> import struct
>>> struct.unpack('!H', gz_file.read(2))
(1,)
接着4个字节是一个以大端模式存放的无符号整数,代表后面存放的json字节长度,如下长度为226
>>> struct.unpack('!I', gz_file.read(4))
(226,)
由上面可知接下来226个字节存放的是一个json格式字符串,读取并解析如下。里面的devs字段存放的是整个系统的物理存储设备信息,replica_count表示副本个数(与创建ring时的第二个参数对应),part_shift是用于移位的(如果之前创建ring时的第1个参数为n,那么这里就是(32-n))
>>> import json
>>> ring_dict = json.loads(gz_file.read(226))
>>> ring_dict
{u'devs': [{u'replication_port': 6000, u'zone': 1, u'weight': 100.0, u'ip': u'10.93.192.13', u'region': 1, u'port': 6000, u'replication_ip': u'10.93.192.13',
u'meta': u'', u'device': u'vdb1', u'id': 0}], u'part_shift': 14, u'replica_count': 3}
由于part_shift为14,说明partition或者虚拟节点的个数为2的(32-14)次方,那么接下来的2*2^18个字节就存放的是2^18个无符号短整数,每个无符号短整数代表物理设备id,然后这些整数构成的列表就代表着partition到物理设备之间的映射关系,由于副本数为3,那么以上这种映射关系有3份
>>> ring_dict['replica2part2dev_id'] = []
>>> partition_count = 1 << (32 - ring_dict['part_shift'])
>>> for x in xrange(ring_dict['replica_count']):
... ring_dict['replica2part2dev_id'].append(array.array('H', gz_file.read(2 * partition_count)))