Ceph Luminous librbd & librados 解析 -- 代碼概述

1. librbd? &? librados介紹

Librbd模塊實現(xiàn)了RBD接口,其基于Librados實現(xiàn)了對RBD的基本操作。

1.1 架構(gòu)概述

????上層應(yīng)用訪問RBD塊設(shè)備有兩種途徑:librbd和krbd。其中l(wèi)ibrbd是一個基于librados的用戶態(tài)接口庫,而krbd是繼承在GNU/Linux內(nèi)核中的一個內(nèi)核模塊,通過用戶態(tài)的rbd命令行工具,可以將RBD塊設(shè)備映射為本地的一個塊設(shè)備文件。

??? 從RBD的架構(gòu)圖中可以看到,RBD塊設(shè)備由于元數(shù)據(jù)信息少且訪問不頻繁,故RBD在Ceph集群中不需要daemon守護(hù)進(jìn)程將元數(shù)據(jù)加載到內(nèi)存進(jìn)行元數(shù)據(jù)訪問加速,所有的元數(shù)據(jù)和數(shù)據(jù)操作直接與集群中的MON服務(wù)和OSD服務(wù)交互。其架構(gòu)圖如下:


????最上層是librbd層,模塊cls_rbd是一個Cls擴(kuò)展模塊,實現(xiàn)了RBD的元數(shù)據(jù)相關(guān)的操作。RBD的數(shù)訪問直接通過Librados來訪問。在最底層是OSDC層完成數(shù)據(jù)的發(fā)送。

1.2 源碼結(jié)構(gòu)

1.2.1 librbd

????在src/librbd和路徑下為librbd的源碼,其中分為.cc文件.h文件和子目錄,文件的大致內(nèi)容為:

??? 1..cc & .h 文件:對應(yīng)組件的源代碼,其中.h為頭文件,具體的實現(xiàn)在.cc中;

??? 2.子目錄:子目錄中文件為針對每個模塊的請求,如針對librbd/operation.cc組件,存在路徑operation,路徑中文件為


? ??????可見相應(yīng)目錄中為對應(yīng)組件的請求的實現(xiàn),這些請求發(fā)送到rados,進(jìn)而實現(xiàn)對osd的操作。

1.2.2 librados

????src/librados中為librados的源碼,內(nèi)容如下


??? 與librbd目錄下源碼相比,librados中的源碼內(nèi)容相對較少,librados.cc中負(fù)責(zé)接口的封裝,具體的實現(xiàn)細(xì)節(jié)在IoCtxImpl.cc中。

2? librados & librbd API介紹

2.1 源碼概覽

????ceph封裝的接口源碼位于src/pybind/路徑下,其中子目錄下的.pyx文件為api接口源碼,文件結(jié)構(gòu)如圖


2.2 主要操作介紹

對于librbd和librados提供的python api接口,本文重點關(guān)注以下操作:

1.? pool的創(chuàng)建和刪除;

2.? image的創(chuàng)建和刪除;

3.??snapshot的創(chuàng)建、利用snapshot進(jìn)行clone操作、snapshot的刪除;

4.??image flatten操作。

? ??下文將按照{(diào)create pool} -> {create image} -> {create snapshot} -> {image clone} -> {image flatten} -> {delete snapshot} -> {delete image} -> {delete pool}的順序來依次介紹上述操作的api接口調(diào)用。

2.2.1 準(zhǔn)備工作:創(chuàng)建鏈接

????在所有的操作之前,首先需要創(chuàng)建對集群的連接,才能進(jìn)行進(jìn)一步的操作:

import rados

import rbd

# connect to cluster

cluster = rados.Rados(conffile='/etc/ceph/ceph.conf')

cluster.connect()

?2.2.2?創(chuàng)建存儲池,并獲取ioctx

????創(chuàng)建了對集群的connection之后,就可以創(chuàng)建存儲池,并獲取ioctx:

# list pool

before_create = cluster.list_pools()

print("before create pools: {0}".format(before_create))

# create pool

cluster.create_pool(POOL)

# list pool

after_create = cluster.list_pools()

print("after create pools: {0}".format(after_create))

# get ioctx

ioctx = cluster.open_ioctx(POOL)

注意:

1. 這里create_pool()接口的輸入不包括pg和pgp,因為pgp和pg的數(shù)量在api中是根據(jù)ceph.conf中參數(shù)設(shè)置

# /etc/ceph/ceph.conf

osd_pool_default_pg_num = {int}

osd_pool_default_pgp_num = {int}

2.2.3 創(chuàng)建image

????創(chuàng)建存儲池并獲取ioctx,就可以開始創(chuàng)建rbd image了

rbd_inst = rbd.RBD()

size = 4 * 1024**3

rbd_inst.create(ioctx, “myimage”, size)

img_list = rbd_inst.list(ioctx)

print("after create images {0}".format(img_list))

注意:

1. 在哪個pool中創(chuàng)建image,ioctx就從哪個pool中獲??;

2. image創(chuàng)建必須顯式指定大小,size計算值為bytes。

2.2.4 創(chuàng)建snapshot

? ??rbd image創(chuàng)建之后,就可以根據(jù)image創(chuàng)建snapshot了。

# create snapshot

print("start to create snapshot")

rbd_img = rbd.Image(ioctx, name=IMG)

rbd_img.create_snap(SNP)

# list snapshot

print("list snapshot")

snap_list = rbd_img.list_snaps()

for item in snap_list:

??? print(item['name'])

注意:

1. 使用的是img.Image()類,與2.2.2區(qū)分;

2. snap_list的類型為rbd.SnapIterator(Image image),使用for循環(huán)迭代的元素為dict,其中有三個key:id(int: numeric identifier of the snapshot), size(int: size of theimage at the time of snapshot (in bytes)), name(str: name of the snapshot).

2.2.5?使用snapshot clone rbd image

? ??如果需要使用snapshot克隆image,需要首先對snapshot進(jìn)行保護(hù),之后才能進(jìn)行clone操作。

# protect snapshot

rbd_img.protect_snap(SNP)

is_protect = rbd_img.is_protected_snap(SNP)

print("{0} protected status:{1}".format(SNP, is_protect))

# image clone

print("clone image")

# parent_ioctx, parent_image_name,parent_snap_name, child_ioctx, child_image_name

rbd_inst.clone(ioctx, “myimage”,“mysnapshot”, ioctx, “clnimg”)

img_list = rbd_inst.list(ioctx)

print("after clone image: {0}".format(img_list))

注意:

????1. rbd.Image()需要與保護(hù)的snpashot一致(即在初始化時需要提供該snapshot隸屬的pool的ioctx和image的name);

????2. clone()函數(shù)必須傳入的五個變量:

(1) parent_ioctx: snapshot父類的ioctx;

(2) parent_image_name: 父image的名稱;

(3) parent_snap_name: 父snapshot的名稱;

(4) child_ioctx: 子image的ioctx;

(5) child_image_name: 子image名稱;

????如果clone之后的image和原來的image位于同一個pool,則兩者的ioctx相同,反之需要從子image所屬的pool獲取子ioctx。

2.2.6 image flatten

? ??image flatten操作使clone生成的rbd image擺脫對snapshot的依賴。

# image flatten

print("flatten image")

clone_img = rbd.Image(ioctx, name=”clnimg”)

clone_img.flatten()

注意:

1. 因為需要訪問的是clone生成的新image,故需要新初始化一個rbd.Image()訪問。

2.2.7 刪除 snapshot / image / pool

# unprotect image

print("unprotect snapshot")

rbd_img.unprotect_snap(SNP)

is_protect = rbd_img.is_protected_snap(SNP)

print("{0} protected status:{1}".format(SNP, is_protect))


# purge snapshot

print("remove snapshot")

rbd_img.remove_snap(SNP)


# close image connection

rbd_img.clone()

clone_img.close()


# remove rbd image

print("remove rbd image")

rbd_inst.remove(ioctx, IMG)

rbd_inst.remove(ioctx, CLN)

注意:

1. 只有在snapshot下的所有image都進(jìn)行flatten操作之后,才能夠unprotect該snapshot;

2. 需要先關(guān)閉rbd.Image()對image的訪問之后,才能移除rbd image。

2.2.7 關(guān)閉鏈接,終止對集群的訪問

# close ioctx

print("close ioctx")

ioctx.close()


# delete pool

print("delete pool")

cluster.delete_pool(POOL)

after_delete = cluster.list_pools()

print("after delete pools:? {0}".format(after_delete))


# close connection

print("close connection")

cluster.shutdown()

注意:

1. 順序:{關(guān)閉ioctx} -> {刪除pool} -> {關(guān)閉cluster鏈接}.

2.4 參考資料

1. librbd(python)

http://docs.ceph.com/docs/master/rbd/api/librbdpy/

2. librados(python)

http://docs.ceph.com/docs/master/rados/api/python/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容