1. 程式人生 > >大話Ceph--RBD那點事兒

大話Ceph--RBD那點事兒

引言

這篇文章主要介紹了RBD在Ceph底層的儲存方式,解釋了RBD的實際佔用容量和RBD大小的關係,用幾個檔案的例子演示了檔案在RBD(更恰當的是xfs)中的儲存位置,最後組裝了一個RBD,給出了一些FAQ。

RBD是什麼

RBD : Ceph’s RADOS Block Devices , Ceph block devices are thin-provisioned, resizable and store data striped over multiple OSDs in a Ceph cluster.

上面是官方的闡述,簡單的說就是:

  • RBD就是Ceph裡的塊裝置,一個4T的塊裝置的功能和一個4T的SATA類似,掛載的RBD就可以當磁碟用。

  • resizable:這個塊可大可小。

  • data striped:這個塊在ceph裡面是被切割成若干小塊來儲存,不然1PB的塊怎麼存的下。

  • thin-provisioned:精簡置備,我認為的很容易被人誤解的RBD的一個屬性,1TB的叢集是能建立無數1PB的塊的。說白了就是,塊的大小和在ceph中實際佔用的大小是沒有關係的,甚至,剛創建出來的塊是不佔空間的,今後用多大空間,才會在ceph中佔用多大空間。打個比方就是,你有一個32G的U盤,存了一個2G的電影,那麼RBD大小就類似於32G,而2G就相當於在ceph中佔用的空間。

RBD,和下面說的,是一回事。

實驗環境很簡單,可以參考一分鐘部署單節點Ceph

這篇文章,因為本文主要介紹RBD,對ceph環境不講究,一個單OSD的叢集即可。

建立一個1G的塊foo,因為是Hammer預設是format 1的塊,具體和format 2的區別會在下文講到:

[[email protected] cluster]# ceph -s
    cluster fc44cf62-53e3-4982-9b87-9d3b27119508
     health HEALTH_OK
     monmap e1: 1 mons at {ceph=233.233.233.233:6789/0}
            election epoch 2, quorum 0 ceph
     osdmap e5: 1 osds: 1 up, 1 in
      pgmap v7: 64 pgs, 1 pools, 0 bytes data, 0 objects
            7135 MB used, 30988 MB / 40188 MB avail
                  64 active+clean
[
[email protected]
cluster]# rbd create foo --size 1024 [[email protected] cluster]# rbd info foo rbd image 'foo':    size 1024 MB in 256 objects    order 22 (4096 KB objects)    block_name_prefix: rb.0.1014.74b0dc51    format: 1 [[email protected] cluster]# ceph -s ...    pgmap v10: 64 pgs, 1 pools, 131 bytes data, 2 objects            7136 MB used, 30988 MB / 40188 MB avail                  64 active+clean

Tips : rbd的指令如果省略-p / --pool引數,則會預設-p rbd,而這個rbd pool是預設生成的。

對剛剛的rbd info的幾行輸出簡單介紹下:

    size 1024 MB in 256 objects
    order 22 (4096 KB objects)
    block_name_prefix: rb.0.1014.74b0dc51
    format: 1
  • size: 就是這個塊的大小,即1024MB=1G,1024MB/256 = 4M,共分成了256個物件(object),每個物件4M,這個會在下面詳細介紹。

  • order 22, 22是個編號,4M是22, 8M是23,也就是2^22 bytes = 4MB, 2^23 bytes = 8MB。

  • block_name_prefix: 這個是塊的最重要的屬性了,這是每個塊在ceph中的唯一字首編號,有了這個字首,把伺服器上的OSD都拔下來帶回家,就能復活所有的VM了。

  • format : 格式有兩種,1和2,下文會講。

觀察建foo前後的ceph -s輸出,會發現多了兩個檔案,檢視下:

    pgmap v10: 64 pgs, 1 pools, 131 bytes data, 2 objects

[[email protected] cluster]# rados -p rbd ls
foo.rbd
rbd_directory

再檢視這兩個檔案裡面的內容:

[[email protected] ~]# rados -p rbd get foo.rbd foo.rbd
[[email protected] ~]# rados -p rbd get rbd_directory rbd_directory
[[email protected] ~]# hexdump  -vC foo.rbd 
00000000  3c 3c 3c 20 52 61 64 6f  73 20 42 6c 6f 63 6b 20  |<<< Rados Block |
00000010  44 65 76 69 63 65 20 49  6d 61 67 65 20 3e 3e 3e  |Device Image >>>|
00000020  0a 00 00 00 00 00 00 00  72 62 2e 30 2e 31 30 31  |........rb.0.101|
00000030  34 2e 37 34 62 30 64 63  35 31 00 00 00 00 00 00  |4.74b0dc51......|
00000040  52 42 44 00 30 30 31 2e  30 30 35 00 16 00 00 00  |RBD.001.005.....|
[email protected] ~]# hexdump  -vC rbd_directory 
00000000  00 00 00 00 01 00 00 00  03 00 00 00 66 6f 6f 00  |............foo.|

這時候我們再建立一個RBD叫bar,再次對比檢視:

[[email protected] ~]# rbd create bar --size 1024
[[email protected] ~]# rados -p rbd ls
bar.rbd
foo.rbd
rbd_directory
[[email protected] ~]# rados -p rbd get rbd_directory rbd_directory
[[email protected] ~]# hexdump  -vC rbd_directory 
00000000  00 00 00 00 02 00 00 00  03 00 00 00 62 61 72 00  |............bar.|
00000010  00 00 00 03 00 00 00 66  6f 6f 00 00 00 00        |.......foo....|

多出了個bar.rbd檔案,很容易聯想到這個檔案的內容是和foo.rbd內容類似的,唯一不同的是儲存了各自的block_name_prefix。然後,rbd_directory裡面多出了bar這個塊名字。可以得出以下的推論:

每個塊(RBD)剛建立(format 1)時都會生成一個rbdName.rbd這樣的檔案(ceph裡的物件),裡面儲存了這個塊的prefix同時,rbd_directory會增加剛剛的建立的rbdName,顧名思義這個檔案就是這個pool裡面的所有RBD的索引。

為了簡單試驗,刪掉剛剛的bar只留下foo:

[[email protected] ~]# rbd rm bar
Removing image: 100% complete...done.

RBD使用

建好了塊,我們就開始使用這個塊了:

[[email protected] ~]# rbd map foo
/dev/rbd0
[[email protected] ~]# mkfs.xfs /dev/rbd0 
meta-data=/dev/rbd0              isize=256    agcount=9, agsize=31744 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=262144, imaxpct=25
         =                       sunit=1024   swidth=1024 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=8 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[[email protected] ~]# mkdir  /foo
[[email protected] ~]# mount /dev/rbd0 /foo/
[[email protected] ~]# df -h
檔案系統        容量  已用  可用 已用% 掛載點
/dev/vda1        40G  7.0G   31G   19% /
...
/dev/rbd0      1014M   33M  982M    4% /foo

我喜歡記點東西,比如上面的33M就是剛格式化完的xfs系統的大小,算是一個特點吧。 先別急著用,叢集發生了點變化,觀察下:

[[email protected] ~]# ceph -s
      pgmap v44: 64 pgs, 1 pools, 14624 KB data, 15 objects

[[email protected] ~]# rados -p rbd ls |sort 
foo.rbd
rb.0.1014.74b0dc51.000000000000
rb.0.1014.74b0dc51.000000000001
rb.0.1014.74b0dc51.00000000001f
rb.0.1014.74b0dc51.00000000003e
rb.0.1014.74b0dc51.00000000005d
rb.0.1014.74b0dc51.00000000007c
rb.0.1014.74b0dc51.00000000007d
rb.0.1014.74b0dc51.00000000007e
rb.0.1014.74b0dc51.00000000009b
rb.0.1014.74b0dc51.0000000000ba
rb.0.1014.74b0dc51.0000000000d9
rb.0.1014.74b0dc51.0000000000f8
rb.0.1014.74b0dc51.0000000000ff
rbd_directory

比剛剛多了13個檔案,而且特別整齊還!觀察這些檔案的字尾,可以發現,字尾是以16進位制進行編碼的,那麼從0x00 -> 0xff是多大呢,就是十進位制的256,這個數字是不是很眼熟:

    size 1024 MB in 256 objects

可是這裡只有13個檔案,並沒有256個啊,這就是RBD的精簡置備的一個驗證,剛剛建立foo的時候,一個都沒有呢,而這裡多出的13個,是因為剛剛格式化成xfs時生成的。我們著重關注索引值為0x00 & 0x01這兩個碎片檔案(Ceph Object):

[[email protected] ~]# rados -p rbd get rb.0.1014.74b0dc51.000000000000 rb.0.1014.74b0dc51.000000000000
[[email protected] ~]# rados -p rbd get rb.0.1014.74b0dc51.000000000001 rb.0.1014.74b0dc51.000000000001
[[email protected] ~]# hexdump -vC rb.0.1014.74b0dc51.000000000000|more
00000000  58 46 53 42 00 00 10 00  00 00 00 00 00 04 00 00  |XFSB............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  c5 79 ca f7 fc 5d 48 2d  81 5e 4c 75 29 3c 90 d3  |.y...]H-.^Lu)<..|
...

[[email protected] ~]# ll rb.* -h
-rw-r--r-- 1 root root 128K 10月 12 19:10 rb.0.1014.74b0dc51.000000000000
-rw-r--r-- 1 root root  16K 10月 12 19:10 rb.0.1014.74b0dc51.000000000001
[[email protected] ~]# file rb.0.1014.74b0dc51.000000000000
rb.0.1014.74b0dc51.000000000000: SGI XFS filesystem data (blksz 4096, inosz 256, v2 dirs)
[[email protected] ~]# rbd export foo hahahaha
Exporting image: 100% complete...done.
[[email protected] ~]# file hahahaha 
hahahaha: SGI XFS filesystem data (blksz 4096, inosz 256, v2 dirs)

[[email protected] ~]# hexdump -vC rb.0.1014.74b0dc51.000000000001
00000000  49 4e 41 ed 02 01 00 00  00 00 00 00 00 00 00 00  |INA.............|
00000010  00 00 00 02 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  57 fe 15 be 0b cb a3 58  |........W......X|
00000030  57 fe 15 be 0b cb a3 58  00 00 00 00 00 00 00 06  |W......X........|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...............太長了自己看~
[[email protected] ~]# hexdump -vC rb.0.1014.74b0dc51.000000000001|grep IN |wc -l
64

這裡的每一行輸出都是很值得思考的,首先我們匯出剛剛提到的兩個物件,檢視第一個物件,開頭就是XFSB,可以驗證這是剛剛mkfs.xfs留下來的,這時候檢視檔案大小,發現並沒有4M那麼大,別擔心一會會變大的,值得關注的是file第0x00個物件,輸出居然是XFS filesystem data,進一步驗證了剛剛mkfs.xfs的足跡,這和整個塊的file資訊是一樣的,我猜測xfs把檔案系統核心資訊就儲存在塊裝置的最最前面的128KB。而後面的第0x01個物件裡面的IN輸出是64,我不負責任得猜想這個可能是傳說中的inode。拋去猜想這裡給到的結論是:

在使用塊裝置的容量後,會按需生成對應的物件,這些物件的共同點是:命名遵循 block_name_prefix+index, index range from [0x00, 0xff],而這個區間的大小正好是所有物件數的總和。

現在讓我們把foo塞滿:

[[email protected] ~]# dd if=/dev/zero of=/foo/full-me 
dd: 正在寫入"/foo/full-me": 裝置上沒有空間
記錄了2010449+0 的讀入
記錄了2010448+0 的寫出
1029349376位元組(1.0 GB)已複製,37.9477 秒,27.1 MB/秒

[[email protected] ~]# ceph -s
      pgmap v81: 64 pgs, 1 pools, 994 MB data, 258 objects
            10500 MB used, 27623 MB / 40188 MB avail

這裡寫了將近1G的資料,重點在後面的258 objects,如果理解了前面說的內容,這258個物件自然是由rbd_directoyfoo.rbd還有256個prefix+index物件構成的,因為我們用完了這個塊的所有容量,所以自然就生成了所有的256的小4M物件。

寫入檔案

我們把環境恢復到foo被填滿的上一步,也就是剛剛mkfs.xfsmount /dev/rbd0 /foo這裡。向這個塊裡面寫入檔案:

[[email protected] ~]# echo '111111111111111111111111111111111111111111' > /foo/file1.txt
[[email protected] ~]# echo '222222222222222222222222222222222222222222' > /foo/file2.txt
[[email protected] ~]# echo '333333333333333333333333333333333333333333' > /foo/file3.txt
[[email protected] ~]# rados -p rbd get rb.0.106a.74b0dc51.000000000001 rb.0.106a.74b0dc51.000000000001

這裡我之所以只匯出了0x01這個物件,是因為我之前已經匯出過所有的物件,經過對比後發現,在寫入檔案之後,只有這個檔案的大小增大了diff之後,很快找到了寫入的內容。

[[email protected] ~]# hexdump -vC rb.0.106a.74b0dc51.000000000001 
00000000  49 4e 41 ed 02 01 00 00  00 00 00 00 00 00 00 00  |INA.............|
00000010  00 00 00 02 00 00 00 00  00 00 00 00 00 00 00 01  |................|
00000020  00 00 00 00 00 00 00 00  57 fe 25 2f 32 6c 64 83  |........W.%/2ld.|
00000030  57 fe 25 2f 32 6c 64 83  00 00 00 00 00 00 00 36  |W.%/2ld........6|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 02 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000060  ff ff ff ff 03 00 00 00  40 00 09 00 30 66 69 6c  |[email protected]|
00000070  65 31 2e 74 78 74 00 00  40 03 09 00 48 66 69 6c  |[email protected]|
00000080  65 32 2e 74 78 74 00 00  40 04 09 00 60 66 69 6c  |[email protected]`fil|
00000090  65 33 2e 74 78 74 00 00  40 05 00 00 00 00 00 00  |[email protected]|
000000a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
00004000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00004010  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00004020  31 31 31 31 31 31 31 31  31 31 0a 00 00 00 00 00  |1111111111......|
00004030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
00005000  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32  |2222222222222222|
00005010  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32  |2222222222222222|
00005020  32 32 32 32 32 32 32 32  32 32 0a 00 00 00 00 00  |2222222222......|
00005030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
00006000  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33  |3333333333333333|
00006010  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33  |3333333333333333|
00006020  33 33 33 33 33 33 33 33  33 33 0a 00 00 00 00 00  |3333333333......|
00006030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

這裡我們找到了檔名和檔案的內容,這很xfs!因為是xfs將這些檔案和他們的內容組織成這樣的格式的,再關注下每一行前面的編號,這裡同樣是16進位制編碼,如果之前我對IN == inode的猜測是對的話,所有的inodeIN都出現在索引範圍為[0x00000000, 0x00004000)的區間,這個0x00004000的單位是byte轉換過來就是16KB,這個小4M內的所有的inode都儲存在前16KB區間。而檔案出現的第一個索引為0x00004000,第二個在0x00005000,第三個在0x00006000,之間相差了0x1000 bytes也就是4096 bytes  == 4KB,還記得mkfs.xfs時的輸出嗎:

[[email protected] ~]# mkfs.xfs /dev/rbd1
meta-data=/dev/rbd1              isize=256    agcount=9, agsize=31744 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=262144, imaxpct=25
         =                       sunit=1024   swidth=1024 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=8 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

也就是這裡的bsize = 4096使得檔案之間間隔了4KB,很抱歉我的xfs知識還是一片空白,所以這裡很多東西都靠猜,等我補完這一課會回來再做更正的。所以這裡我們的結論就是:

RBD其實是一個完完整整的塊裝置,如果把1G的塊想成一個1024層樓的高樓的話,xfs可以想象成住在這個大樓裡的樓管,它只能在大樓裡面,也就只能看到這1024層的房子,樓管自然可以安排所有的住戶(檔案or檔名),住在哪一層哪一間,睡在地板還是天花板(檔案偏移量),隔壁的樓管叫做ext4,雖然住在一模一樣的大樓裡(foo or bar),但是它們有著自己的安排策略,這就是檔案系統如果組織檔案的一個比喻了,我們就不做深究,明白到這裡就好了然並卵,拆遷大隊長跑來說,我不管你們(xfsorext4)是怎麼安排的,蓋這麼高的樓是想上天了?,然後大隊長把這1024層房子,每4層(4MB)砍了一刀,一共砍成了256個四層,然後一起打包帶走了,運到了一個叫做Ceph的小區裡面,放眼望去,這個小區裡面的房子最高也就四層(填滿的),有的才打了地基(還沒寫內容)。。。

這一節最主要的目的就是說明,在Ceph眼裡,它並不關心這個RBD是做什麼用處的,統統一刀斬成4M大小的物件,而使用這個RBD的使用者(比如xfs),它只能從RBD裡面操作,它可能將一個大檔案從三樓寫到了五樓,但是Ceph不管,直接從四樓砍一刀,檔案分了就分了,反正每個小四層都有自己的編號(index),不會真的把檔案給丟了。

最後再來個小操作(4210688=0x405000):

[[email protected] ~]# cat /foo/file2.txt 
222222222222222222222222222222222222222222
[[email protected] ~]# echo Ceph>Ceph
[[email protected] ~]# dd if=Ceph of=/dev/rbd0  seek=4210688  oflag=seek_bytes
記錄了0+1 的讀入
記錄了0+1 的寫出
5位元組(5 B)已複製,0.0136203 秒,0.4 kB/秒
[[email protected] ~]# hexdump -Cv /dev/rbd0 -n 100 -s 0x405000
00405000  43 65 70 68 0a 32 32 32  32 32 32 32 32 32 32 32  |Ceph.22222222222|
00405010  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32  |2222222222222222|
00405020  32 32 32 32 32 32 32 32  32 32 0a 00 00 00 00 00  |2222222222......|
00405030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

[[email protected] ~]# cat /foo/file2.txt 
Ceph
2222222222222222222222222222222222222

AMAZING!,至少我是這麼覺得的,我們通過檢視index0x01的小4M檔案,得知了file2.txt這個檔案內容在這個小4M內儲存的位置為0x5000,因為0x01前面還有一個小4M檔案即0x00,那麼這個file2.txt在整個RBD內的偏移量為4MB+0x5000B=0x400,000B+0x5000B=0x405000B=4210688B,也就是說儲存在/dev/rbd0的偏移量為0x405000的位置,這時候用dd工具,直接向這個位置寫入一個Ceph,再檢視file2.txt的內容,果然,被修改了!

RBD組裝

受到這篇文章啟發,我們開始組裝一個RBD,所謂組裝,就是把剛剛的13個小4M碎片從叢集中取出來,然後利用這13個檔案,重建出一個1G的RBD塊,這裡的實驗環境沒有那篇文章裡面那麼苛刻,因為叢集還是能訪問的,不像文章裡提到的叢集已死,不能執行ceph指令,需要從OSD裡面把碎片檔案一個個撈出來。

一點思考: 使用find .這種方法太慢了,有一個事實是,可以從任何一個dead OSD 匯出這個叢集的CRUSHMAP,我有一個未證實的猜想,能否將這個CRUSHMAP注入到一個活的叢集,然後這兩個叢集的ceph osd map <pool> <object>的輸出如果一樣的話:

  • live叢集: ceph osd map <pool> foo.rbd,得到塊名所儲存的位置,前往dead叢集找到之。

  • dead叢集: 讀取foo.rbd檔案讀取prefix。希望你還能記得這個塊的大小。

  • live叢集: 做個迴圈,讀取ceph osd map <pool> prefix+index[0x00,Max_index]的輸出,可以獲取在dead叢集的某個OSD的某個PG下面,這樣就可以直接定位而不需要從find .結果來過濾了。

  • 只是猜想,未證實,這兩天證實過再回來訂正。

我們很快就可以把那13個檔案拿出來了,現在開始組裝:

[[email protected] rbd]# ll
總用量 14636
-rw-r--r-- 1 root root  131072 10月 13 11:35 rb.0.1078.74b0dc51.000000000000
-rw-r--r-- 1 root root   28672 10月 13 11:35 rb.0.1078.74b0dc51.000000000001
-rw-r--r-- 1 root root   16384 10月 13 11:35 rb.0.1078.74b0dc51.00000000001f
-rw-r--r-- 1 root root   16384 10月 13 11:35 rb.0.1078.74b0dc51.00000000003e
-rw-r--r-- 1 root root   16384 10月 13 11:35 rb.0.1078.74b0dc51.00000000005d
-rw-r--r-- 1 root root 4194304 10月 13 11:36 rb.0.1078.74b0dc51.00000000007c
-rw-r--r-- 1 root root 4194304 10月 13 11:36 rb.0.1078.74b0dc51.00000000007d
-rw-r--r-- 1 root root 2129920 10月 13 11:36 rb.0.1078.74b0dc51.00000000007e
-rw-r--r-- 1 root root   16384 10月 13 11:36 rb.0.1078.74b0dc51.00000000009b
-rw-r--r-- 1 root root   16384 10月 13 11:36 rb.0.1078.74b0dc51.0000000000ba
-rw-r--r-- 1 root root   16384 10月 13 11:36 rb.0.1078.74b0dc51.0000000000d9
-rw-r--r-- 1 root root   16384 10月 13 11:36 rb.0.1078.74b0dc51.0000000000f8
-rw-r--r-- 1 root root 4194304 10月 13 11:36 rb.0.1078.74b0dc51.0000000000ff

組裝的基本思想就是,先搭建一個1024層的大樓,然後,把剛剛的13個四層根據它的index,安插到對應的樓層,缺少的樓層就空在那就好了,指令碼來自剛剛的文章,我對其進行了一小部分的修改,使之適合我們這個實驗,指令碼將輸出一個名為foo的塊:

#!/bin/sh
# Rados object size 這是剛剛的4M的大小
obj_size=4194304

# DD bs value
rebuild_block_size=512

#rbd="${1}" 
rbd="foo"  #生成的塊名
#base="${2}" #prefix
base="rb.0.1078.74b0dc51"
#rbd_size="${3}" #1G
rbd_size="1073741824" 

base_files=$(ls -1 ${base}.* 2>/dev/null | wc -l | awk '{print $1}')
if [ ${base_files} -lt 1 ]; then
  echo "COULD NOT FIND FILES FOR ${base} IN $(pwd)"
  exit
fi

# Create full size sparse image.  Could use truncate, but wanted
# as few required files and dd what a must.
dd if=/dev/zero of=${rbd} bs=1 count=0 seek=${rbd_size} 2>/dev/null

for file_name in $(ls -1 ${base}.* 2>/dev/null); do
  seek_loc=$(echo ${file_name} | awk -F_ '{print $1}' | awk -v os=${obj_size} -v rs=${rebuild_block_size} -F. '{print os*strtonum("0x" $NF)/rs}')
  dd conv=notrunc if=${file_name} of=${rbd} seek=${seek_loc} bs=${rebuild_block_size} 2>/dev/null
done

從上面的指令碼就可以看出,這是一個填樓工程,將其填完之後,我們來看得到的foo檔案:

[[email protected] rbd]# file foo
foo: SGI XFS filesystem data (blksz 4096, inosz 256, v2 dirs)
[[email protected] rbd]# du -sh foo 
15M    foo
[[email protected] rbd]# ll  -h foo
-rw-r--r-- 1 root root 1.0G 10月 13 12:26 foo

這時候,我們掛載會出現一個小問題,uuid重複:

[[email protected] rbd]# mount foo /mnt
mount: 檔案系統型別錯誤、選項錯誤、/dev/loop0 上有壞超級塊、
       缺少內碼表或助手程式,或其他錯誤

       有些情況下在 syslog 中可以找到一些有用資訊- 請嘗試
       dmesg | tail  這樣的命令看看。
[[email protected] rbd]# dmesg |tail
[3270374.155472] XFS (loop0): Filesystem has duplicate UUID 1c4b010c-a2d8-4615-8307-be5419d94add - can't mount

原因很簡單,還記得我們剛剛操作時的mount /dev/rbd0 /foo嗎? foo塊是/dev/rbd0的克隆,所以fooUUID是和/dev/rbd0的是一樣的,這時候我們umount /foo即可:

[[email protected] rbd]# umount  /foo/
[[email protected] rbd]# mount foo /mnt
[[email protected] rbd]# ls /mnt/
file1.txt  file2.txt  file3.txt
[[email protected] rbd]# cat /mnt/file2.txt 
Ceph
2222222222222222222222222222222222222

神奇吧,我們用碎片檔案組裝了一個完完整整的RBD塊,能和Ceph裡map出來的RBD一樣使用,並且資料也是一樣的,相信如果理解了前幾節的內容,對這個實驗的結果就不會很意外了。