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命令的作用、三条核心子命令(map、unmap、list)的用法、全部命令行选项,以及 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 构建,链接geom、librbd、librados、global库,包含Driver.cc、Server.cc、Watcher.cc、ggate_drv.c、main.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 listmap:派生一个进程,负责创建 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)中完整实现,可归纳为以下步骤:
- 初始化 Ceph 客户端上下文:以
CEPH_ENTITY_TYPE_CLIENT类型初始化,使用Preforker完成守护进程式的前后台分离(main.ccL89-L114)。未显式指定池时,从配置项rbd_default_pool读取默认池名(L116-L118)。 - 连接集群并打开镜像:
rados.connect()连接集群,rados.ioctx_create()打开指定池,io_ctx.set_namespace()设置命名空间,rbd.open()打开镜像(L125-L151)。 - 可选独占锁:指定
--exclusive时调用image.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE)获取独占锁(L153-L160)。 - 快照与只读:若指定了快照,调用
image.snap_set()定位到快照,并强制将设备置为只读(快照天然不可写),设备描述符记为RBD pool/[ns/]image@snap(L165-L174)。 - 创建 ggate 设备:通过
Driver::load()确保内核已加载geom_gate模块,再构造Driver并调用init()创建 provider。从源码看,设备以512 字节扇区大小、镜像实际大小、只读标志和描述信息创建(L183-L191)。 - 注册 watcher:创建
Watcher并通过image.update_watch()注册,用于感知镜像大小变化(L193-L200)。 - 输出设备路径并进入服务循环:打印
/dev/<devname>后,按需daemonize(),随后启动Server的请求处理循环(L202-L214)。
映射成功后输出类似:
/dev/ggate0之后即可把该设备当作普通磁盘使用:
# FreeBSD 下格式化并挂载 newfs /dev/ggate0 mount /dev/ggate0 /mnt/rbdmap 的 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 的异步接口:Write→image.aio_write(offset, length, bl, c)Read→image.aio_read(offset, length, bl, c)Flush→image.aio_flush(c)Discard→image.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→WRITE、BIO_READ→READ、BIO_FLUSH→FLUSH、BIO_DELETE→DISCARD。
底层与内核的通信全部通过/dev/ggctl控制节点的 ioctl 完成:G_GATE_CMD_CREATE创建设备、G_GATE_CMD_START接收请求、G_GATE_CMD_DONE返回结果、G_GATE_CMD_DESTROY销毁设备(见ggate_drv.c中ggate_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 格式下输出一张表格,包含id、pool、namespace、image、snap、device六列;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/ggate3) | map、unmap |
--read-only | 以只读方式映射 | map |
--exclusive | 禁止其他客户端写入(获取独占锁) | map |
--format <plain\|json\|xml> | list 输出格式(源码支持,默认 plain) | list |
--pretty-format | json/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),仅供参考