Ceph 用统一的系统提供了对象、块、和文件存储功能,它可靠性高、管理简便、并且是自由软件。 Ceph 可提供极大的伸缩性——供成千用户访问 PB 乃至 EB 级的数据。 Ceph 节点以普通硬件和智能守护进程作为支撑点, Ceph 存储集群组织起了大量节点,它们之间靠相互通讯来复制数据、并动态地重分布数据。
下图为应用场景示意图,其核心是RADOS,也即高可用、自动化的分布式对象存储,该模块负责对OSD的自动化运行,保证整个存储系统的可用性。同时,该模块通过一个名为librados的公共库对外提供存储服务,块存储和对象存储都依赖该动态库。
同时,Ceph本身封装了对象存储的接口和块存储的接口。对象存储的接口包括对象网关和对象存储访问库等。块存储接口包括块存储访问动态库、Python绑定库和内核态的虚拟块设备。
两个概念:
RADOS 可靠 自动化 分布式 对象 存储
CRUSH Controoled Replication Under Scalable Hashing 可控副本伸缩哈希 、一种伪随机数据分布算法
CRUSH有两个关键优点:
任何组件都可以独立计算出每个object所在的位置(去中心化)。
只需要很少的元数据(cluster map),只要当删除添加设备时,这些元数据才需要改变。
ceph使用基础
ceph集群搭建起来后,可以在ceph集群上进行块存储、对象存储以及文件系统存储。从架构上来看,在ceph集群的上面是rados协议,该协议为使用ceph集群的用户提供必要的支持(ceph用户通过调用rados协议来使用ceph集群)。对于块存储来说,可以通过内核模块的方式使用ceph集群也可以通过用户态调用librbd库来使用ceph集群。通过内核模块方式可以充分的利用内核的page cache机制,而通过用户态调用librbd也可以使用librbd在用户态提供的cache方式提高性能。
LIBRADOS提供客户端访问Ceph集群的原生态统一接口。其它接口或者命令行工具都基于该动态库实现。在librados中实现了Crush算法和网络通信等公共功能,数据请求操作在librados计算完成后可以直接与对应的OSD交互进行数据传输。LIBRBD 是CEPH提供的在librados上封装的块存储接口的抽象。
它们提供C/C++、PYTHON等多种接口。对于C++。
librados主要的类是
librados::Rados 负责初始化集群、读取配置、连接集群
librados::IoCtx 负责创建IO上线文环境
librados::bufferlist 负责读写缓存
librbd最主要的两个类是
LIBRADOS::rbd 主要负责创建、删除、克隆映像等操作,
LIBRADOS::image 负责映像的读写等操作。
对于任何客户端应用,都需要首先连接到一个运行良好的CEPH集群。
然后使用时代码中需要包含主要的接口,有:
1. 集群句柄创建、读取配置
2. 集群连接
3. IO上下文环境初始化(poll创建读写等)
4. 对象读写 、rbd、image 创建读写等
5. IO上下文环境关闭
6. 集群句柄关闭
librados的使用
官网链接HTTP://DOCS.CEPH.COM/DOCS/MASTER/RADOS/API/LIBRADOS-INTRO/
STEP 1: GETTING LIBRADOS¶
sudo yum install librados2-devel
sudo apt-get install librados-dev
安装后在/usr/include/rados文件夹下 /usr/inluce/rbd文件夹下
ls /usr/include/rados
buffer.h crc32c.h librados.h librados.hpp memory.h page.h rados_types.h rados_types.hpp
ls /usr/include/rbd
features.h librbd.h librbd.hpp
STEP 2: CONFIGURING A CLUSTER HANDLE
Tip
Talking to different Ceph Storage Clusters – or to the same cluster with different users – requires different cluster handles.
C++ EXAMPLE
The Ceph project provides a C++ example in the ceph/examples/librados directory. For C++, a simple cluster handle using the admin user requires you to initialize a librados::Rados cluster handle object:
#include
#include
#include
int main(int argc, const char **argv)
{
int ret = 0;
/* Declare the cluster handle and required variables. */
librados::Rados cluster;
char cluster_name[] = "ceph";
char user_name[] = "client.admin";
uint64_t flags = 0;
/* Initialize the cluster handle with the "ceph" cluster name and "client.admin" user */
{
ret = cluster.init2(user_name, cluster_name, flags);
if (ret < 0) {
std::cerr << "Couldn't initialize the cluster handle! error " << ret << std::endl;
return EXIT_FAILURE;
} else {
std::cout << "Created a cluster handle." << std::endl;
}
}
/* Read a Ceph configuration file to configure the cluster handle. */
{
ret = cluster.conf_read_file("/etc/ceph/ceph.conf");
if (ret < 0) {
std::cerr << "Couldn't read the Ceph configuration file! error " << ret << std::endl;
return EXIT_FAILURE;
} else {
std::cout << "Read the Ceph configuration file." << std::endl;
}
}
/* Read command line arguments */
{
ret = cluster.conf_parse_argv(argc, argv);
if (ret < 0) {
std::cerr << "Couldn't parse command line options! error " << ret << std::endl;
return EXIT_FAILURE;
} else {
std::cout << "Parsed command line options." << std::endl;
}
}
/* Connect to the cluster */
{
ret = cluster.connect();
if (ret < 0) {
std::cerr << "Couldn't connect to cluster! error " << ret << std::endl;
return EXIT_FAILURE;
} else {
std::cout << "Connected to the cluster." << std::endl;
}
}
return 0;
}
Compile the source; then, link librados using -lrados. For example:
g++ -g -c ceph-client.cc -o ceph-client.o
g++ -g ceph-client.o -lrados -o ceph-client
STEP 3: CREATING AN I/O CONTEXT
The following examples use the default data pool. However, you may also use the API to list pools, ensure they exist, or create and delete pools. For the write operations, the examples illustrate how to use synchronous mode. For the read operations, the examples illustrate how to use asynchronous mode.
Important
Use caution when deleting pools with this API. If you delete a pool, the pool and ALL DATA in the pool will be lost.
C++ EXAMPLE
#include
#include
#include
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.
*/
librados::IoCtx io_ctx;
const char *pool_name = "data";
{
ret = cluster.ioctx_create(pool_name, io_ctx);
if (ret < 0) {
std::cerr << "Couldn't set up ioctx! error " << ret << std::endl;
exit(EXIT_FAILURE);
} else {
std::cout << "Created an ioctx for the pool." << std::endl;
}
}
/* Write an object synchronously. */
{
librados::bufferlist bl;
bl.append("Hello World!");
ret = io_ctx.write_full("hw