一個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);