openstack swift的副本存放位置解析

我们知道在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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世纪殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值