openstack swift的副本存放位置解析

来源:互联网 发布:淘宝铁十字勋章价格 编辑:程序博客网 时间:2024/04/24 09:18
我们知道在swift中的副本一般是3个,但是对于这三个副本放在哪里?或者存储位置是怎么选择的呢?这段代码是在/common/ring/ring.py文件中的,现在我们来看看这段代码
 def get_more_nodes(self, part):        """        根据虚节点生成虚节点对应的其他节点        Generator to get extra nodes for a partition for hinted handoff.        预备节点尽量不在主节点上,这会考虑到设备权重,还有就是预备节点原有的顺序        The handoff nodes will try to be in zones other than the        primary zones, will take into account the device weights, and        will usually keep the same sequences of handoffs even with        ring changes.        :param part: partition to get handoff nodes for        :returns: generator of node dicts        See :func:`get_nodes` for a description of the node dicts.        """        if time() > self._rtime:            self._reload()        primary_nodes = self._get_part_nodes(part)#获得主节点        used = set(d['id'] for d in primary_nodes)#used就是使用的主节点的设备ID        same_regions = set(d['region'] for d in primary_nodes)#主节点所在的区域        same_zones = set((d['region'], d['zone']) for d in primary_nodes)#主节点所在的区域        same_ip_ports = set((d['region'], d['zone'], d['ip'], d['port'])                            for d in primary_nodes)#主节点所使用的其他信息        parts = len(self._replica2part2dev_id[0])        start = struct.unpack_from(            '>I', md5(str(part)).digest())[0] >> self._part_shift#获得根据虚节点获得其实位置        inc = int(parts / 65536) or 1 #步长默认是1,        # Multiple loops for execution speed; the checks and bookkeeping get        # simpler as you go along        #hit_all_regions获得主节点的区域和该存储的区域个数是否相同的标记        hit_all_regions = len(same_regions) == self._num_regions        #xrange([start], stop[, step])         #chain依次枚举所给的两个数组,我们可以认为handoff_part是副本节点的计算出的二次虚节点号        for handoff_part in chain(xrange(start, parts, inc),                                  xrange(inc - ((parts - start) % inc),                                         start, inc)):            if hit_all_regions:                # At this point, there are no regions left untouched, so we                # can stop looking.                break            for part2dev_id in self._replica2part2dev_id:                if handoff_part < len(part2dev_id):                    dev_id = part2dev_id[handoff_part]                    dev = self._devs[dev_id]                    region = dev['region']                    if dev_id not in used and region not in same_regions:#如果不是同一设备同时得到的这个设备ID所在的region,还没有使用,则考虑使用该设备                        yield dev                        used.add(dev_id)                        same_regions.add(region)#正在使用的区域增减                        zone = dev['zone']                        ip_port = (region, zone, dev['ip'], dev['port'])                        same_zones.add((region, zone))                        same_ip_ports.add(ip_port)                        if len(same_regions) == self._num_regions:                            hit_all_regions = True                            break        #经过上一步,如果使用的zones已经达到上限则不进行操作        hit_all_zones = len(same_zones) == self._num_zones        for handoff_part in chain(xrange(start, parts, inc),                                  xrange(inc - ((parts - start) % inc),                                         start, inc)):            if hit_all_zones:                # Much like we stopped looking for fresh regions before, we                # can now stop looking for fresh zones; there are no more.                break            for part2dev_id in self._replica2part2dev_id:                if handoff_part < len(part2dev_id):                    dev_id = part2dev_id[handoff_part]                    dev = self._devs[dev_id]                    zone = (dev['region'], dev['zone'])                    if dev_id not in used and zone not in same_zones:#如果不是同一设备同时得到的这个设备ID所在的zone,还没有使用,则考虑使用该设备                        yield dev                        used.add(dev_id)                        same_zones.add(zone)                        ip_port = zone + (dev['ip'], dev['port'])                        same_ip_ports.add(ip_port)                        if len(same_zones) == self._num_zones:                            hit_all_zones = True                            break        hit_all_ip_ports = len(same_ip_ports) == self._num_ip_ports        for handoff_part in chain(xrange(start, parts, inc),                                  xrange(inc - ((parts - start) % inc),                                         start, inc)):            if hit_all_ip_ports:                # We've exhausted the pool of unused backends, so stop                # looking.                break            for part2dev_id in self._replica2part2dev_id:                if handoff_part < len(part2dev_id):                    dev_id = part2dev_id[handoff_part]                    dev = self._devs[dev_id]                    ip_port = (dev['region'], dev['zone'],                               dev['ip'], dev['port'])                    if dev_id not in used and ip_port not in same_ip_ports:#如果不是同一设备同时得到的这个设备ID的IP 或者port有一个不一样,还没有使用,则考虑使用该设备                        yield dev                        used.add(dev_id)                        same_ip_ports.add(ip_port)                        if len(same_ip_ports) == self._num_ip_ports:                            hit_all_ip_ports = True                            break        hit_all_devs = len(used) == self._num_devs        for handoff_part in chain(xrange(start, parts, inc),                                  xrange(inc - ((parts - start) % inc),                                         start, inc)):            if hit_all_devs:                # We've used every device we have, so let's stop looking for                # unused devices now.                break            for part2dev_id in self._replica2part2dev_id:                if handoff_part < len(part2dev_id):                    dev_id = part2dev_id[handoff_part]                    if dev_id not in used:    #如果不是同一设备还没有使用,则考虑使用该设备                        yield self._devs[dev_id]                        used.add(dev_id)                        if len(used) == self._num_devs:                            hit_all_devs = True                            break

这样我们就找到了备份数据的选择策略,


1.首先根据原有的虚节点号计算出新的虚节点号

2.遍历得到的虚节点数组中的虚节点号m

3.检查m所在的region是否被该数据使用,没有则添加

4.检查m所在的zone是否被该数据使用,没有则添加

5.检查m所在的IP和PORT是否完全一直,不完全一致则添加

6.检查m所在的设备和该数据所使用的设备是否是同一设备,不是,则添加

7.添加失败,m变换成下一个虚节点,转到步骤3

8.添加成功,可以作为备份节点

而新的虚节点的计算过程是这样的

parts = len(self._replica2part2dev_id[0])start = struct.unpack_from(            '>I', md5(str(part)).digest())[0] >> self._part_shift#获得根据虚节点获得其实位置inc = int(parts / 65536) or 1 #步长默认是1,
parts则是虚节点的数量?,根据虚节点号计算出MD5值,之后进行移位,得到start,inc则是计算得到的parts对65536的商,如果为0则为1

这样就得到了start  parts    inc,一个集合是以start作为起点  parts作为终点 步长是inc 得到的中间序列

另一个集合的起点是(inc-((parts-start)%inc))  终点是start   步长是inc的中间序列

这样我们就可以得到该数据可以存放的节点信息了!!!

0 0