Administrator
发布于 2022-08-03 / 6 阅读
0
0

rbd 原理初步探索

rbd 原理初步探索

ceph中RBD 建立 image后,可以map到操作系统,当磁盘使用和插入STAT一样,此外内核模块已经支持 rbd(krbd), modinfo 可以查看内核模块;创建100g的image并不是在真实磁盘中占用了100g,而是用多少,在ceph中就占用多少

![](http://img.rui.vin/image-20220802162244952.png)

创建RBD发生了什么

现在创建pool,名字为rbd,并在rbd pool里创建image


[root@node29 hrp]# rados lspools
pool_A1
pool_A2
pool_rack
rbd
[root@node29 hrp]# rbd create foo --size 10240
[root@node29 hrp]# rbd -p rbd ls
foo
#查看rbd信息
# [root@node29 hrp]# rbd info foo
rbd image 'foo':
	size 10 GiB in 2560 objects
	order 22 (4 MiB objects) #22是次方  4M是22, 8M是23,因为2^22 bytes = 4MB, 2^23 bytes = 8MB
	snapshot_count: 0
	id: 87fa3437b808
	block_name_prefix: rbd_data.87fa3437b808 #每个块 唯一的前缀编号
	format: 2  # 有两种格式,1 和 2 ,两者区别只是 data的obj命名不同
	features: layering #这里特性 在其他文章有提过
	op_features:
	flags:
	create_timestamp: Tue Aug  2 16:31:58 2022
	access_timestamp: Tue Aug  2 16:31:58 2022
	modify_timestamp: Tue Aug  2 16:31:58 2022

现在r bd pool里建了rbd,看看此时产生了什么数据


[root@node29 hrp]# rados -p rbd ls
rbd_directory
rbd_info
rbd_id.foo
rbd_header.87fa3437b808
[root@node29 hrp]#

建立 foo 后,生成了 rbd\_id.foo,现在 查看下 rbd\_directory 这个对象的内容


[root@node29 hrp]#  rados listomapvals rbd_directory -p rbd
id_87fa3437b808
value (7 bytes) :
00000000  03 00 00 00 66 6f 6f                              |....foo|
00000007

name_foo
value (16 bytes) :
00000000  0c 00 00 00 38 37 66 61  33 34 33 37 62 38 30 38  |....87fa3437b808|
00000010

You have new mail in /var/spool/mail/root
#不是给人看的,反编译下
[root@node29 hrp]#  rados listomapvals rbd_directory -p rbd > temp && hexdump -vC temp && cat temp
00000000  69 64 5f 38 37 66 61 33  34 33 37 62 38 30 38 0a  |id_87fa3437b808.|
00000010  76 61 6c 75 65 20 28 37  20 62 79 74 65 73 29 20  |value (7 bytes) |
00000020  3a 0a 30 30 30 30 30 30  30 30 20 20 30 33 20 30  |:.00000000  03 0|
00000030  30 20 30 30 20 30 30 20  36 36 20 36 66 20 36 66  |0 00 00 66 6f 6f|
00000040  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000050  20 20 20 20 20 20 20 20  20 20 20 20 20 20 7c 2e  |              |.|
00000060  2e 2e 2e 66 6f 6f 7c 0a  30 30 30 30 30 30 30 37  |...foo|.00000007|
00000070  0a 0a 6e 61 6d 65 5f 66  6f 6f 0a 76 61 6c 75 65  |..name_foo.value|
00000080  20 28 31 36 20 62 79 74  65 73 29 20 3a 0a 30 30  | (16 bytes) :.00|
00000090  30 30 30 30 30 30 20 20  30 63 20 30 30 20 30 30  |000000  0c 00 00|
000000a0  20 30 30 20 33 38 20 33  37 20 36 36 20 36 31 20  | 00 38 37 66 61 |
000000b0  20 33 33 20 33 34 20 33  33 20 33 37 20 36 32 20  | 33 34 33 37 62 |
000000c0  33 38 20 33 30 20 33 38  20 20 7c 2e 2e 2e 2e 38  |38 30 38  |....8|
000000d0  37 66 61 33 34 33 37 62  38 30 38 7c 0a 30 30 30  |7fa3437b808|.000|
000000e0  30 30 30 31 30 0a 0a                              |00010..|
000000e7

从信息可以看到 信息包含了 刚才建立的image foo,从 rbd\_directory可以猜测 这对象可能是保存 image信息的,现在再建立一个 rbd


[root@node29 hrp]# rbd create bar --size 10240
[root@node29 hrp]# rados -p rbd ls
rbd_directory
rbd_id.bar
rbd_id.foo
rbd_header.881e37e3e168
rbd_header.87fa3437b808
rbd_info
[root@node29 hrp]#

[root@node29 hrp]#  rados listomapvals rbd_directory -p rbd > temp && hexdump -vC temp && cat temp | grep name
name_bar
name_foo

太多信息,过滤了其他其他内容,不过可以确定的是,每次创建一个rbd,都会pool里面rbd\_directory 添加数据信息,而且还会添加 一个 rbd\_header开头的 obj,rbd\_header后面跟的是一个id,可以 再 rbd info看到


[root@node29 hrp]# rbd info foo
rbd image 'foo':
	size 10 GiB in 2560 objects
	order 22 (4 MiB objects)
	snapshot_count: 0
	id: 87fa3437b808
	block_name_prefix: rbd_data.87fa3437b808  # 这里后面的id和rbd_header后面一样,很重要
	format: 2
	features: layering
	op_features:
	flags:
	create_timestamp: Tue Aug  2 16:31:58 2022
	access_timestamp: Tue Aug  2 16:31:58 2022
	modify_timestamp: Tue Aug  2 16:31:58 2022
[root@node29 hrp]#
#发现一个命令  可以从 rbd_head 中看 这些信息
#比如我想看 order
[root@node29 ~]# rados getomapval -p rbd rbd_header.8a15f6edcaf9 order
value (1 bytes) :
00000000  16                                                |.|
00000001
#想看 features
[root@node29 ~]# rados getomapval -p rbd rbd_header.8a15f6edcaf9 features
value (8 bytes) :
00000000  01 00 00 00 00 00 00 00                           |........|
00000008

!image-20220803101534670(补充 info 里面 feature)

可以得出,每创建一个 rbd 会在 pool里 生产 rbd\_id.{name }和 rbd\_header.{id}这两个 obj,并且也会更新 池中rbd\_directory 的内容(可以理解一个目录,现在加了新的内容,要更新目录), rbd\_header.{id} 里面包含了 image 的配置信息

使用时底层发生什么


#简单使用下
[root@node29 hrp]# rbd ls
bar
foo
[root@node29 hrp]#  rbd map foo
/dev/rbd1
# 格式化  xfs
[root@node29 hrp]# mkfs.xfs /dev/rbd1
#挂载后
[root@node29 mnt]# df -h | grep rbd1
/dev/rbd1        10G   33M   10G   1% /mnt/foo
[root@node29 mnt]#

文件系统建立后,查看 rdb pool增加的内容


[root@node29 home]# rados -p rbd ls |sort
rbd_data.87fa3437b808.0000000000000000
rbd_data.87fa3437b808.0000000000000001
rbd_data.87fa3437b808.00000000000000a0
rbd_data.87fa3437b808.0000000000000140
rbd_data.87fa3437b808.00000000000001e0
rbd_data.87fa3437b808.0000000000000280
rbd_data.87fa3437b808.0000000000000320
rbd_data.87fa3437b808.00000000000003c0
rbd_data.87fa3437b808.0000000000000460
rbd_data.87fa3437b808.0000000000000500
rbd_data.87fa3437b808.0000000000000501
rbd_data.87fa3437b808.0000000000000502
rbd_data.87fa3437b808.00000000000005a0
rbd_data.87fa3437b808.0000000000000640
rbd_data.87fa3437b808.00000000000006e0
rbd_data.87fa3437b808.0000000000000780
rbd_data.87fa3437b808.0000000000000820
rbd_data.87fa3437b808.00000000000008c0
rbd_data.87fa3437b808.0000000000000960
rbd_data.rbd_data.00000000000009ff
...
#主要增加了 rbd_data.87fa3437b808.{index} 这些内容

rbd\_data数据井然有序,查看下 第一个data内容


[root@node29 hrp]# rados -p rbd get rbd_data.87fa3437b808.0000000000000001 tmp1 && hexdump -vC tmp1 |more
00000000  58 46 53 42 00 00 10 00  00 00 00 00 00 28 00 00  |XFSB.........(..|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  e7 f1 7c c2 16 09 4b fc  ba 61 4e fd b0 8d 18 2f  |..|...K..aN..../|
[root@node29 ~]# rados -p rbd get rbd_data.87fa3437b808.0000000000000001 tmp1 && ls -lah tmp1
-rw-r--r-- 1 root root 4.0M Aug  2 20:15 tmp1

可以确定,块格式化为 xfs 时候 ,是有对块读写数据的,每个 obj都是 4M,这也书上说的一样,ceph中会将大文件切割成 4M 大小的obj,而且都遵循 对象文件名都是 以

rbd\_data.{block\_name\_prefix}.{index}命名( format 2 风格

block\_name\_prefix作为全局唯一标识,在加上索引即可成为一个obj;

在ceph 设计原理与实现有一张图可以很好体现出 image的结构 ?()

format 1 ,2之间区别

  • format 1 - 此格式兼容所有版本的 librbd 和内核模块,但是不支持较新的功能,像克隆。
  • format 2 - librbd 和 3.11 版以上内核模块才支持。此格式增加了克隆支持,使得扩展更容易,还允许以后增加新功能。

!image-20220803095650245

如果我在挂载的目录 新建一个有内容的文件,在 obj 文件中是否有更新呢?


#新建一个文件
[root@node29 foo]# echo "aaaaaaaaaaaaaaagggggggggggggggggggggg" > file3
#同上面一样,提取obj 并反编译,发现刚才写的内容就保存在 obj中
#通过文件对比可以查到 具体是更新到那个文件里面
[root@node29 ~]# rados -p rbd get rbd_data.87fa3437b808.0000000000000001 tmp1 && hexdump -vC tmp1 | grep -5 "gggg"
0000afc0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000afd0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000afe0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000aff0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000b000  61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 67  |aaaaaaaaaaaaaaag|
0000b010  67 67 67 67 67 67 67 67  67 67 67 67 67 67 67 67  |gggggggggggggggg|
0000b020  67 67 67 67 67 0a 00 00  00 00 00 00 00 00 00 00  |ggggg...........|
0000b030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0000b040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

显然文件内容在 obj中可以找到,只不过被压缩编译了下。如果 写入一个大文件,会有什么变化呢?


#这里写入一个 1G的 大文件
[root@node29 mnt]# dd if=/dev/zero  of=/mnt/foo/maxfile count=1000 bs=1M
[root@node29 foo]# ls -lah maxfile
-rw-r--r-- 1 root root 1000M Aug  2 20:19 maxfile
[root@node29 foo]#

#在rbd pool里查看obj数量是否增加
[root@node29 mnt]# rados -p rbd ls | wc -l| sort
280
#原本才20几,现在290多个,1000/4=250  这样一算好像也差不多,符合上面说的,文件会分割成 4M大小obj

以上操作可以得出, rbd 生产 image 后,然后 map(这里用到的是 内核rbd)到操作系统,格式化,挂载使用;在挂载目录里面进行 crud操作,此时还没到 ceph pool 中,而是先通过 文件系统将数据整理后,在交给ceph,分割成4M对象文件(不一定都是是4M!!),接下来怎么操作是ceph底层的事情了。(后期结合代码更新)

!image-20220803114900839

文件是怎么分割的

待总结…..

思考的问题 思考的问题

以下是日常遇到RBD问题补充的

上文说到,数据通过编译后才看得到数据,这种是直接以二进制的方式来存放数据的,在RADOS还有两种存放数据的方式,第二种是 以键值对的方式(xattr),地方是也是键值对 omap方式


评论