侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

Swift中的一致性哈希算法(补充)

2022-06-12 星期日 / 0 评论 / 0 点赞 / 129 阅读 / 5256 字

总结一下,理解算法时的几个问题,搞懂这些基本上就算理解Swift rebalnce的算法了。 Swift如何保证文件的随机存储和保持系统中的平衡性? 例如有4台dev(编号0,1,2,3)2的


    总结一下,理解算法时的几个问题,搞懂这些基本上就算理解Swift rebalnce的算法了。

Swift如何保证文件的随机存储和保持系统中的平衡性?

例如有4dev(编号 01,  2,  3218次幂262144虚节点,我们都知道builder和ring中存储了一个数据结构_replica2part2dev,它表明了partition到replica到dev的映射关系,即某个文件的某个副本存储到哪个dev上,如下图

系统要做的是根据策略来生成随机的分布,让一个文件的三个副本可以存储到3个不同的dev上去。



builder文件到底存的什么?

其实builder文件里存储了一个字典型的数据结构,其中包含了整个系统所有的重要的数据。

                'part_power': self.part_power,                'replicas': self.replicas,                'min_part_hours': self.min_part_hours,                'parts': self.parts,                'devs': self.devs,                'devs_changed': self.devs_changed,                'version': self.version,                '_replica2part2dev': self._replica2part2dev,                '_last_part_moves_epoch': self._last_part_moves_epoch,                '_last_part_moves': self._last_part_moves,                '_last_part_gather_start': self._last_part_gather_start,                '_remove_devs': self._remove_devs

ring文件里到底存了什么?

ring文件只存储记录part分布的数据

 

def serialize_v1(self, file_obj):        # Write out new-style serialization magic and version:        file_obj.write(struct.pack('!4sH', 'R1NG', 1))        ring = self.to_dict()        json_text = json.dumps(            {'devs': ring['devs'], 'part_shift': ring['part_shift'],             'replica_count': len(ring['replica2part2dev_id'])})        json_len = len(json_text)        file_obj.write(struct.pack('!I', json_len))        file_obj.write(json_text)        for part2dev_id in ring['replica2part2dev_id']:            file_obj.write(part2dev_id.tostring())

文件对应的part如何生成

一个上传文件的请求,proxy会来决定哪个node(dev)来存储这个文件和它的副本。然后向选好的dev发送请求。

例如 admin账户,向test容器中,上传一个名字为update.c的文件。会根据/admin/test/update.c + 设置的HASH_PATH_SUFFIX 生成一个md5 的值 然后解析成一个数字 例如35564 这个就是part,然后在_replica2part2dev 中查找它的三个replica所在的dev  ,然后向这三个dev发送请求。

def get_nodes(self, account, container=None, obj=None):        key = hash_path(account, container, obj, raw_digest=True)#md5(/account/contianer/obj + HASH_PATH_SUFFIX).digest()        if time() > self._rtime:            self._reload()        part = struct.unpack_from('>I', key)[0] >> self._part_shift        seen_ids = set()        return part, [self._devs[r[part]] for r in self._replica2part2dev_id                      if not (r[part] in seen_ids or seen_ids.add(r[part]))]
.

sort_key

dev对应的sort_key影响它分配的方式,系统生成一个字符串,它分成三段,进行排序,第一段为dev_want,第二段随机数,第三段dev_id,系统根据这个三段排序,然后查找最想want的dev

   

def _sort_key_for(self, dev):        # The maximum value of self.parts is 2^32, which is 9 hex        # digits wide (0x100000000). Using a width of 16 here gives us        # plenty of breathing room; you'd need more than 2^28 replicas        # to overflow it.        # Since the sort key is a string and therefore an ascii sort applies,        # the maximum_parts_wanted + parts_wanted is used so negative        # parts_wanted end up sorted above positive parts_wanted.        return '%016x.%04x.%04x' % (            (self.parts * self.replicas) + dev['parts_wanted'],            randint(0, 0xffff),            dev['id'])

parts_wanted = (sum_part/sum_weight )*dev_weith-dev_pars

系统设置的part减去已经分配的part 生成想要得到的part

.


广告 广告

评论区