背景
看到有这个需求,具体碰到什么场景了不太清楚,之前做过rbd的重构的研究,既然能重构,那么修改应该是比重构还要简单一点的,我们具体看下怎么操作
数据结构分析
rbd的元数据信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| [root@lab104 ~] [root@lab104 ~] rbd image 'testrbd': size 1 TiB in 262144 objects order 22 (4 MiB objects) snapshot_count: 0 id: 5f0c22d39dda block_name_prefix: rbd_data.5f0c22d39dda format: 2 features: layering, exclusive-lock, object-map, fast-diff, deep-flatten op_features: flags: create_timestamp: Thu Apr 10 11:01:08 2025 access_timestamp: Thu Apr 10 11:01:08 2025 modify_timestamp: Thu Apr 10 11:01:08 2025 [root@lab104 ~] Removing image: 100% complete...done. [root@lab104 ~] [root@lab104 ~] rbd image 'testrbd': size 1 TiB in 262144 objects order 22 (4 MiB objects) snapshot_count: 0 id: 5f57bde3f24c block_name_prefix: rbd_data.5f57bde3f24c format: 2 features: layering, exclusive-lock, object-map, fast-diff, deep-flatten op_features: flags: create_timestamp: Thu Apr 10 11:07:17 2025 access_timestamp: Thu Apr 10 11:07:17 2025 modify_timestamp: Thu Apr 10 11:07:17 2025
|
这个id信息就是那个block_name_prefix里面的,可以看到,同样的名称同样的大小,重建一次,这个信息就发生了改变了,说明这个信息是随机性的,并没有固定算法,这些信息是在几个地方有记录的我们把这几个地方找出来
rbd相关的对象
1 2 3 4
| rbd_id.testrbd rbd_directory rbd_header.5f57bde3f24c rbd_object_map.5f57bde3f24c
|
这几个是元数据的对象,其它就是数据的信息,我们假如要改id名称,需要先处理元数据
1
| rbd_data.5f57bde3f24c.xxxxxxxx
|
数据存储是这样的
1 2 3 4 5 6 7 8 9 10
| [root@lab104 ~] id_5f57bde3f24c value (11 bytes) : 00000000 07 00 00 00 74 65 73 74 72 62 64 |....testrbd| 0000000b
name_testrbd value (16 bytes) : 00000000 0c 00 00 00 35 66 35 37 62 64 65 33 66 32 34 63 |....5f57bde3f24c| 00000010
|
rbd_directory通过omap老存储id和名称的对应关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| [root@lab104 ~] access_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
create_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
features value (8 bytes) : 00000000 3d 00 00 00 00 00 00 00 |=.......| 00000008
modify_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
object_prefix value (25 bytes) : 00000000 15 00 00 00 72 62 64 5f 64 61 74 61 2e 35 66 35 |....rbd_data.5f5| 00000010 37 62 64 65 33 66 32 34 63 |7bde3f24c| 00000019
order value (1 bytes) : 00000000 16 |.| 00000001
size value (8 bytes) : 00000000 00 00 00 00 00 01 00 00 |........| 00000008
snap_seq value (8 bytes) : 00000000 00 00 00 00 00 00 00 00 |........| 00000008
|
rbd_header.5f57bde3f24c 这个存储的是这个对象的rbd info看到的一些信息
1 2 3
| [root@lab104 ~] [root@lab104 ~] 5f57bde3f24c[root@lab104 ~]
|
rbd_id.testrbd是用实体数据存储的rbd的id信息
rbd_object_map.5f57bde3f24c这个可以忽略先,这个是支持重建的
操作实践
修改 rbd_directory 的omap信息
我们先修改 rbd_directory 的信息
存在两组关系
- id_5f57bde3f24c 对应 |….testrbd|
- name_testrbd 对应|….5f57bde3f24c|
这里我们任意指定一个名称,这个应该是16进制的,所以注意字母不要超过f
我们改掉中间的一部分
id_5f57bde3f24c 改成id_5f57abc3f24c
那么新的对应关系是
- id_5f57abc3f24c 对应 |….testrbd|
- name_testrbd 对应 |….5f57bde3f24c|
那么就是一个改val 一个改key了 ,rados没有rename key val的接口。那么只能set操作
1
| echo -en \\x07\\x00\\x00\\x00\\x74\\x65\\x73\\x74\\x72\\x62\\x64 |rados -p rbd setomapval rbd_directory id_5f57abc3f24c
|
这个val直接取上面查询到的val即可了,这个是没变的
我们检查效果
1 2 3 4 5 6 7 8 9 10
| [root@lab104 ~] id_5f57abc3f24c value (11 bytes) : 00000000 07 00 00 00 74 65 73 74 72 62 64 |....testrbd| 0000000b
id_5f57bde3f24c value (11 bytes) : 00000000 07 00 00 00 74 65 73 74 72 62 64 |....testrbd| 0000000b
|
可以看到完整的复刻了,那么我们可以删除老的key了
1
| rados -p rbd rmomapkey rbd_directory id_5f57bde3f24
|
再修改name里面的val的信息
1 2 3 4 5 6 7
| [root@lab104 ~]
name_testrbd value (16 bytes) : 00000000 0c 00 00 00 35 66 35 37 62 64 65 33 66 32 34 63 |....5f57bde3f24c| 00000010
|
这个里面左边的就是表示右边的内容的,这个是
1
| 35 66 35 37:分别是 ASCII 字符 `'5' 'f' '5' '7'
|

那么我们反向计算
5f57bde3f24c这个我们改成的是5f57abc3f24c
那么对应左边的值就是

1
| 0c 00 00 00 35 66 35 37 61 62 63 33 66 32 34 63
|
先删除之前的
1
| rados -p rbd rmomapkey rbd_directory name_testrbd
|
然后设置
1
| echo -en \\x0c\\x00\\x00\\x00\\x35\\x66\\x35\\x37\\x61\\x62\\x63\\x33\\x66\\x32\\x34\\x63|rados -p rbd setomapval rbd_directory name_testrbd
|
检查
1 2 3 4 5 6 7 8 9 10
| [root@lab104 ~] id_5f57abc3f24c value (11 bytes) : 00000000 07 00 00 00 74 65 73 74 72 62 64 |....testrbd| 0000000b
name_testrbd value (16 bytes) : 00000000 0c 00 00 00 35 66 35 37 61 62 63 33 66 32 34 63 |....5f57abc3f24c| 00000010
|
可以看到已经修改好了
修改rbd_id.testrbd二进制
再改动rbd_id.testrbd信息
1 2 3
| [root@lab104 ~] 00000000 0c 00 00 00 35 66 35 37 62 64 65 33 66 32 34 63 |....5f57bde3f24c| 00000010
|
可以看到这是一个二进制的文件,那么我们手动编辑了
1 2 3
| vim -b rbd_id.testrbd 文本转16进制编辑 :%!xxd
|
内容
1
| 0000000: 0c00 0000 3566 3537 6264 6533 6632 3463 ....5f57bde3f24c
|
我们改成
1
| 0000000: 0c00 0000 3566 3537 6162 6333 6632 3463 ....5f57abc3f24c
|
上面已经计算过了,直接套用即可
16进制编辑还原成文本
检查
1 2 3
| [root@lab104 ~] 00000000 0c 00 00 00 35 66 35 37 61 62 63 33 66 32 34 63 |....5f57abc3f24c| 00000010
|
没有问题,可以把对象覆盖回去了
1
| rados -p rbd put rbd_id.testrbd rbd_id.testrbd
|
还剩最后一个了rbd_header.5f57bde3f24c
1
| rados -p rbd cp rbd_header.5f57bde3f24c rbd_header.5f57abc3f24c
|
复制下对象后,检查下相关的信息是否复制过来了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| [root@lab104 ~] access_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
create_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
features value (8 bytes) : 00000000 3d 00 00 00 00 00 00 00 |=.......| 00000008
modify_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
object_prefix value (25 bytes) : 00000000 15 00 00 00 72 62 64 5f 64 61 74 61 2e 35 66 35 |....rbd_data.5f5| 00000010 37 62 64 65 33 66 32 34 63 |7bde3f24c| 00000019
order value (1 bytes) : 00000000 16 |.| 00000001
size value (8 bytes) : 00000000 00 00 00 00 00 01 00 00 |........| 00000008
snap_seq value (8 bytes) : 00000000 00 00 00 00 00 00 00 00 |........| 00000008
|
这个里面只有一条信息需要修改object_prefix

1 2 3 4 5
| object_prefix value (25 bytes) : 00000000 15 00 00 00 72 62 64 5f 64 61 74 61 2e 35 66 35 |....rbd_data.5f5| 00000010 37 62 64 65 33 66 32 34 63 |7bde3f24c| 00000019
|
可以看到这个地方的对应关系是这样转换的,我们还是反向转换一下即可

1
| rbd_data.5f57abc3f24c 对应为72 62 64 5f 64 61 74 61 2e 35 66 35 37 61 62 63 33 66 32 34 63
|
我们设置下
1 2
| rados -p rbd rmomapkey rbd_header.5f57abc3f24c object_prefix echo -en \\x15\\x00\\x00\\x00\\x72\\x62\\x64\\x5f\\x64\\x61\\x74\\x61\\x2e\\x35\\x66\\x35\\x37\\x61\\x62\\x63\\x33\\x66\\x32\\x34\\x63|rados -p rbd setomapval rbd_header.5f57abc3f24c object_prefix
|
注意前面的\\x15\\x00\\x00\\x00
前缀不要漏了
查看信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| [root@lab104 ~] access_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
create_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
features value (8 bytes) : 00000000 3d 00 00 00 00 00 00 00 |=.......| 00000008
modify_timestamp value (8 bytes) : 00000000 e5 35 f7 67 95 6f 07 08 |.5.g.o..| 00000008
object_prefix value (25 bytes) : 00000000 15 00 00 00 72 62 64 5f 64 61 74 61 2e 35 66 35 |....rbd_data.5f5| 00000010 37 61 62 63 33 66 32 34 63 |7abc3f24c| 00000019
|
可以看到已经改好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [root@lab104 ~] rbd image 'testrbd': size 1 TiB in 262144 objects order 22 (4 MiB objects) snapshot_count: 0 id: 5f57abc3f24c block_name_prefix: rbd_data.5f57abc3f24c format: 2 features: layering, exclusive-lock, object-map, fast-diff, deep-flatten op_features: flags: create_timestamp: Thu Apr 10 11:07:17 2025 access_timestamp: Thu Apr 10 11:07:17 2025 modify_timestamp: Thu Apr 10 11:07:17 2025
|
可以看到已经可以查询到信息了,并且prefix已经改好了,我们还需要处理数据
1
| rados -p rbd ls|grep rbd_data.5f57bde3f24c > obj.list
|
我们需要把这些对象全部复制一份
1
| for obj in `cat obj.list`;do target=`echo $obj|sed 's/\(rbd_data\.\)[^.]*\(\..*\)/\15f57abc3f24c\2/'`;echo $obj;echo $target;rados -p rbd cp $obj $target ;done
|
这个就是把数据改掉prefix后全部复制了一遍
确认没问题就可以删掉了
1 2
| [root@lab104 ~] rbd_object_map.5f57bde3f24c
|
重建object-map
1 2 3 4 5 6 7 8 9 10 11
| [root@lab104 ~] 2025-04-10T12:11:16.762+0800 7f601b7fe700 -1 librbd::object_map::RefreshRequest: failed to load object map: rbd_object_map.5f57abc3f24c 2025-04-10T12:11:16.773+0800 7f601b7fe700 -1 librbd::object_map::InvalidateRequest: 0x7f600c00c560 invalidating object map in-memory 2025-04-10T12:11:16.773+0800 7f601b7fe700 -1 librbd::object_map::InvalidateRequest: 0x7f600c00c560 invalidating object map on-disk 2025-04-10T12:11:16.774+0800 7f601b7fe700 -1 librbd::object_map::InvalidateRequest: 0x7f600c00c560 should_complete: r=0 Object Map Rebuild: 100% complete...done. [root@lab104 ~] rbd_object_map.5f57abc3f24c rbd_object_map.5f57bde3f24c
[root@lab104 ~]
|
老的可以清理了
数据访问确认
到这里工作就都完成了,我们需要去确认下我们的数据是不是完整的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| [root@lab103 ~] testrbd zp [root@lab103 ~] /dev/rbd0 [root@lab103 ~] [root@lab103 ~] rbd image 'testrbd': size 1 TiB in 262144 objects order 22 (4 MiB objects) snapshot_count: 0 id: 5f57abc3f24c block_name_prefix: rbd_data.5f57abc3f24c format: 2 features: layering, exclusive-lock, object-map, fast-diff, deep-flatten op_features: flags: create_timestamp: Thu Apr 10 11:07:17 2025 access_timestamp: Thu Apr 10 11:07:17 2025 modify_timestamp: Thu Apr 10 11:07:17 2025 [root@lab103 ~] Filesystem Size Used Avail Use% Mounted on /dev/rbd0 1.0T 7.2G 1017G 1% /mnt
|
可以看到可以挂载,文件系统还在
总结
通过上面的一系列的操作,我们可以看到这个id是可以更改的,这个地方对元数据的控制能够让我们在面对极端故障的时候能够更好的挽回数据,比如元数据对象丢失,就需要我们去重构下这个数据了,以上操作是操作的一个比较原始使用场景的rbd,没有做快照,没有克隆,如果有用到,需要对更多信息进行修改
大致上说就是该两部分数据:
- 通过echo修改omap的数据
- 通过vim编辑二进制对象的数据