文章目录
第一部分:原理介绍
环境介绍:
EC模式 2+1
dd if=/dev/zero of=file bs=6k count=10 oflag=direct
6k IO拆分成3k到每个osd上,补齐到bdev_size(4k)后执行write
1、第一次写
new Blob(Blob1), 从磁盘中alloc blob(blob1 大小为min_alloc_size 64k)
3k的io补零后和bdev_size对齐,写到blob1的extent1
第二次写(覆盖extent1的补零部分)
两种方式选择,可由配置参数bluestore_clone_cow选择
默认bluestore_clone_cow = true 使用cow模式覆盖
cow模式下将第二个io分为两次写执行:
clone 原始的lextent1; ->
使用前1k io补齐lextent1, 写到lextent2; ->
后2k io 补零后写到lextent3; ->
释放lextent1对pextent1的引用 ->
remove 克隆后的临时onode, 释放临时lextent对pextent1的引用,进而释放blob1
(1)_do_clone_range
clone之后磁盘上的extent1被Blob1和Blob2中的两个lextent共享,blob1成为shared_blob(blob->ref = 2)
(2)do_write_small写拼好的第一个4k
do_write_small—new_blob
_do_alloc_write txc 0x7f5026c33080 1 blobs
(3)do_write_small写剩余的2k数据(pad_zero补齐到bdev_size)
(4)回收垃圾
estimate gc range(hex): [0, 1000)
释放Blob1中的lextent1对blob1的引用
回收垃圾之后的映射效果:
blob1的引用计数减1,Blob1中第一个4k数据映射到extent2上
(5)remove 临时onode,回收blob1的磁盘空间
删除临时onode,释放blob1
1.第三个io
同理,第三个io下来时,分为两次写操作:
cow方式覆盖写extent2;
补零后写extent3
执行完各个op的io映射图如下:
分析:
由于第三个io下来只覆盖写lextent2,所以只有这部分执行cow,数据写在新的blob(blob3)上, 老的blob(blob2)上还有已经写好的extent1,所以不能释放
同理申请blob4执行第四次写io
执行后的io映射图如下:
当执行下一次io时:
由于不需要覆盖写,所以不需要再申请新的blob,复用blob4
综上,当ec小写拆分出的io与bdev_size非对齐时,执行cow覆盖写会对磁盘空间造成浪费;
如:2+1模式,6k io顺序写
磁盘浪费3/4(每4次写需要新申请3个blob)
2+1模式, 4k io顺序写时
磁盘浪费1/2(每两次写需要新申请1个新的blob)
第二部分:测试数据支持及场景应用
(1) 磁盘浪费测试(cow浪费磁盘空间, rmw不浪费磁盘空间)
Cow模式下拆分到每个osd上的io,看是否和bdev_size(4k)对齐:
如果大小为1k, 则每4次写申请一个blob
如果大小为2k, 则每4次写申请2个blob
如果大小为3k, 则每4次写申请3个blob
如果大小和bdev_size对齐,则不会有磁盘空间浪费
(2)cow模式下浪费的空间再使用rmw模式覆盖写,磁盘空间回收测试
(3)cow模式覆盖写后,再使用cow模式覆盖写测试
第三部分:rmw模式下没有磁盘浪费说明:
直接读取,合并,写入;不申请额外的空间
第四部分 bluestore默认使用cow模式而不用rmw的原因
环境介绍:
cephfs的数据资源池使用2+1的ec pool,组成为osd.0 osd.2 osd.3
为了避免写元数据时对small write统计的影响,元数据资源池使用其他osd创建,和数据osd隔离
(一)以osd.0为例,执行顺序小写时使用cow模式进行clone
(1)在执行写操作之前:
bluestore_write_small = 3183
(2)执行bs=6k count=36的写操作:
(3)执行后,osd.0 的数据统计如下:
bluestore_write_small = 3237
dd数据之后, bluestore执行small_write的次数为3237 – 3183 = 54次
下面分析osd.0在cow模式下接收36次大小为3k(拆分后)的io下发时实际进行54次小写的原因:
接收36次3k io 需要clone的次数 = 36 * 3 / 4 = 27 (原理见第一部分)
每次执行clone需要执行small write的次数 = 2 (一次合并后的数据, 一次补零后的新数据)
所以一共执行small write的次数为27 * 2 = 54 次
(二)将osd.0 clone的模式修改为rmw
测试同样下发36次,大小为3k的io,实际执行small write的次数
(1)下发io之前的数据统计:
bluestore_write_small = 3237
1、执行io下发操作
拆分后,落在osd.0 上的io大小为36次3k写
1、执行完写之后, osd.0的数据统计
bluestore_write_small = 3318
dd数据之后, bluestore执行small_write的次数为3318 – 3237 = 81次
下面分析osd.0在rmw模式下接收36次大小为3k(拆分后)的io下发时实际进行81次小写的原因:
接收36次3k io 需要clone的次数 = 36 * 3 / 4 = 27 (原理见第一部分)
每次clone操作需要执行的small write的次数 = 3(除cow模式下的那两次,还有clone时的一次)
所以, 总共执行的small write次数为 27 * 3 = 81次
综上,当执行小写时,bluestore在执行small write时会有放大,根据覆盖写时执行clone的模式的不同,放大的情况也不一样:
当clone模式为cow时:每次clone对于small_write的放大为1倍
当clone模式为rmw时: 每次clone对于small_write的放大为2倍
cow :
bluestore_write_small = num * size / bdev_size * 2
rmw:
bluestore_write_small = num * size / bdev_size * 3
其中:
num 下发的写io个数
size: ec拆分完落在每个osd上的io大小,单位是k
bdev_size: 默认大小4k
num * size / bdev_size即为num个非对齐小io下发时,执行clone的次数(也是执行read的次数)
第五部分 总结
rmw模式下虽然不会造成磁盘空间的浪费,还能够在覆盖写时回收已经浪费的磁盘空间,但是在执行覆盖小写的过程中产生比cow模式更多的写放大,而越多的deffer写就会带来更多的读操作,bluestore的小写性能也会产生更大的瓶颈;cow模式下根据实际拆分后的io大小带来不同程度上的磁盘浪费(拆分后的size余越接近bdev_size浪费的越多——见第一部分和第二部分),但是对于small write,写放大相对较小,对性能的影响更小,实际环境部署时,可根据业务需要灵活配置。