Ceph rbd-ggate 使用指南:在 FreeBSD 上通过 GEOM Gate 将 RBD 镜像映射为本地块设备
2026/9/23 1:39:33 网站建设 项目流程

Ceph rbd-ggate 使用指南:在 FreeBSD 上通过 GEOM Gate 将 RBD 镜像映射为本地块设备

【免费下载链接】cephCeph is a distributed object, block, and file storage platform项目地址: https://gitcode.com/gh_mirrors/ce/ceph

本篇技术指南围绕 Ceph 仓库中的 rbd-ggate 手册 展开,系统讲解rbd-ggate命令的作用、三条核心子命令(mapunmaplist)的用法、全部命令行选项,以及 image-spec / snap-spec 的书写规则,并结合src/tools/rbd_ggate/下的源码剖析其底层实现。读完本文,你将掌握在 FreeBSD 主机上把一个 Ceph RBD 镜像(或快照)映射为本地 GEOM Gate(ggate)块设备、卸载设备与查询映射状态,并理解请求从内核到 RADOS 的完整转发链路。

一、rbd-ggate 是什么

rbd-ggate是 Ceph 为 FreeBSD 平台提供的 RADOS 块设备(RBD)客户端。它把一个 RBD 镜像映射(map)为 FreeBSD GEOM Gate 类(GEOM Gate class)设备,使其可以被当作普通本地块设备访问——可以对其执行newfs、挂载文件系统、作为虚拟机磁盘等。映射出的设备路径形如/dev/ggate0/dev/ggate1,与 Linux 平台上的/dev/rbdN角色对应。

从仓库源码看,rbd-ggate是独立可执行程序,由 src/tools/rbd_ggate/CMakeLists.txt 构建,链接geomlibrbdlibradosglobal库,包含Driver.ccServer.ccWatcher.ccggate_drv.cmain.cc等单元,并安装到bin目录。

适用前提:rbd-ggate仅在 FreeBSD 上受支持。在rbd命令的 ggate 动作实现(src/tools/rbd/action/Ggate.cc)中,非 FreeBSD 平台会直接报错rbd: ggate is only supported on FreeBSD并返回-EOPNOTSUPP

二、命令语法总览

rbd-ggate [--read-only] [--exclusive] [--device ggate device] map image-spec | snap-spec rbd-ggate unmap ggate device rbd-ggate list
  • map:派生一个进程,负责创建 ggate 设备,并在 GEOM Gate 内核子系统与 RADOS 之间转发 I/O 请求;
  • unmap:销毁 ggate 设备并终止负责它的进程;
  • list:列出所有已映射的 ggate 设备。

实际使用中,三个子命令配合如下:

# 映射(返回 /dev/ggateN 设备路径) rbd-ggate map rbd/disk01 # 查看已映射设备 rbd-ggate list # 卸载设备 rbd-ggate unmap /dev/ggate0

三、map:把 RBD 镜像变成本地块设备

map是核心子命令,负责从集群拉取镜像信息、创建 ggate provider 并常驻服务 I/O。其执行流程在 src/tools/rbd_ggate/main.cc 的do_map()(L77-L236)中完整实现,可归纳为以下步骤:

  1. 初始化 Ceph 客户端上下文:以CEPH_ENTITY_TYPE_CLIENT类型初始化,使用Preforker完成守护进程式的前后台分离(main.ccL89-L114)。未显式指定池时,从配置项rbd_default_pool读取默认池名(L116-L118)。
  2. 连接集群并打开镜像rados.connect()连接集群,rados.ioctx_create()打开指定池,io_ctx.set_namespace()设置命名空间,rbd.open()打开镜像(L125-L151)。
  3. 可选独占锁:指定--exclusive时调用image.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE)获取独占锁(L153-L160)。
  4. 快照与只读:若指定了快照,调用image.snap_set()定位到快照,并强制将设备置为只读(快照天然不可写),设备描述符记为RBD pool/[ns/]image@snap(L165-L174)。
  5. 创建 ggate 设备:通过Driver::load()确保内核已加载geom_gate模块,再构造Driver并调用init()创建 provider。从源码看,设备以512 字节扇区大小、镜像实际大小、只读标志和描述信息创建(L183-L191)。
  6. 注册 watcher:创建Watcher并通过image.update_watch()注册,用于感知镜像大小变化(L193-L200)。
  7. 输出设备路径并进入服务循环:打印/dev/<devname>后,按需daemonize(),随后启动Server的请求处理循环(L202-L214)。

映射成功后输出类似:

/dev/ggate0

之后即可把该设备当作普通磁盘使用:

# FreeBSD 下格式化并挂载 newfs /dev/ggate0 mount /dev/ggate0 /mnt/rbd

map 的 I/O 转发链路(源码剖析)

设备创建之后,I/O 服务由 src/tools/rbd_ggate/Server.cc 的Server类承担,它采用读线程 + 写线程的双线程模型(Server::run()L25-L41):

  • reader 线程reader_entry()L149-L202):阻塞在m_drv->recv()上等待内核 GEOM Gate 下发请求,然后根据请求类型分发到 librbd 的异步接口:
    • Writeimage.aio_write(offset, length, bl, c)
    • Readimage.aio_read(offset, length, bl, c)
    • Flushimage.aio_flush(c)
    • Discardimage.aio_discard(offset, length, c)
  • writer 线程writer_entry()L204-L229):等待异步 I/O 完成(wait_io_finish()),再通过m_drv->send()把结果(含读出的数据)返回给内核。

请求命令字定义在 src/tools/rbd_ggate/Request.h(Unknown=0, Write=1, Read=2, Flush=3, Discard=4),与 FreeBSD 内核的BIO_*命令的映射关系见 src/tools/rbd_ggate/ggate_drv.c 的ggate_drv_req_cmd()(L32-L47):BIO_WRITE→WRITEBIO_READ→READBIO_FLUSH→FLUSHBIO_DELETE→DISCARD

底层与内核的通信全部通过/dev/ggctl控制节点的 ioctl 完成:G_GATE_CMD_CREATE创建设备、G_GATE_CMD_START接收请求、G_GATE_CMD_DONE返回结果、G_GATE_CMD_DESTROY销毁设备(见ggate_drv.cggate_drv_create()ggate_drv_recv()ggate_drv_send()ggate_drv_destroy())。若内核中尚无geom_gate模块,ggate_drv_load()会尝试kldload("geom_gate")自动加载。

快照映射与自动扩容

  • 映射快照时(snap-spec),设备强制为只读,因此可安全地把任意历史快照暴露为块设备进行备份或数据提取。
  • 若内核版本足够新(rbd-ggate.sh测试中以uname -K >= 1200078判断扩容支持),Watcher(src/tools/rbd_ggate/Watcher.cc)会在收到镜像通知后比对image.stat()返回的新大小,调用m_drv->resize()动态调整设备容量,并invalidate_cache()使本地缓存失效(handle_notify()L23-L45),保证rbd resize扩容后的镜像能反映到已映射设备上。

四、unmap:卸载 ggate 设备

unmap销毁指定 ggate 设备并终止其对应进程。用法:

rbd-ggate unmap /dev/ggate0

实现上,do_unmap()(src/tools/rbd_ggate/main.cc L238-L251)会先剥离/dev/前缀,再调用Driver::kill()下发G_GATE_CMD_DESTROYioctl 强制销毁设备(ggate_drv_kill()gctl_force = 1)。

更便捷的卸载方式unmap的参数也可以是镜像规格。main()(L469-L480)会先判断参数是否以/dev/开头;若不是,则调用find_mapped_dev_by_spec()(L280-L318)遍历Driver::list()返回的设备描述,按pool/ns/image@snap反查出对应设备名,再执行卸载。也就是说以下两条命令等价:

rbd-ggate unmap /dev/ggate0 rbd-ggate unmap rbd/disk01

注意:按规格反查时池名是必填的(源码注释说明此时不会使用rbd_default_pool推断),因此请始终携带池名,如rbd/disk01

五、list:列出已映射设备

list枚举当前所有已映射的 ggate 设备。手册给出的基本用法为:

rbd-ggate list

从源码(do_list(),L320-L393)看,它还额外支持两个手册之外但实测有效的输出选项:

  • --format plain|json|xml:输出格式,默认plain
  • --pretty-format:对 json/xml 输出进行美化缩进。

plain 格式下输出一张表格,包含idpoolnamespaceimagesnapdevice六列;json/xml 格式则按devices数组输出同样的字段。list只会显示描述以"RBD "开头的设备(即由 rbd-ggate 创建的设备)。

示例(json 格式):

rbd-ggate list --format json --pretty-format
{ "devices": [ { "id": "0", "pool": "rbd", "namespace": "", "image": "disk01", "snap": "", "device": "/dev/ggate0" } ] }

六、命令行选项详解

选项作用适用子命令
--device <ggate device>指定 ggate 设备路径(如/dev/ggate3mapunmap
--read-only以只读方式映射map
--exclusive禁止其他客户端写入(获取独占锁)map
--format <plain\|json\|xml>list 输出格式(源码支持,默认 plain)list
--pretty-formatjson/xml 美化输出(源码支持)list

各选项解析逻辑见main()(L419-L436),其中--read-only--exclusive为布尔开关。

  • --read-only:映射后的设备只读,所有写请求会被拒绝。典型场景是只读挂载镜像做数据校验、安全审计,或防止误写。映射快照时设备会被强制只读(见上文)。
  • --exclusive:调用 librbd 的RBD_LOCK_MODE_EXCLUSIVE独占锁,阻止其他客户端对同一镜像的并发写入,避免多写者互相破坏数据一致性。适合需要严格单写者的场景。
  • --device:显式指定 ggate 设备名。设备名可以带/dev/前缀也可以不带(源码中会自动剥离前缀),未指定时由内核自动分配单元号(G_GATE_UNIT_AUTO),生成形如ggate0的设备名。

七、镜像与快照规格(image-spec / snap-spec)

image-spec 为 [pool-name/]image-name snap-spec 为 [pool-name/]image-name@snap-name

规则要点:

  • 默认池为rbd:省略pool-name时使用rbd池。源码中未指定池时读取配置项rbd_default_pool(main.cc L116-L118)。
  • 镜像名含/时必须显式给出池名:因为规格使用/分隔池与镜像,若不写池名将无法区分。
  • 支持命名空间(namespace):源码中的解析正则^(?:([^/]+)/(?:([^/@]+)/)?)?([^@]+)(?:@([^/@]+))?$(L256)允许pool/namespace/image三层写法。
  • 快照用@附加在镜像名后,如rbd/disk01@snap01

实际示例:

# 默认池 rbd 中的镜像 rbd-ggate map disk01 # 指定池 rbd-ggate map mypool/disk01 # 指定池 + 命名空间 rbd-ggate map mypool/ns1/disk01 # 映射快照(自动只读) rbd-ggate map rbd/disk01@snap01

八、通过 rbd 命令使用 ggate

rbd-ggate的命令行界面同样被整合进了统一的rbd工具。rbd的 ggate 动作实现在 src/tools/rbd/action/Ggate.cc,它会通过SubProcess直接唤起rbd-ggate二进制,因此下列命令等价:

# 映射 rbd device map rbd/disk01 --device-type ggate # 或 rbd --device-type ggate map rbd/disk01 # 卸载(接受设备路径或镜像规格) rbd device unmap /dev/ggate0 --device-type ggate rbd unmap rbd/disk01 --device-type ggate # 列出 rbd device list --device-type ggate

rbd手册(doc/man/8/rbd.rst L263)中,ggate 被列为非默认支持的设备类型之一(Linux 上为 nbd/ubbd,FreeBSD 上为 ggate),因此使用rbd包装时需显式指定--device-type ggate

九、测试与验证

仓库为 rbd-ggate 提供了两层测试,可作为功能验证参考:

  • 端到端测试 src/test/rbd-ggate.sh:前置断言uname必须为 FreeBSD,随后以 1 个 MON、3 个 OSD、1 个 MGR 的 vstart 集群运行qa/workunits/rbd/rbd-ggate.sh
  • 工作单元测试 qa/workunits/rbd/rbd-ggate.sh:完整覆盖环境准备、映射、读写校验、快照、扩容与卸载流程,其中:
    • check_geom_gate()负责检查/加载geom_gate内核模块,无法加载则直接失败退出;
    • 测试同时覆盖了默认命名空间与显式命名空间(rbd namespace create)两种映射路径;
    • 使用dd if=/dev/urandom生成随机数据并rbd import到镜像,再通过 ggate 设备做读写一致性校验;
    • 依据uname -K内核版本判断是否支持 resize,验证镜像扩容后设备大小跟随变化。

如需手动验证,可按测试脚本的流程:加载geom_gate模块 → 创建池与镜像 →rbd-ggate map得到/dev/ggateN→ 对设备进行读写并比对数据 →rbd-ggate list确认状态 →rbd-ggate unmap清理。

十、可用性与注意事项

  • rbd-ggate是 Ceph(一个大规模可扩展的开源分布式存储系统)的组成部分,仅面向 FreeBSD 平台,需要内核具备 GEOM Gate 支持(geom_gate模块,必要时自动kldload)。
  • 映射、卸载设备通常需要 root 权限(测试脚本中通过sudo执行相关步骤)。
  • map常驻前台输出设备路径,如需后台运行可借助 Ceph 守护进程配置(如daemonize)或rbd命令包装。
  • 若设备在映射期间发生镜像扩容,Watcher 会在新内核上自动调整设备大小;旧内核上该能力受限。
  • 更多 Ceph 整体信息可参阅仓库根目录的 README.md 及doc/下的 rbd 手册、ceph 手册。

【免费下载链接】cephCeph is a distributed object, block, and file storage platform项目地址: https://gitcode.com/gh_mirrors/ce/ceph

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询