librados的介紹與應用

        一個Ceph客戶端,經過librados直接與OSD交互,來存儲和取出數據。爲了與OSD交互,客戶端應用必須直接調用librados,鏈接一個Ceph Monitor。一旦鏈接好之後,librados會從Monitor處取回一個Cluster map。當客戶端的應用想讀或者取數據的時候,它會建立一個I/O上下文而且與一個pool綁定。經過這個I/O上下文,客戶端將Object的名字提供給librados,而後librados會根據Object的名字和Cluster map計算出相應的PG和OSD的位置。而後客戶端就能夠讀或者寫數據。客戶端的應用無需知道這個集羣的拓撲結構。session

        Ceph Storage Cluster handle封裝了以下客戶端配置,包括:app

        1. 給rados_create()使用的User ID和給rados_create2()使用的user name,其中後者更受推薦異步

        2. Cephx authentication keyasync

        3. Monitor的ID和IP地址函數

        4. 日誌級別ui

        5. 調試級別加密

        因此,從你的app使用集羣的步驟以下:1. 建立一個cluster handle,它將被用來鏈接集羣;2. 使用這個handle來鏈接集羣。爲了鏈接集羣,這個app必須提供一個monitor地址,一個用戶名,還有一個authentication key。spa

步驟一 配置Ceph cluster handle命令行

        那麼到底該如何去配置一個handle?Rados提供了一系列方法讓你來設置所須要的設置的值。對於monitor和加密key的設置,一個簡單的方法就是在ceph.conf文件中設置monitor的地址和keyring的path。舉個例子:調試

        [global]

        mon host    = 192.168.1.155

        keyring        = /etc/ceph/ceph.client.admin.keyring

        一旦你創造了一個handle,那麼能夠經過讀取ceph的配置文件來配置handle,也能夠經過讀取命令行參數或者環境參數來配置handle。     

        

        當鏈接好以後,客戶端的app能夠調用不少函數來影響整個集羣,好比能夠作如下事情:

        * Get cluster statistics

        * Use Pool Operation (exists, create, list, delete)

        * Get and set the configuration

        Ceph有一個很是強大的能力就是綁定不一樣的pool。每一個pool可能擁有不一樣數量的PG,對象拷貝數量和拷貝策略。舉個例子,一個使用SSD的pool能夠被設置爲hot pool來存儲熱數據,一個使用HDD的pool能夠被設置用來存儲冷數據

        下面是一個配置handle並鏈接ceph集羣的C代碼示例: 

#include <stdio.h>

#include <string.h>

#include <rados/librados.h>

int main (int argc, char argv**)

{

        /* Declare the cluster handle and required arguments. */

        rados_t cluster;

        char cluster_name[] = "ceph";

        char user_name[] = "client.admin";

        uint64_t flags;

        /* Initialize the cluster handle with the "ceph" cluster name and the "client.admin" user */

        int err;

        err = rados_create2(&cluster, cluster_name, user_name, flags);

        if (err < 0) {

                fprintf(stderr, "%s: Couldn't create the cluster handle! %s\n", argv[0], strerror(-err));

                exit(EXIT_FAILURE);

        } else {

                printf("\nCreated a cluster handle.\n");

        }

        /* Read a Ceph configuration file to configure the cluster handle. */

        err = rados_conf_read_file(cluster, "/etc/ceph/ceph.conf");

        if (err < 0) {

                fprintf(stderr, "%s: cannot read config file: %s\n", argv[0], strerror(-err));

                exit(EXIT_FAILURE);

        } else {

                printf("\nRead the config file.\n");

        }

        /* Read command line arguments */

        err = rados_conf_parse_argv(cluster, argc, argv);

        if (err < 0) {

                fprintf(stderr, "%s: cannot parse command line arguments: %s\n", argv[0], strerror(-err));

                exit(EXIT_FAILURE);

        } else {

                printf("\nRead the command line arguments.\n");

        }

        /* Connect to the cluster */

        err = rados_connect(cluster);

        if (err < 0) {

                fprintf(stderr, "%s: cannot connect to cluster: %s\n", argv[0], strerror(-err));

                exit(EXIT_FAILURE);

        } else {

                printf("\nConnected to the cluster.\n");

        }

}

步驟二 建立I/O上下文並應用

        當你的應用有一個cluster handle以後而且鏈接上了Ceph集羣以後,你能夠建立一個I/O上下文來讀 或者寫數據。一個I/O上下文綁定到一個特定pool的鏈接。I/O上下文的功能包括以下:

        1. Write/read data and extended attributes

        2. List and iterate over objects and extended attributes

        3. Snapshot pools, list snapshots, etc.

        

        Rados容許你同步或者異步地與cluster交互。

        來看一段C代碼的例子

#include <stdio.h>

#include <string.h>

#include <rados/librados.h>

int main (int argc, const char argv**)

{

        /*

         * Continued from previous C example, where cluster handle and

         * connection are established. First declare an I/O Context.

         */

        rados_ioctx_t io;

        char *poolname = "data";

        err = rados_ioctx_create(cluster, poolname, &io);

        if (err < 0) {

                fprintf(stderr, "%s: cannot open rados pool %s: %s\n", argv[0], poolname, strerror(-err));

                rados_shutdown(cluster);

                exit(EXIT_FAILURE);

        } else {

                printf("\nCreated I/O context.\n");

        }

        /* Write data to the cluster synchronously. */

        err = rados_write(io, "hw", "Hello World!", 12, 0);

        if (err < 0) {

                fprintf(stderr, "%s: Cannot write object \"hw\" to pool %s: %s\n", argv[0], poolname, strerror(-err));

                rados_ioctx_destroy(io);

                rados_shutdown(cluster);

                exit(1);

        } else {

                printf("\nWrote \"Hello World\" to object \"hw\".\n");

        }

        char xattr[] = "en_US";

        err = rados_setxattr(io, "hw", "lang", xattr, 5);

        if (err < 0) {

                fprintf(stderr, "%s: Cannot write xattr to pool %s: %s\n", argv[0], poolname, strerror(-err));

                rados_ioctx_destroy(io);

                rados_shutdown(cluster);

                exit(1);

        } else {

                printf("\nWrote \"en_US\" to xattr \"lang\" for object \"hw\".\n");

        }

        /*

         * Read data from the cluster asynchronously.

         * First, set up asynchronous I/O completion.

         */

        rados_completion_t comp;

        err = rados_aio_create_completion(NULL, NULL, NULL, &comp);

        if (err < 0) {

                fprintf(stderr, "%s: Could not create aio completion: %s\n", argv[0], strerror(-err));

                rados_ioctx_destroy(io);

                rados_shutdown(cluster);

                exit(1);

        } else {

                printf("\nCreated AIO completion.\n");

        }

        /* Next, read data using rados_aio_read. */

        char read_res[100];

        err = rados_aio_read(io, "hw", comp, read_res, 12, 0);

        if (err < 0) {

                fprintf(stderr, "%s: Cannot read object. %s %s\n", argv[0], poolname, strerror(-err));

                rados_ioctx_destroy(io);

                rados_shutdown(cluster);

                exit(1);

        } else {

                printf("\nRead object \"hw\". The contents are:\n %s \n", read_res);

        }

        /* Wait for the operation to complete */

        rados_wait_for_complete(comp);

        /* Release the asynchronous I/O complete handle to avoid memory leaks. */

        rados_aio_release(comp);

        char xattr_res[100];

        err = rados_getxattr(io, "hw", "lang", xattr_res, 5);

        if (err < 0) {

                fprintf(stderr, "%s: Cannot read xattr. %s %s\n", argv[0], poolname, strerror(-err));

                rados_ioctx_destroy(io);

                rados_shutdown(cluster);

                exit(1);

        } else {

                printf("\nRead xattr \"lang\" for object \"hw\". The contents are:\n %s \n", xattr_res);

        }

        err = rados_rmxattr(io, "hw", "lang");

        if (err < 0) {

                fprintf(stderr, "%s: Cannot remove xattr. %s %s\n", argv[0], poolname, strerror(-err));

                rados_ioctx_destroy(io);

                rados_shutdown(cluster);

                exit(1);

        } else {

                printf("\nRemoved xattr \"lang\" for object \"hw\".\n");

        }

        err = rados_remove(io, "hw");

        if (err < 0) {

                fprintf(stderr, "%s: Cannot remove object. %s %s\n", argv[0], poolname, strerror(-err));

                rados_ioctx_destroy(io);

                rados_shutdown(cluster);

                exit(1);

        } else {

                printf("\nRemoved object \"hw\".\n");

        }

}


步驟三 關閉session

    當你的APP完成了全部要完成的工做之後,這個app應該可以關閉鏈接而且關閉這個handle。對於異步I/O操做,app還應該保證全部的異步操做已經完成。

    rados_ioctx_destroy(io);

    rados_shutdown(cluster);

相關文章
相關標籤/搜索