ceph rbd:總覽

基本原理

整體概念:
官方文檔:CEPH BLOCK DEVICE
rbd總體架構(gòu)和原理:《ceph設(shè)計(jì)原理與實(shí)現(xiàn)》第六章
rbd快照和克隆補(bǔ)充:《ceph源碼分析》第九章

其他一些不錯(cuò)的資料:
ceph rbd快照原理解析
理解 OpenStack + Ceph (3):Ceph RBD 接口和工具 [Ceph RBD API and Tools]
理解 OpenStack + Ceph (4):Ceph 的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu) [Pool, Image, Snapshot, Clone]

對(duì)外接口

rbd使用方法有兩種:

  1. 通過(guò)librbd,通過(guò)函數(shù)接口來(lái)操作曙搬。
  2. 通過(guò)kernel module彼乌,走kernel 的路徑,使用時(shí)類(lèi)似于普通塊設(shè)備,可以mkfs演训、mount。

kernel module的方式可以參考相關(guān)文檔膝擂。
目前應(yīng)用比較廣泛的是librbd的方式,接入openstack隙弛、iscsi等都是使用的這種方式架馋。下面對(duì)librbd進(jìn)行介紹。

librbd

librbd大部分操作通過(guò)librados來(lái)實(shí)現(xiàn)全闷,部分元數(shù)據(jù)相關(guān)的操作通過(guò)cls模塊直接注冊(cè)在osd上叉寂。

librbd使用方法

作為一個(gè)對(duì)外接口庫(kù),librbd默認(rèn)支持c和cpp总珠,其對(duì)應(yīng)的頭文件在src/include/rbd下屏鳍,針對(duì)c和cpp分別是librdb.h和librbd.hpp勘纯。具體的實(shí)現(xiàn)在src/rbd目錄下。cls相關(guān)的代碼在cls/rbd目錄下钓瞭,具體見(jiàn)附錄A驳遵。

src/include/rbd/librbd.hpp中最主要的兩個(gè)類(lèi)是class CEPH_RBD_API RBDclass CEPH_RBD_API Image。RBD 主要負(fù)責(zé)創(chuàng)建降淮、刪除超埋、克隆鏡像等操作, 而Image 類(lèi)負(fù)責(zé)鏡像的讀寫(xiě),以及快照相關(guān)的操作等等佳鳖。

要使用librbd,需要先安裝下面兩個(gè)包媒惕∠捣裕可以通過(guò)yum安裝,也可以通過(guò)下載ceph源碼編譯后妒蔚,通過(guò)make install進(jìn)行安裝穿挨。

$  yum list | grep librbd
librbd1.x86_64                          1:0.80.7-3.el7                 base     
librbd1-devel.x86_64                    1:0.80.7-3.el7                 base     

至于如何使用librbd來(lái)編程,請(qǐng)參考下面的代碼肴盏,這是使用librbd的一般流程科盛。
編譯時(shí)記得加上鏈接參數(shù):g++ librbdtest.cpp -lrados -lrbd
更多函數(shù)的使用請(qǐng)參考 librbd.hpp菜皂。另外 這里 有一些不錯(cuò)的示例贞绵。

#include <rbd/librbd.hpp>
#include <rados/librados.hpp>

#include <cstring>
#include <iostream>
#include <string>

void err_msg(int ret, const std::string &msg = ""){
    std::cerr<< "[error] msg:" << msg << " strerror: " << strerror(-ret) <<  std::endl;
}
void err_exit(int ret, const std::string &msg = ""){
    err_msg(ret, msg);
    exit(EXIT_FAILURE);
}

int main(int argc, char* argv[]) {
    int ret = 0;
    // rados
    librados::Rados rados;

    // use client.admin keyring
    ret = rados.init("admin");
    if (ret < 0)
        err_exit(ret,"failed to initialize rados");
    // read ceph.conf 
    ret = rados.conf_read_file("/path/to/ceph.conf");
    if (ret < 0)
        err_exit(ret, "failed to parse ceph.conf");
    // connect to cluster
    ret = rados.connect();
    if (ret < 0)
        err_exit(ret, "failed to connect to rados cluster");

    std::string pool_name = "rbd";
    librados::IoCtx io_ctx;
    
    ret = rados.ioctx_create(pool_name.c_str(), io_ctx);
    if (ret < 0) {
        rados.shutdown();
        err_exit(ret, "failed to create ioctx");
    }
    
    // rbd
    librbd::RBD rbd;
    
    std::string image_name = "image1";
    librbd::Image image;
    // open image
    ret = rbd.open(io_ctx, image, image_name.c_str());
    if (ret < 0) {
        io_ctx.close();
        rados.shutdown();
        err_exit(ret, "failed to open rbd image");
    }
    
    // now, you can operate image
    
    // check the image info
    librbd::image_info_t info;
    ret = image.stat(info, sizeof info);
    if (ret < 0) {
        err_msg(ret, "get image stat failed");
    } else {
        std::cout << "info.size:" << info.size << std::endl;
        std::cout << "info.obj_size:" << info.obj_size << std::endl;
        std::cout << "info.num_objs:" << info.num_objs << std::endl;
        std::cout << "info.order:" << info.order << std::endl;
        std::cout << "info.block_name_prefix:" << info.block_name_prefix << std::endl;
    }


done:
    image.close();
    io_ctx.close();
    rados.shutdown();
    exit(EXIT_SUCCESS);
}

librbd代碼小窺

這里只是librbd最簡(jiǎn)單的代碼流程,只是為了告知你各個(gè)功能的實(shí)現(xiàn)函數(shù)在哪恍飘,至于執(zhí)行這個(gè)功能所使用的異步機(jī)制等過(guò)程沒(méi)有提及榨崩。

讓我們通過(guò)一些函數(shù)來(lái)看一下librbd的代碼流程。rbd是基于rados實(shí)現(xiàn)的章母,但rados中并沒(méi)有rbd的邏輯母蛛,可以說(shuō),librbd就是rbd的完整實(shí)現(xiàn)乳怎,rados只是作為存儲(chǔ)彩郊。

另外,在librbd中蚪缀,使用了一種獨(dú)特的代碼風(fēng)格秫逝。操作對(duì)外提供的api在class RBD和class Image中,但這些函數(shù)的實(shí)現(xiàn)僅僅是一些參數(shù)的解析和傳遞椿胯,其最終的功能實(shí)現(xiàn)筷登,都會(huì)封裝到一個(gè)名為<operation>Request的類(lèi)中,這個(gè)類(lèi)往往包含完成該操作所必須的數(shù)據(jù)和功能哩盲。在類(lèi)的注釋中還會(huì)包含該操作執(zhí)行邏輯的流程圖前方,或者狀態(tài)圖狈醉。

所以當(dāng)你需要尋找某個(gè)功能的實(shí)現(xiàn)代碼時(shí),直接尋找以這個(gè)功能命名的<operation>Request類(lèi)吧惠险。

RBD::create為例:
1) 首先在librbd.hpp/librbd.cc中苗傅,定義了對(duì)外的create函數(shù)接口。其函數(shù)實(shí)現(xiàn)班巩,簡(jiǎn)單調(diào)用了internal.h/internal.cc中定義的librbd::create函數(shù)渣慕。

2)librbd::create函數(shù)做的主要工作就是準(zhǔn)備create需要的各種參數(shù),準(zhǔn)備create操作可能用到的工具(線程池等)抱慌,然后將這些數(shù)據(jù)封裝到image::CreateRequest對(duì)象中逊桦。最后調(diào)用對(duì)象的send()函數(shù)開(kāi)始執(zhí)行流程。最后通過(guò)cond.wait()來(lái)等待操作的完成抑进。代碼如下:

  int create(IoCtx& io_ctx, const std::string &image_name,
         const std::string &image_id, uint64_t size,
         ImageOptions& opts,
             const std::string &non_primary_global_image_id,
             const std::string &primary_mirror_uuid,
             bool skip_mirror_enable)
  {
    // 此處省略代碼內(nèi)容:
    // 根據(jù)參數(shù)準(zhǔn)備image id强经、order、format等屬性寺渗,沒(méi)有則設(shè)默認(rèn)值
    ...
    if (old_format) {
      // 如果是舊版的format匿情,調(diào)用format v1的create函數(shù),現(xiàn)在很少使用
      r = create_v1(io_ctx, image_name.c_str(), size, order);
    } else {
      // 從ceph ctx中獲得全局的線程池和隊(duì)列
      ThreadPool *thread_pool;
      ContextWQ *op_work_queue;
      ImageCtx::get_thread_pool_instance(cct, &thread_pool, &op_work_queue);

      C_SaferCond cond;
      // 創(chuàng)建image::CreateRequest對(duì)象信殊,
      // 其實(shí)就是new 了一個(gè)image::CreateRequest對(duì)象炬称。
      image::CreateRequest<> *req = image::CreateRequest<>::create(
        io_ctx, image_name, id, size, opts, non_primary_global_image_id,
        primary_mirror_uuid, skip_mirror_enable, op_work_queue, &cond);
      req->send();
      // 等待創(chuàng)建請(qǐng)求完成
      r = cond.wait();
    }

    int r1 = opts.set(RBD_IMAGE_OPTION_ORDER, order);
    assert(r1 == 0);

    return r;
  }

3)image::CreateRequest對(duì)象中給出的流程圖,或者說(shuō)狀態(tài)圖涡拘。這幅圖描述了send()函數(shù)執(zhí)行后的邏輯玲躯,其中的狀態(tài)轉(zhuǎn)移是通過(guò)if判斷和函數(shù)調(diào)用來(lái)實(shí)現(xiàn)的。

Image在rados中的創(chuàng)建過(guò)程如下:

  • 創(chuàng)建一個(gè)rbd_id.<name>對(duì)象鲸伴,映射image name到image id府蔗。
  • 增加name_<name>->image idid_<id>->name的映射到rbd_directorty對(duì)象的omap。
  • 創(chuàng)建rbd_header.<id>對(duì)象汞窗,在其omap和xattr中記錄該image的metadata姓赤。
  • 如果開(kāi)啟了object map特性,創(chuàng)建rbd_object_map.<id>對(duì)象仲吏,記錄該image所有data object的情況
  • 數(shù)據(jù)對(duì)象不會(huì)被創(chuàng)建不铆,直到有數(shù)據(jù)寫(xiě)入
  /**
   * @verbatim
   *
   *                                  <start> . . . . > . . . . .
   *                                     |                      .
   *                                     v                      .
   *                               VALIDATE POOL                v (pool validation
   *                                     |                      .  disabled)
   *                                     v                      .
   *                             VALIDATE OVERWRITE             .
   *                                     |                      .
   *                                     v                      .
   * (error: bottom up)           CREATE ID OBJECT. . < . . . . .
   *  _______<_______                    |
   * |               |                   v
   * |               |          ADD IMAGE TO DIRECTORY
   * |               |               /   |
   * |      REMOVE ID OBJECT<-------/    v
   * |               |           NEGOTIATE FEATURES (when using default features)
   * |               |                   |
   * |               |                   v         (stripingv2 disabled)
   * |               |              CREATE IMAGE. . . . > . . . .
   * v               |               /   |                      .
   * |      REMOVE FROM DIR<--------/    v                      .
   * |               |          SET STRIPE UNIT COUNT           .
   * |               |               /   |  \ . . . . . > . . . .
   * |      REMOVE HEADER OBJ<------/    v                     /. (object-map
   * |               |\           OBJECT MAP RESIZE . . < . . * v  disabled)
   * |               | \              /  |  \ . . . . . > . . . .
   * |               |  *<-----------/   v                     /. (journaling
   * |               |             FETCH MIRROR MODE. . < . . * v  disabled)
   * |               |                /   |                     .
   * |     REMOVE OBJECT MAP<--------/    v                     .
   * |               |\             JOURNAL CREATE              .
   * |               | \               /  |                     .
   * v               |  *<------------/   v                     .
   * |               |           MIRROR IMAGE ENABLE            .
   * |               |                /   |                     .
   * |        JOURNAL REMOVE*<-------/    |                     .
   * |                                    v                     .
   * |_____________>___________________<finish> . . . . < . . . .
   *
   * @endverbatim
   */

C_InvokeAsyncRequest相關(guān)的流程之后補(bǔ)充。

附錄A cls/rbd介紹

元數(shù)據(jù)相關(guān)的操作裹唆,通過(guò)cls注冊(cè)到osd上誓斥。

cls是ceph的一個(gè)模塊擴(kuò)展,用戶(hù)可以自定義對(duì)象的接口的實(shí)現(xiàn)方法许帐,通過(guò)動(dòng)態(tài)鏈接的形式加入osd中劳坑,在osd上直接執(zhí)行。在此不做展開(kāi)成畦,具體可以參考這里距芬。

這部分rbd代碼主要包含兩部分涝开,cls_rbd.h/cccls_rbd_client.h/cc。類(lèi)似于服務(wù)端和客戶(hù)端的關(guān)系框仔,前者定義了具體在osd上執(zhí)行的函數(shù)舀武,后者在客戶(hù)端執(zhí)行,將函數(shù)參數(shù)封裝后發(fā)送給服務(wù)端(osd)离斩,然后在osd上執(zhí)行银舱。

snapshot_add函數(shù)為例,該函數(shù)主要負(fù)責(zé)在rbd_header對(duì)象中增加新的snapshot元數(shù)據(jù)信息:

  • cls_rbd.cc函數(shù)中跛梗,對(duì)函數(shù)進(jìn)行定義和注冊(cè)寻馏。下面的代碼注冊(cè)了rbd模塊,以及snapshot_add函數(shù)核偿。
  cls_register("rbd", &h_class);
  cls_register_cxx_method(h_class, "snapshot_add",
              CLS_METHOD_RD | CLS_METHOD_WR,
              snapshot_add, &h_snapshot_add);
  • cls_rbd_client.h/cc定義了通過(guò)客戶(hù)端訪問(wèn)osd注冊(cè)的cls函數(shù)的方法操软。以snapshot_add函數(shù)為例,這個(gè)函數(shù)將參數(shù)封裝進(jìn)bufferlist宪祥,通過(guò)ioctx->exec方法,把操作發(fā)送給osd處理家乘。
    void snapshot_add(librados::ObjectWriteOperation *op, snapid_t snap_id,
              const std::string &snap_name, const cls::rbd::SnapshotNamespace &snap_namespace)
    {
      bufferlist bl;
      ::encode(snap_name, bl);
      ::encode(snap_id, bl);
      ::encode(cls::rbd::SnapshotNamespaceOnDisk(snap_namespace), bl);
      op->exec("rbd", "snapshot_add", bl);
    }
  • cls_rbd.cc定義了方法在服務(wù)端的實(shí)現(xiàn)蝗羊,其一般流程是:從bufferlist將客戶(hù)端傳入的參數(shù)解析出來(lái),調(diào)用對(duì)應(yīng)的方法實(shí)現(xiàn)仁锯,然后將結(jié)果返回客戶(hù)端耀找。
/**
 * Adds a snapshot to an rbd header. Ensures the id and name are unique.
 */
int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
{
  bufferlist snap_namebl, snap_idbl;
  cls_rbd_snap snap_meta;
  uint64_t snap_limit;
  // 從bl中解析參數(shù)
  try {
    bufferlist::iterator iter = in->begin();
    ::decode(snap_meta.name, iter);
    ::decode(snap_meta.id, iter);
    if (!iter.end()) {
      ::decode(snap_meta.snapshot_namespace, iter);
    }
  } catch (const buffer::error &err) {
    return -EINVAL;
  }
  // 判斷參數(shù)合法性,略
  ......
  // 完成操作业崖,在rbd_header對(duì)象中增加新的snapshot元數(shù)據(jù)野芒,并更新sanp_seq。
  map<string, bufferlist> vals;
  vals["snap_seq"] = snap_seqbl;
  vals[snapshot_key] = snap_metabl;
  r = cls_cxx_map_set_vals(hctx, &vals);
  if (r < 0) {
    CLS_ERR("error writing snapshot metadata: %s", cpp_strerror(r).c_str());
    return r;
  }
  return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末双炕,一起剝皮案震驚了整個(gè)濱河市狞悲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌妇斤,老刑警劉巖摇锋,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異站超,居然都是意外死亡荸恕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)死相,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)融求,“玉大人,你說(shuō)我怎么就攤上這事算撮∩穑” “怎么了县昂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)茅糜。 經(jīng)常有香客問(wèn)我七芭,道長(zhǎng),這世上最難降的妖魔是什么蔑赘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任狸驳,我火速辦了婚禮,結(jié)果婚禮上缩赛,老公的妹妹穿的比我還像新娘耙箍。我一直安慰自己,他們只是感情好酥馍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布辩昆。 她就那樣靜靜地躺著,像睡著了一般旨袒。 火紅的嫁衣襯著肌膚如雪汁针。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天砚尽,我揣著相機(jī)與錄音施无,去河邊找鬼。 笑死必孤,一個(gè)胖子當(dāng)著我的面吹牛猾骡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播敷搪,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼兴想,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赡勘?” 一聲冷哼從身側(cè)響起嫂便,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狮含,沒(méi)想到半個(gè)月后顽悼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡几迄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蔚龙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片映胁。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡木羹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坑填,我是刑警寧澤抛人,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站脐瑰,受9級(jí)特大地震影響妖枚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苍在,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一绝页、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寂恬,春花似錦续誉、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至牙咏,卻和暖如春臼隔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背妄壶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工躬翁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盯拱。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像例嘱,于是被迫代替她去往敵國(guó)和親狡逢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 原因:2017年4月14日 星期五 學(xué)習(xí)記錄拼卵。說(shuō)明:整理ceph資料奢浑。我的博客 : http://minichao...
    nicocoi閱讀 8,210評(píng)論 1 9
  • ceph簡(jiǎn)介 Ceph是一個(gè)分布式存儲(chǔ)系統(tǒng),誕生于2004年腋腮,是最早致力于開(kāi)發(fā)下一代高性能分布式文件系統(tǒng)的項(xiàng)目雀彼。隨...
    愛(ài)吃土豆的程序猿閱讀 6,028評(píng)論 0 21
  • 系統(tǒng)環(huán)境: centos73.10.0-514.26.2.el7.x86_64 機(jī)器數(shù)量:五臺(tái) 硬盤(pán):四塊一塊為系...
    think_lonely閱讀 4,683評(píng)論 0 5
  • Ceph Pool操作總結(jié)一個(gè)ceph集群可以有多個(gè)pool,每個(gè)pool是邏輯上的隔離單位即寡,不同的pool可以有...
    think_lonely閱讀 10,910評(píng)論 0 0
  • 集群管理 每次用命令啟動(dòng)徊哑、重啟、停止Ceph守護(hù)進(jìn)程(或整個(gè)集群)時(shí),必須指定至少一個(gè)選項(xiàng)和一個(gè)命令,還可能要指定...
    Arteezy_Xie閱讀 18,852評(píng)論 0 19