本帖最后由 xioaxu790 于 2014-7-21 12:33 编辑
问题导读
1、什么是ring?
2、如何重新平衡ring文件?
3、swift对象信息的SQLite数据库是什么?
swift是openstack的object storage service。最近结合着一些文章大致梳理了一下它的源代码。致谢牛皮糖的博客的深入讲解。
关于代码目录
下图是它的代码目录
其中可以看到几个重要的文件夹:Accout、Ring、Container、obj、proxy。
在物理主机上安装完成的目录为:
/usr/lib/python2.7/dist-packages/swift# ls
account common container __init__.py __init__.pyc obj proxy 复制代码
关于使用到的第三方
swift的对象信息使用是SQLite数据库。SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。
可以通过下面的方法来输出数据库包含的表
import sqlite3
cx=sqlite3.connect("./test.db")
cu=cx.cursor()
cu.execute("select name from sqlite_master where type='table'")
print cu.fetchall() 复制代码
如果需要查看某个数据库的某个表的内容,可以通过下列语句来实现,利于我需要查看test.db内container的内容:
import sqlite3
cx=sqlite3.connect("./test.db")
cu=cx.cursor()
cu.execute("select * from container")
print cu.fetchall() 复制代码
可以通过打开官网的链接详细了解感兴趣的每一个函数,其实可以当做手册来用:Building a Consistent Hashing Ring
但是其中代码并不是全部,如果需要全部的代码,还是需要下载swift的源代码。
关于ring
对于ring的分析有一篇博客分析的比较好,它的原文在:Python Module Index
Ring的Rebalance机制
当集群中发生存储节点宕机、新增(删)存储节点、新增(删)zone等必须改变partition和node间的映射关系时,就需要对Ring文件进行更新,也就是在swift文档中见到的rebalance一词。
在源码中对rebalance的定义如下:swift/Common/Ring/Builder.py
def rebalance(self):
"""
Rebalance the ring.
This is the main work function of the builder, as it will assign and
reassign partitions to devices in the ring based on weights, distinct
zones, recent reassignments, etc.
The process doesn't always perfectly assign partitions (that'd take a
lot more analysis and therefore a lot more time -- I had code that did
that before). Because of this, it keeps rebalancing until the device
skew (number of partitions a device wants compared to what it has) gets
below 1% or doesn't change by more than 1% (only happens with ring that
can't be balanced no matter what -- like with 3 zones of differing
weights with replicas set to 3).
:returns: (number_of_partitions_altered, resulting_balance)
"""
self._ring = None
if self._last_part_moves_epoch is None:
self._initial_balance()
self.devs_changed = False
return self.parts, self.get_balance()
retval = 0
self._update_last_part_moves()
last_balance = 0
while True:
reassign_parts = self._gather_reassign_parts()
self._reassign_parts(reassign_parts)
retval += len(reassign_parts)
while self._remove_devs:
self.devs[self._remove_devs.pop()['id']] = 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来构造新Ring时,swift-ring-builder首先要重新计算每个设备所需的partition数量。然后,将需要重新分配的partition收集起来。取消分配给被移除设备上的partition并把这些partition添加到收集列表。从拥有比当前所需的partition数多的设备上随机地取消分配多出的partition并添加到收集列表中。最后,将收集列表中的partition使用与初始化分配时类似的方法重新分配。
在本地执行swift-ring-builder命令行来生成新的ring文件,然后把这些文件复制到集群的每个节点的/etc/swift目录中,所有需要使用ring的server进程会每15秒(默认值)检查一遍ring文件的修改时间mtime,如果发现和内存中的不一致,则重新加载ring文件到内存中去。
举例说明
现在再增加一台存储节点node4并作为zone5,使用相同权重的devcie。那么每个存储节点上的partition数是52428.8。需要从每台存储节点上随机地移除13107.2个partition到收集列表,然后再重新分配这些parttion到node4上。当有partition的replica被重分配时,重分配的时间将被记录。在RingBuilder类内使用min_part_hours来限制在规定时间内,同一个partition不会被移动两次。
由于收集用来重新分配的partition是基于随机的,rebalacne进程并不能一次就可以完美地重平衡ring。为了达到一个较为平衡的ring,rebalacne进程被重复执行直到接近完美(小于1%)或者当rebalacne的提升达不到最小值1%。
具体的操作如下,首先移除旧的ring文件:
rm -f account.builder account.ring.gz backups/account.builder backups/account.ring.gz
....... 复制代码
然后,重新平衡ring文件:
swift-ring-builder account.builder create 18 3 1
swift-ring-builder account.builder add z1-192.168.1.50:6002/sdc 100
swift-ring-builder account.builder add z2-192.168.1.51:6002/sdc 100
swift-ring-builder account.builder add z3-192.168.1.52:6002/sdc 100
swift-ring-builder account.builder add z4-192.168.1.54:6002/sdc 100
swift-ring-builder account.builder add z5-192.168.1.53:6002/sdc 100
swift-ring-builder account.builder rebalance
swift-ring-builder container.builder create 18 3 1
swift-ring-builder container.builder add z1-192.168.1.50:6001/sdc 100
swift-ring-builder container.builder add z2-192.168.1.51:6001/sdc 100
swift-ring-builder container.builder add z3-192.168.1.52:6001/sdc 100
swift-ring-builder container.builder add z4-192.168.1.54:6001/sdc 100
swift-ring-builder container.builder add z5-192.168.1.53:6001/sdc 100
swift-ring-builder container.builder rebalance
swift-ring-builder object.builder create 18 3 1
swift-ring-builder object.builder add z1-192.168.1.50:6000/sdc 100
swift-ring-builder object.builder add z2-192.168.1.51:6000/sdc 100
swift-ring-builder object.builder add z3-192.168.1.52:6000/sdc 100
swift-ring-builder object.builder add z4-192.168.1.54:6000/sdc 100
swift-ring-builder object.builder add z5-192.168.1.53:6000/sdc 100
swift-ring-builder object.builder rebalance 复制代码
最后,复制account.ring.gz、container.ring.gz、object.ring.gz到集群的各节点的/etc/swift目录下。这样我们就完成了Ring的重平衡(rebalance)。