OpenStack Swift源码分析(5)----swift-ring-builder源代码解析之二
本帖最后由 pig2 于 2014-11-21 15:13 编辑问题导读
1.那个方法实现了从环ring中删除dev_id指定的device?
2.rebalance方法实现了什么功能?
static/image/hrline/4.gif
上一篇
OpenStack Swift源码分析(5)----swift-ring-builder源代码解析之一
接续上一篇博文,继续解析文件swift-ring-builder。
6.来看方法remove_dev:
def remove_dev(self, dev_id):
"""
从环ring中移除一个设备device;
"""
# 根据dev_id获取指定的dev的id;
dev = self.devs
# 设置准备删除dev的weight的值为0;
dev['weight'] = 0
# 记录所删除的dev到列表中;
self._remove_devs.append(dev)
# _set_parts_wanted:方法根据dev的weight计算dev除了目前已经分配的partition数目而外,还要分配的partition数目;
self._set_parts_wanted()
self.devs_changed = True
self.version += 1
这个方法实现了从环ring中删除dev_id指定的device;
7.来看方法rebalance:
def rebalance(self, seed=None):
if seed:
random.seed(seed)
# 令实例中的ring为空
self._ring = None
# _last_part_moves_epoch:表示时间的偏移量;
if self._last_part_moves_epoch is None:
# 增加一些初始化设置的balance方法;
self._initial_balance()
# devs_changed:表明如果设备信息自上一次平衡后已经改变,则赋值为true;
self.devs_changed = False
# 分区数目:self.parts = 2 ** self.part_power;
# get_balance:获取ring的balance的值;
# balance的值具体解释如下:
# 比如一个device至少需要123个partitions,而目前存在的是124个partitions,则balance的值计算如下:
# (124-123)/123
return self.parts, self.get_balance()
retval = 0
# 更新part moved时间;
self._update_last_part_moves()
last_balance = 0
# _adjust_replica2part2dev_size:调整_replica2part2dev的大小,确保_replica2part2dev中的序列长度是正确的,相对于self.replicas当前的值;
# 返回包含两个元素的元组:
# 第一个元素是一个列表(partition,replicas)表示哪些副本需要(重新)分配给设备;
# 第二个元素是一个计数器,表示多少副本需要被move;
new_parts, removed_part_count = self._adjust_replica2part2dev_size()
retval += removed_part_count
self._reassign_parts(new_parts)
retval += len(new_parts)
while True:
# 返回一个list(part,replica)对,需要重新分配;
reassign_parts = self._gather_reassign_parts()
# 重新分配的实际动作;
self._reassign_parts(reassign_parts)
retval += len(reassign_parts)
while self._remove_devs:
# 删除相应的dev;
self.devs] = None
# 获取新的平衡比;
balance = self.get_balance()
if balance < 1 or abs(last_balance - balance) < 1 or retval == self.parts:
break
last_balance = balance
self.devs_changed = False
self.version += 1
return retval, balance
这个方法实现了执行重新平衡ring操作;
这个方法是builder中重要的方法,因为它会对ring上的devices执行分配和重新分配的分区的操作,基于权重、zones和最近执行的重新分配信息等;
程序会根据_last_part_moves_epoch是否为None来决定,程序执行的路线;如果为None(说明是第一次rebalance),程序会调用_initial_balance()方法,然后返回结果;其实它的操作跟_last_part_moves_epoch不为None时,进行的操作大体相同;只是_initial_balance会做一些初始化的操作;而真正执行rebalance操作动作的是_reassign_parts方法;
具体来看代码:
try:
# get_balance:获取执行重新平衡操作之前的ring的balance的值;
# balance的值具体解释如下:
# 比如一个device至少需要123个partitions,而目前存在的是124个partitions,则balance的值计算如下:
# (124-123)/123
# 返回获取的balance的值给last_balance;
last_balance = builder.get_balance()
parts, balance = builder.rebalance(seed=get_seed(3))
except exceptions.RingBuilderError, e:
......
exit(EXIT_ERROR)
首先调用方法get_balance来获取执行重新平衡操作之前的ring的balance的值。具体来看方法get_balance,看看这个值是怎么定义和计算的(注释解析的很清楚了):
def get_balance(self):
"""
获取ring的balance的值;
balance的值具体解释如下:
比如一个device至少需要123个partitions,而目前存在的是124个partitions,则balance的值计算如下:
(124-123)/123
返回获取的balance的值;
"""
balance = 0
# 计算并获取一个分区的权重(weight);
# 从所有设备的总权重(weight)中,返回计算出来的每一个分区的权重(weight);
# 计算方法就是将partition数目乘以副本数得到总的partition数目,然后除以现有dev的weight总和,得到每个partition的权重;
# 实际上得到的是单位权重对应的partition数目;
# return self.parts * self.replicas / sum(d['weight'] for d in self._iter_devs())
weight_of_one_part = self.weight_of_one_part()
for dev in self._iter_devs():
if not dev['weight']:
if dev['parts']:
balance = 999.99
break
continue
# 计算blance的值;
# dev['parts']表示目前所存在的partitions的数目;
# dev['weight'] * weight_of_one_part表示的是根据dev['weight']计算出来的此device所需要的partitions的数目;
dev_balance = abs(100.0 * dev['parts'] / (dev['weight'] * weight_of_one_part) - 100.0)
# 取得和原来相比数值较高的值,赋值给balance;
if dev_balance > balance:
balance = dev_balance
return balance
其次,调用类RingBuilder(object)中的方法rebalance来实现执行重新平衡ring操作,并返回发生变动的parts数目和新的平衡比变量balance。
def rebalance(self, seed=None):
"""
执行重新平衡ring操作;
这个方法是builder中重要的方法,因为它会对ring上的devices执行分配和重新分配的分区的操作,基于权重、zones和最近执行的重新分配信息等;
程序会根据_last_part_moves_epoch是否为None来决定,程序执行的路线;
如果为None(说明是第一次rebalance),程序会调用_initial_balance()方法,然后返回结果;
其实它的操作跟_last_part_moves_epoch不为None时,进行的操作大体相同;
只是_initial_balance会做一些初始化的操作;
而真正执行rebalance操作动作的是_reassign_parts方法;
返回发生变动的parts数目和新的平衡比变量balance;
"""
if seed:
random.seed(seed)
# 令实例中的ring为空
self._ring = None
# _last_part_moves_epoch:表示时间的偏移量;
# 表示partition最后一次迁移时间;
# 如果这个值为None,则在执行平衡操作之前要进行相关变量的初始化,所以调用方法_initial_balance;
if self._last_part_moves_epoch is None:
# 增加一些初始化设置的balance方法;
# 跟rebalance方法实现的功能是一样的,不过就是增加一些初始化方法;
self._initial_balance()
# devs_changed:表明如果设备信息自上一次平衡后已经改变,则赋值为true;
self.devs_changed = False
# 分区数目:self.parts = 2 ** self.part_power;
# get_balance:获取ring的balance的值;
# balance的值具体解释如下:
# 比如一个device至少需要123个partitions,而目前存在的是124个partitions,则balance的值计算如下:
# (124-123)/123
return self.parts, self.get_balance()
retval = 0
# 更新part moved时间;
# 即更新_last_part_moves_epoch;
self._update_last_part_moves()
last_balance = 0
# _adjust_replica2part2dev_size:调整_replica2part2dev的大小,确保_replica2part2dev中的序列长度是正确的,相对于self.replicas当前的值;
# 返回包含两个元素的元组:
# 第一个元素是一个列表(partition,replicas)表示哪些副本需要(重新)分配给设备;
# 第二个元素是一个计数器,表示多少副本需要被move;
new_parts, removed_part_count = self._adjust_replica2part2dev_size()
# 增加需要被move的副本数目;
retval += removed_part_count
# 调用 _reassign_parts 方法,顾名思义,就是从新分配parts的过程;
# 无论是第一次rebalance还是修改后重新rebalance ,最终都是通过这个函数。
self._reassign_parts(new_parts)
# 增加需要新分配dev的part的数目;
retval += len(new_parts)
while True:
# 返回一个list(part,replica)对,需要重新分配;
reassign_parts = self._gather_reassign_parts()
# 重新分配的实际动作;
self._reassign_parts(reassign_parts)
# 增加需要新分配dev的part的数目;
retval += len(reassign_parts)
while self._remove_devs:
# 删除相应的dev;
self.devs] = None
# 获取新的平衡比;
# 获取ring的balance的值;
balance = self.get_balance()
if balance
解析一下这个重要的方法:
(1)看语句:
if self._last_part_moves_epoch is None:
self._initial_balance()
self.devs_changed = False
return self.parts, self.get_balance()
_last_part_moves_epoch:表示partition最后一次迁移时间;
如果_last_part_moves_epoch值为None,则调用方法_initial_balance来完成ring重平衡的操作,然后返回self.parts和方法get_balance获取的平衡比值;
方法_initial_balance完全的实现了ring的重平衡操作,所不同的是,方法中增加对变量_last_part_moves和_last_part_moves_epoch初始化的过程;
def _initial_balance(self):
"""
初始化分区的分配,和重新平衡一个存在的ring是一样的,只不过要事先进行一些初始化操作;
"""
self._last_part_moves = array('B', (0 for _junk in xrange(self.parts)))
self._last_part_moves_epoch = int(time())
self._reassign_parts(self._adjust_replica2part2dev_size())
(2)看代码:
retval = 0
self._update_last_part_moves()
last_balance = 0
new_parts, removed_part_count = self._adjust_replica2part2dev_size()
retval += removed_part_count
self._reassign_parts(new_parts)
retval += len(new_parts)
首先调用方法_update_last_part_moves来实现更新part moved时间,进入这个方法可以看到,具体就是更新了变量_last_part_moves_epoch和_last_part_moves。
方法_adjust_replica2part2dev_size返回了两个值new_parts和removed_part_count。第一个值具体是一个列表(partition,replicas),表示哪些副本需要(重新)分配给设备;第二个值是一个计数器,表示多少副本需要被move。
调用方法_reassign_parts实现对new_parts(需要分配给设备的副本)重新分配parts的过程;
retval表示发生变动的parts数目;
(3)看代码:
while True:
reassign_parts = self._gather_reassign_parts()
self._reassign_parts(reassign_parts)
retval += len(reassign_parts)
while self._remove_devs:
self.devs] = None
balance = self.get_balance()
if balance
这里其实和(2)中的处理是一致的,在swift前面的版本中,没有(2)的那一部分,就我理解而言,(2)也许是做了一个预处理的意思(有时间需要深入分析一下);
这里调用了方法_gather_reassign_parts返回一个list(part,replica)对,表示需要重新分配的副本。接下来调用方法_reassign_parts实现对reassign_parts重新分配的过程。在完成对重新分配之后,获取新的平衡比,当循环满足一定条件之后跳出(前面两个跳出条件还没有很好的理解,而retval
== self.parts说明,所有的parts都被move过了,当然这种情况一般不会出现)。
(4)方法的最后返回了表示新的平衡比变量balance和表示被迁移和重新分配dev的part数目的变量retval;
再回到最初的方法rebalance中,有这样一条语句:
builder.validate()
这是验证ring正确性的一个方法验证环正确的方法,方法确保分区已分配到实际设备,而没有出现双重分配等错误;
方法rebalance的最后是一些文件保存的操作;
至此,swift-ring-builder中的方法rebalance也解析完成。
至此,swift-ring-builder中比较重要的操作方法都解析完成了,其他都是很好理解的方法。
博文中不免有不正确的地方,欢迎朋友们不吝批评指正,谢谢大家了!
上一篇
OpenStack Swift源码分析(5)----swift-ring-builder源代码解析之一
页:
[1]