当前位置:   article > 正文

【分析】Ceph编程实例 接口Librbd(C++) -- 映像创建与数据读写_ceph c++

ceph c++

目前我们有两种路径使用Ceph的块存储: 
- 利用QEMU/KVM通过librbd与 Ceph 块设备交互,主要为虚拟机提供块存储设备,如下图所示; 

- 利用kernel module与Host kernel交互,主要为物理机提供块设备支持。

OpenStack/Ceph 技术栈

Librbd 是Ceph提供的块存储接口的抽象,它提供C/C++、Python等多种接口。对于C++,最主要的两个类就是RBD 和 Image。 RBD 主要负责创建、删除、克隆映像等操作,而Image 类负责映像的读写等操作。

准备工作

对于任何客户端应用,都需要首先连接到一个运行良好的Ceph集群。

获取集群句柄

  1. //声明Rados对象,并初始化
  2. librados::Rados rados;
  3. ret = rados.init("admin"); // just use the client.admin keyring
  4. if (ret < 0) { // let's handle any error that might have come back
  5. std::cerr << "couldn't initialize rados! err " << ret << std::endl;
  6. ret = EXIT_FAILURE;
  7. return EXIT_FAILURE;
  8. } else {
  9. std::cout << "we just set up a rados cluster object" << std::endl;
  10. }
  11. //获取配置文件信息: /etc/ceph/ceph.conf
  12. // 1. 根据命令行参数
  13. /*
  14. ret = rados.conf_parse_argv(argc, argv);
  15. if (ret < 0) {
  16. // This really can't happen, but we need to check to be a good citizen.
  17. std::cerr << "failed to parse config options! error " << ret << std::endl;
  18. ret = EXIT_FAILURE;
  19. return EXIT_FAILURE;
  20. } else {
  21. std::cout << "we just parsed our config options" << std::endl;
  22. // We also want to apply the config file if the user specified
  23. // one, and conf_parse_argv won't do that for us.
  24. for (int i = 0; i < argc; ++i) {
  25. if ((strcmp(argv[i], "-c") == 0) || (strcmp(argv[i], "--conf") == 0)) {
  26. ret = rados.conf_read_file(argv[i+1]);
  27. if (ret < 0) {
  28. // This could fail if the config file is malformed, but it'd be hard.
  29. std::cerr << "failed to parse config file " << argv[i+1]
  30. << "! error" << ret << std::endl;
  31. ret = EXIT_FAILURE;
  32. return EXIT_FAILURE;
  33. }
  34. break;
  35. }
  36. }
  37. }
  38. */
  39. // 2. 程序里面指定
  40. ret = rados.conf_read_file("/etc/ceph/ceph.conf");
  41. if (ret < 0) {
  42. // This could fail if the config file is malformed, but it'd be hard.
  43. std::cerr << "failed to parse config file! err " << ret << std::endl;
  44. ret = EXIT_FAILURE;
  45. return EXIT_FAILURE;
  46. }

连接集群

  1. ret = rados.connect();
  2. if (ret < 0) {
  3. std::cerr << "couldn't connect to cluster! err " << ret << std::endl;
  4. ret = EXIT_FAILURE;
  5. return EXIT_FAILURE;
  6. } else {
  7. std::cout << "we just connected to the rados cluster" << std::endl;
  8. }

创建I/O上下文环境

如果没有存储池,需要先新建一个存储池。

新建存储池

  1. const char *pool_name = "gnar";
  2. ret = rados.pool_create(pool_name);
  3. if (ret < 0) {
  4. std::cerr << "couldn't create pool! error " << ret << std::endl;
  5. ret = EXIT_FAILURE;
  6. rados.shutdown(); //断开集群连接
  7. return EXIT_FAILURE;
  8. } else {
  9. std::cout << "we just created a new pool named " << pool_name << std::endl;
  10. }

新建I/O上下文环境

  1. librados::IoCtx io_ctx; //I/O上下文
  2. const char *pool_name = "gnar";
  3. ret = rados.ioctx_create(pool_name, io_ctx);
  4. if (ret < 0) {
  5. std::cerr << "couldn't setup ioctx! err " << ret << std::endl;
  6. ret = EXIT_FAILURE;
  7. rados.shutdown(); //断开集群连接
  8. return EXIT_FAILURE;
  9. } else {
  10. std::cout << "we just created an ioctx for our pool" << std::endl;
  11. }

若干RBD映像API

声明RBD对象,创建rbd映像

  1. librbd::RBD rbd;
  2. const char *image_name = "rumboo";
  3. uint64_t init_size = (uint64_t) 200 * 1024 * 1024; //映像初始化大小200MB
  4. uint64_t features = 1; //影响feature个数
  5. int order = 22; //默认值为22, 即4MB (1 << 22)
  6. ret = rbd.create2(io_ctx, image_name, init_size, features, &order);
  7. if (ret < 0) {
  8. std::cerr << "couldn't create rbd image! err " << ret << std::endl;
  9. ret = EXIT_FAILURE;
  10. io_ctx.close(); //关闭I/O上下文
  11. rados.shutdown(); //断开集群连接
  12. return EXIT_FAILURE;
  13. } else {
  14. std::cout << "We just created an rbd image" << std::endl;
  15. }

打开rbd映像

  1. librbd::RBD rbd;
  2. const char *image_name = "rumboo";
  3. librbd::Image image;
  4. ret = rbd.open(io_ctx, image, image_name);
  5. if (ret < 0) {
  6. std::cerr << "couldn't open rbd image! err " << ret << std::endl;
  7. ret = EXIT_FAILURE;
  8. io_ctx.close(); //关闭I/O上下文
  9. rados.shutdown(); //断开集群连接
  10. return EXIT_FAILURE;
  11. } else {
  12. std::cout << "We just opened an rbd image" << std::endl;
  13. }

查看映像大小

  1. uint64_t size = 0;
  2. ret = image.size(&size);
  3. if (ret < 0) {
  4. std::cerr << "couldn't get image size! err " << ret << std::endl;
  5. ret = EXIT_FAILURE;
  6. return EXIT_FAILURE;
  7. } else {
  8. std::cout << "The size of the image is " << size << std::endl;
  9. }

调整映像大小

  1. size = (uint64_t) 500 * 1024 * 1024; //调整映像大小500MB
  2. ret = image.resize(size);
  3. if (ret < 0) {
  4. std::cerr << "couldn't change the size of the image! err " << ret << std::endl;
  5. ret = EXIT_FAILURE;
  6. return EXIT_FAILURE;
  7. } else {
  8. std::cout << "We just change the size of the image" << std::endl;
  9. }

查看映像ID

  1. std::string id;
  2. ret = image.get_id(&id);
  3. if (ret < 0) {
  4. std::cerr << "couldn't get image ID! err " << ret << std::endl;
  5. ret = EXIT_FAILURE;
  6. return EXIT_FAILURE;
  7. } else {
  8. std::cout << "The ID of the image is " << id << std::endl;
  9. }

查看映像features

  1. features = 0;
  2. ret = image.features(&features);
  3. if (ret < 0) {
  4. std::cerr << "couldn't get image features! err " << ret << std::endl;
  5. ret = EXIT_FAILURE;
  6. return EXIT_FAILURE;
  7. } else {
  8. std::cout << "The features of the image are " << features << std::endl;
  9. }

查看映像状态信息

  1. librbd::image_info_t info;
  2. ret = image.stat(info, sizeof(info));
  3. if (ret < 0) {
  4. std::cerr << "couldn't get image stat_info! err " << ret << std::endl;
  5. ret = EXIT_FAILURE;
  6. return EXIT_FAILURE;
  7. } else {
  8. std::cout << "info.size is " << info.size << std::endl;
  9. std::cout << "info.obj_size is " << info.obj_size << std::endl;
  10. std::cout << "info.num_objs is " << info.num_objs << std::endl;
  11. std::cout << "info.order is " << info.order << std::endl;
  12. std::cout << "info.block_name_prefix is " << info.block_name_prefix << std::endl;
  13. }

查看存储池ID

std::cout << "data pool id is " << image.get_data_pool_id() << std::endl;
  • 1

查看block_name_prefix

std::cout << "block name prefix is " << image.get_block_name_prefix() << std::endl;

查看flags

  1. uint64_t flags = 0;
  2. ret = image.get_flags(&flags);
  3. if (ret < 0) {
  4. std::cerr << "couldn't get image flags! err " << ret << std::endl;
  5. ret = EXIT_FAILURE;
  6. return EXIT_FAILURE;
  7. } else {
  8. std::cout << "image flags is " << flags << std::endl;
  9. }

查看条带化参数

  1. std::cout << "image stripe unit is " << image.get_stripe_unit() << std::endl;
  2. std::cout << "image stripe count is " << image.get_stripe_count() << std::endl;

RBD映像数据读写

数据读写 – synchronous

  1. uint64_t ofs_w = (uint64_t) 0; //读写偏移量
  2. uint64_t ofs_r = (uint64_t) 0;
  3. size_t len_w = 100; //读写长度
  4. size_t len_r = 100;
  5. ceph::bufferlist bl_w; //读写bufferlist
  6. ceph::bufferlist bl_r;
  7. const char *fn_i = "input"; //读写文件名
  8. const char *fn_o = "output";
  9. std::string error;
  10. ret = bl_r.read_file(fn_i, &error);
  11. std::cout << "read file ret = " << ret << std::endl;
  12. if (ret < 0) {
  13. std::cerr << "couldn't read file! err " << ret << std::endl;
  14. ret = EXIT_FAILURE;
  15. image.close(); //关闭rbd映像
  16. io_ctx.close(); //关闭I/O上下文
  17. rados.shutdown(); //断开集群连接
  18. return EXIT_FAILURE;
  19. } else {
  20. std::cout << "We just read a file" << std::endl;
  21. }
  22. ssize_t ret_w = image.write2(ofs_w, len_w, bl_r, 0);
  23. ssize_t ret_r = image.read2(ofs_r, len_r, bl_w, 0);
  24. ret = bl_w.write_file(fn_o, 0644);
  25. std::cout << "write file ret = " << ret << std::endl;
  26. if (ret < 0) {
  27. std::cerr << "couldn't write file! err " << ret << std::endl;
  28. ret = EXIT_FAILURE;
  29. image.close(); //关闭rbd映像
  30. io_ctx.close(); //关闭I/O上下文
  31. rados.shutdown(); //断开集群连接
  32. return EXIT_FAILURE;
  33. } else {
  34. std::cout << "We just wrote a file" << std::endl;
  35. }

数据读写 – asynchronous

  1. std::string data = "foo";
  2. uint64_t ofs_aiow = (uint64_t) 100; //读写偏移量
  3. uint64_t ofs_aior = (uint64_t) 100;
  4. size_t len_aiow = 600; //读写长度
  5. size_t len_aior = 600;
  6. ceph::bufferlist bl_aiow; //读写bufferlist
  7. ceph::bufferlist bl_aior;
  8. librbd::RBD::AioCompletion *write_completion = new librbd::RBD::AioCompletion(
  9. NULL, (librbd::callback_t) simple_write_cb); //读写AioCompletion
  10. librbd::RBD::AioCompletion *read_completion = new librbd::RBD::AioCompletion(
  11. NULL, (librbd::callback_t) simple_read_cb);
  12. for (int i = 0; i < 200; ++i) {
  13. bl_aior.append(data);
  14. }
  15. std::cout << bl_aior.to_str() << std::endl;
  16. ret = image.aio_write2(ofs_aiow, len_aiow, bl_aior, write_completion, 0);
  17. if (ret < 0) {
  18. std::cerr << "couldn't start write! error " << ret << std::endl;
  19. ret = EXIT_FAILURE;
  20. image.close(); //关闭rbd映像
  21. io_ctx.close(); //关闭I/O上下文
  22. rados.shutdown(); //断开集群连接
  23. return EXIT_FAILURE;
  24. }
  25. write_completion->wait_for_complete(); //等待写完成
  26. ret_w = write_completion->get_return_value();
  27. if (ret_w < 0) {
  28. std::cerr << "couldn't write! error " << ret << std::endl;
  29. ret_w = EXIT_FAILURE;
  30. image.close(); //关闭rbd映像
  31. io_ctx.close(); //关闭I/O上下文
  32. rados.shutdown(); //断开集群连接
  33. return EXIT_FAILURE;
  34. } else {
  35. std::cout << "we just write data successfully, return value is " << ret_w << std::endl;
  36. }
  37. ret = image.aio_read2(ofs_aior, len_aior, bl_aiow, read_completion, 0);
  38. if (ret < 0) {
  39. std::cerr << "couldn't start read! error " << ret << std::endl;
  40. ret = EXIT_FAILURE;
  41. image.close(); //关闭rbd映像
  42. io_ctx.close(); //关闭I/O上下文
  43. rados.shutdown(); //断开集群连接
  44. return EXIT_FAILURE;
  45. }
  46. read_completion->wait_for_complete(); //等待读完成
  47. ret_r = read_completion->get_return_value();
  48. if (ret_r < 0) {
  49. std::cerr << "couldn't read! error " << ret << std::endl;
  50. ret_r = EXIT_FAILURE;
  51. image.close(); //关闭rbd映像
  52. io_ctx.close(); //关闭I/O上下文
  53. rados.shutdown(); //断开集群连接
  54. return EXIT_FAILURE;
  55. } else {
  56. std::cout << "we just read data successfully, return value is " << ret_r << std::endl;
  57. }
  58. std::cout << bl_aiow.to_str() << std::endl;
  59. write_completion->release();
  60. read_completion->release();
  61. void simple_write_cb(librbd::completion_t cb, void *arg) {
  62. std::cout << "write completion cb called!" << std::endl;
  63. }
  64. //简单的回调函数,用于librbd::RBD::AioCompletion
  65. void simple_read_cb(librbd::completion_t cb, void *arg) {
  66. std::cout << "read completion cb called!" << std::endl;
  67. }

收尾工作

在最后,一定不能忘记关闭rbd映像、I/O上下文,断开集群连接。

  1. ret = image.close(); //关闭rbd映像
  2. if (ret < 0) {
  3. std::cerr << "couldn't close rbd image! err " << ret << std::endl;
  4. ret = EXIT_FAILURE;
  5. return EXIT_FAILURE;
  6. } else {
  7. std::cout << "we just closed an rbd image" << std::endl;
  8. }
  9. io_ctx.close(); //关闭I/O上下文
  10. rados.shutdown(); //断开集群连接
  11. return EXIT_SUCCESS;


摘自http://blog.csdn.net/jdplus/article/details/76522298

摘自 http://blog.csdn.net/jdplus/article/details/76522298
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/217515
推荐阅读
相关标签
  

闽ICP备14008679号