1、從部署檔案看Ring
在OpenStaci_Swfit源碼分析-單機部署swift中詳細介紹了swift 部署以及API的基本使用,其中在remakerings中介紹了裝置的添加以及Ring檔案的建立,首先看其具體的部署
#!/bin/bash
cd /etc/swift
rm -f *.builder *.ring.gz backups/*.builder backups/*.ring.gz
swift-ring-builder object.builder create 18 3 1
swift-ring-builder object.builder add z1-127.0.0.1:6010/sdb1 100 #z1 表示 zone1 127.0.0.1:6010 為裝置ip位址和端口号,sdb1為裝置的存儲空間,100代表權重 這些都會調用swift-master/bin/swift-ring-builder 中的main方#法然後再代用swift-master/swift/cli/ringbuilder下的具體方法。ring代碼分析将在下一篇部落格中具體介紹
swift-ring-builder object.builder add z2-127.0.0.1:6020/sdb2 100
swift-ring-builder object.builder add z3-127.0.0.1:6030/sdb3 100
swift-ring-builder object.builder add z4-127.0.0.1:6040/sdb4 100
swift-ring-builder object.builder rebalance
swift-ring-builder container.builder create 18 3 1
swift-ring-builder container.builder add z1-127.0.0.1:6011/sdb1 100
swift-ring-builder container.builder add z2-127.0.0.1:6021/sdb2 100
swift-ring-builder container.builder add z3-127.0.0.1:6031/sdb3 100
swift-ring-builder container.builder add z4-127.0.0.1:6041/sdb4 100
swift-ring-builder container.builder rebalance
swift-ring-builder account.builder create 18 3 1
swift-ring-builder account.builder add z1-127.0.0.1:6012/sdb1 100
swift-ring-builder account.builder add z2-127.0.0.1:6022/sdb2 100
swift-ring-builder account.builder add z3-127.0.0.1:6032/sdb3 100
swift-ring-builder account.builder add z4-127.0.0.1:6042/sdb4 100
swift-ring-builder account.builder rebalance
上面腳本檔案執行後會建立object、container、account三個Ring,在這裡我隻分析Object Ring的建立,其他兩個類似。首先看如何建立Ring檔案:
swift-ring-builder object.builder create 18 3 1
如上腳本片段在執行是首先會,執行/usr/local/bin中的swift-ring-builder這條指令,用vi打開後其裡面内容為:
#!/usr/bin/python
# EASY-INSTALL-DEV-SCRIPT: 'swift==1.13.1.rc1.38.g856c155','swift-ring-builder'
__requires__ = 'swift==1.13.1.rc1.38.g856c155'
from pkg_resources import require; require('swift==1.13.1.rc1.38.g856c155')
del require
__file__ = '/root/swift/bin/swift-ring-builder'
execfile(__file__)
從其實作代碼可以清楚的看出__file__所映射的具體執行代碼,也就是swift源代碼bin檔案夾下的swift-ring-builder,打開此檔案看看其具體的實作
import sys
from swift.cli.ringbuilder import main
if __name__ == "__main__":
sys.exit(main())
從執行main對應的是從swift.cli.ringbuilder中的main函數,找到個檔案,打開看看其具體的代碼實作:
def main(arguments=None):
print Commands.__doc__
exit(0)
global argv, backup_dir, builder, builder_file, ring_file
if arguments:
argv = arguments
else:
argv = sys_argv
if len(argv) < 2:
print "swift-ring-builder %(MAJOR_VERSION)s.%(MINOR_VERSION)s\n" % \
globals()
print Commands.default.__doc__.strip()
print
cmds = [c for c, f in Commands.__dict__.iteritems()
if f.__doc__ and c[0] != '_' and c != 'default']
cmds.sort()
for cmd in cmds:
print Commands.__dict__[cmd].__doc__.strip()
print
print parse_search_value.__doc__.strip()
print
for line in wrap(' '.join(cmds), 79, initial_indent='Quick list: ',
subsequent_indent=' '):
print line
print('Exit codes: 0 = operation successful\n'
' 1 = operation completed with warnings\n'
' 2 = error')
exit(EXIT_SUCCESS)
#根據輸入會得到 .ring.gz 和.builder 檔案
builder_file, ring_file = parse_builder_ring_filename_args(argv)
#對于 swift-ring-builder account.builder 列印 資訊
#print argv
#['/usr/local/bin/swift-ring-builder', 'account.ring.gz']
if exists(builder_file):
#如果存在 builder_file 則加載
builder = RingBuilder.load(builder_file)
#如果 arg<3 或者 argv[2] 不是create 或者 write_builder中的任意一個 則出錯
elif len(argv) < 3 or argv[2] not in('create', 'write_builder'):
print 'Ring Builder file does not exist: %s' % argv[1]
exit(EXIT_ERROR)
backup_dir = pathjoin(dirname(argv[1]), 'backups')
try:
mkdir(backup_dir)
except OSError as err:
if err.errno != EEXIST:
raise
if len(argv) == 2:
command = "default"
else:
command = argv[2]
if argv[0].endswith('-safe'):
try:
#why lock?
with lock_parent_directory(abspath(argv[1]), 15):
#執行指令 如 argv[2]=create 則會 Commands.create()
Commands.__dict__.get(command, Commands.unknown.im_func)()
except exceptions.LockTimeout:
print "Ring/builder dir currently locked."
exit(2)
else:
Commands.__dict__.get(command, Commands.unknown.im_func)()
if __name__ == '__main__':
main()
首先會從
swift-ring-builder object.builder create 18 3 1
截取參數,根據第二個參數argv[1],得到要建立的ring為object ring,并建立object.builder 和object.ring.gz兩個檔案,這兩檔案主要作用就是存入ring的相關資訊。
截取第三個參數argv[2]
if len(argv) == 2:
command = "default"
else:
command = argv[2]
然後是得到command =create 後,
if argv[0].endswith('-safe'):
try:
#why lock?
with lock_parent_directory(abspath(argv[1]), 15):
#執行指令 如 argv[2]=create 則會 Commands.create()
Commands.__dict__.get(command, Commands.unknown.im_func)()
except exceptions.LockTimeout:
print "Ring/builder dir currently locked."
exit(2)
else:
Commands.__dict__.get(command, Commands.unknown.im_func)()
這段代碼就是調用Commands類的具體方法了,我們現在得到的是create,故其會調用Commands類的create方法,同理對于如下腳本片段,從argv[1]中得到要對object ring進行操作,因為執行create後已經建立了object.builder 和object.ring.gz檔案,現在隻需把他們反序列化回來既可。
swift-ring-builder object.builder add z1-127.0.0.1:6010/sdb1 100
swift-ring-builder object.builder add z2-127.0.0.1:6020/sdb2 100
swift-ring-builder object.builder add z3-127.0.0.1:6030/sdb3 100
swift-ring-builder object.builder add z4-127.0.0.1:6040/sdb4 100
上面四條指令時為ring添加4個裝置,如
z1-127.0.0.1:6010/sdb1 100
z1代表zone1 127.0.0.1代表裝置ip位址,6010代表裝置綁定的ip号,sdb1代表裝置的将資料存儲的位置,100為權重。
在添加了裝置後需要對Ring進行重新平衡,語句
swift-ring-builder object.builder rebalance
調用Commands 類中的reblance方法,重新平衡Ring。
2、Ring實作代碼的組織架構
第一節介紹了從部署檔案中看Ring的建立,這一節将介紹Ring的實作中代碼的調用關系:

圖1 Ring中類主要調用關系
上圖簡單的畫出了各個類之間的簡單調用關系,Command類主要是出來運作腳本的,并通過運作腳本出來具體的方法,RingBuilder方法主要是用來出來具體的方法,其save方法是将裝置的一些資訊以及建立環所需要的其他資訊存入*.builder檔案中,RingData類中更多save方法會将replica2part2dev(備份到分區到裝置映射)以及裝置的基本屬性和part_shift(右移位數)存入檔案。Ring類中的_reload()方法對RingData進行反序列化,同時get_part(),get_part_nodes(),get_more_nodes(),提供了對外通路這些資訊的接口。在下面幾篇部落格中我将對這些調用關系以及具體代碼實作做詳細介紹。