BCache源碼淺析
BCache可用於雲平臺加速磁盤的讀寫性能;但目前該技術由於較新還不夠穩定。不過由於它已經移入到了Linux內核源碼中,所以穩定性應會得到不斷的提升。本系類文章將嘗試分析Linux Kernel/Driver/Md/Bcache的工作原理與架構, 但由於個人能力與時間原因可能存在很多不足; 另一個想法是和大家交流bcache((其中bset部分的一些代碼還未理解); 所以這裏只能是淺析, 可能有些地方的理解存在錯誤, 希望能與大家交流討論。
1.作用與架構
1.1 簡介
bcache是按照SSD特性來設計的,只按擦除桶大小進行分配,使用b+tree和日誌混合方法來跟蹤緩存數據,緩存數據可以是桶上的任意一個扇區。bcache最大程度上減少了隨機寫的代價,它按順序填充一個桶,重新使用時只需將桶設置爲無效。bcache支持寫直達和回寫策略。回寫默認情況下是關閉的,可以在運行時改變。bcache還在最大程度上保護你的數據,在系統異常關機時數據仍然是可靠的。因爲它被設計爲只有在數據完全寫回存儲設備才確認寫成功。回寫策略能夠緩存絕大多數的寫請求,然後再按照索引將髒數據按次序寫回到後端存儲設備。SSD的特點就是隨機IO速度很快,而對於大塊順序IO的提升卻並不大。bcache會檢測順序IO並忽略;還會對每一個任務記錄動態的平均IO大小,當平均IO大小超過截止值時該任務後面的IO將會被忽略,這樣就可以透傳備份或者大文件拷貝。
在flash上發現數據IO錯誤時,首先會嘗試讀以恢復數據或者將該緩存項置爲無效。對於不可恢復的錯誤,例如元數據或髒數據,bcache將會自動關閉緩存。如果有髒數據在緩存中,這時會首先關閉回寫策略然後再等待髒數據刷回。
1.2 基本使用:
1.編譯安裝
# git clone http://evilpiepirate.org/git/bcache-tools.git
安裝前需要兩個依賴包pkg-config和libblkid-dev
# apt-get install pkg-config libblkid-dev
然後編譯
# make
# make install
2.使用方式
2.1 創建bcache設備
命令:make-bcache -C [cache-device] -B [backing-device]
以vde作爲緩存盤,vdb和vdc作爲後端設備創建bcache設備,有幾個後端設備就會生成幾個bcache設備。
# make-bcache -C /dev/vde -B /dev/vdb /dev/vdc
UUID: 8941a5d1-074e-4cc6-a6dd-56cb1f65aed3
Set UUID: 7681dbb3-6558-4e60-b062-5fbb648f6665
version: 0
nbuckets: 20480
block_size: 1
bucket_size: 1024
nr_in_set: 1
nr_this_dev: 0
first_bucket: 1
UUID: 9e28d09b-942d-487e-be22-9132063da572
Set UUID: 7681dbb3-6558-4e60-b062-5fbb648f6665
version: 1
block_size: 1
data_offset: 16
UUID: 1bacf83e-2754-4d6a-a964-09e53e6e679f
Set UUID: 7681dbb3-6558-4e60-b062-5fbb648f6665
version: 1
block_size: 1
data_offset: 16
# ls /dev/bcache* -la
brw-rw—T 1 root disk 250, 0 5月22 17:23 /dev/bcache0
brw-rw—T 1 root disk 250, 1 5月22 17:23 /dev/bcache1
然後可以使用lsblk查看這些設備的對應關係
# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 254:0 0 20G 0 disk
└─vda1 254:1 0 20G 0 part /
vdb 254:16 0 50G 0 disk
└─bcache1 250:1 0 50G 0 disk
vdc 254:32 0 50G 0 disk
└─bcache0 250:0 0 50G 0 disk
vdd 254:48 0 50G 0 disk
└─bcache2 250:2 0 50G 0 disk
vde 254:64 0 10G 0 disk
├─bcache0 250:0 0 50G 0 disk
└─bcache1 250:1 0 50G 0 disk
2.2 添加一塊後端設備(backing device)
命令:make-bcache -B [backing-device]
# make-bcache -B /dev/vdh
UUID: bd1bc116-6f39-401e-a328-3bc0af4ac8d1
Set UUID: cd86812e-d24c-46da-b949-683969b59575
version: 1
block_size: 1
data_offset: 16
接着看到對應的設備是/dev/bcache3
查看cache set uuid
# ls -la /sys/fs/bcache/
total 0
drwxr-xr-x 3 root root 0 May 22 17:23 .
drwxr-xr-x 6 root root 0 May 22 17:21 ..
drwxr-xr-x 7 root root 0 May 22 17:26 7681dbb3-6558-4e60-b062-5fbb648f6665
–w——- 1 root root 4096 May 2217:57 register
–w——- 1 root root 4096 May 2220:44 register_quiet
“attach”後端設備
命令:echo [cache set uuid] >/sys/block/bcache[N]/bcache/attach
attach之後,緩存設備就能夠對新加的後端設備緩存數據了。
# echo 7681dbb3-6558-4e60-b062-5fbb648f6665 >/sys/block/bcache3/bcache/attach
2.3 刪除一塊後端設備
1)detach backing device
命令:echo [cache set uuid] >/sys/block/bcache[N]/bcache/detach
detach後端設備後,對應的bcache設備還是存在的,只不過這個bcache設備是無緩存的,查看其狀態可以看到是no cache
比如刪除bcache3
# echo 7681dbb3-6558-4e60-b062-5fbb648f6665 >/sys/block/bcache3/bcache/detach
# cat /sys/block/bcache3/bcache/state
no cache
2)stop backing device
命令:echo 1 > /sys/block/bcache[N]/bcache/stop
detach後端設備後,對應的bcache設備還存在,如果要刪除,還需要stop該設備
# echo 1 > /sys/block/bcache3/bcache/stop
# ls /dev/bcache* -la
brw-rw—T 1 root disk 250, 0 May 22 17:51 /dev/bcache0
brw-rw—T 1 root disk 250, 1 May 22 17:54 /dev/bcache1
brw-rw—T 1 root disk 250, 2 May 22 20:42 /dev/bcache2
2.4 新增一塊緩存設備(caching device)
1)創建cache設備
命令:make-bcache -C [cache device]
有可能對應的設備已經有一些元數據,需要使用wipefs清理掉
# make-bcache -C /dev/vdf
Device /dev/vdf already has a non-bcache superblock, remove it using wipefs andwipefs -a
# wipefs -a /dev/vdf
4 bytes were erased at offset 0x27fff0000 (linux_raid_member)
they were: fc 4e 2b a9
# make-bcache -C /dev/vdf
UUID: 1f8bc71f-0106-4da5-b781-5de7b1517706
Set UUID: 7bfb0d17-b6d0-4fe9-942b-a1c75a0893ab
version: 0
nbuckets: 20480
block_size: 1
bucket_size: 1024
nr_in_set: 1
nr_this_dev: 0
first_bucket: 1
2)與bcache設備關聯
命令:echo [cache set uuid] >/sys/block/bcache[N]/bcache/attach
緩存設備需要與bcache設備關聯後,才能作爲對應bcache設備緩存。
# echo 7bfb0d17-b6d0-4fe9-942b-a1c75a0893ab >/sys/block/bcache3/bcache/attach
2.5 刪除cache設備
首先確保沒有backing device在使用它,上述的“刪除一塊後端設備”有說明如何設置取消後端設備對緩存設備的使用。
然後可以使用lsblk來查看是否有盤在引用它。
在在/sys/fs/bcache目錄下還有對應的cacheset uuid,unregister該set uuid後這個cache設備就被視爲刪除了。
命令:echo 1 > /sys/fs/bcache/[cache setuuid]/unregister
比如vde已經不作爲任何設備的緩存盤了,在/sys/fs/bcache目錄下有對應的cache set uuid
# ls /sys/fs/bcache/ -la
total 0
drwxr-xr-x 4 root root 0 5月 26 09:07 .
drwxr-xr-x 6 root root 0 5月 26 09:06 ..
drwxr-xr-x 7 root root 0 5月 26 09:077681dbb3-6558-4e60-b062-5fbb648f6665
drwxr-xr-x 7 root root 0 5月 26 09:077bfb0d17-b6d0-4fe9-942b-a1c75a0893ab
–w——- 1 root root 4096 5月 26 09:07 register
1.3 源碼模塊與接口說明
文件 |
作用 |
重要接口函數 |
函數說明 |
註釋 |
Super.c |
驅動註冊 與bache初始化 |
bcache_init bcache_exit |
驅動註冊與卸載 |
|
register_bcache |
Make-bcache的內核態實現 |
Bcache_init調用sysfs_create_files(bcache_kobj, files)註冊 |
||
register_bdev |
註冊對block層的設備,該設備作爲最終的/dev/bcache |
|
||
register_cache |
註冊緩存設備 |
|
||
Request.c |
實現對block層的訪問接口 |
cached_dev_make_request |
處理block層的request |
Bcache_init==> bch_cached_dev_request_init |
cached_dev_write cached_dev_read |
處理設備的讀寫 |
|
||
Sysfs.c |
對用戶層的sys文件接口 |
bch_cached_dev_files bch_cache_set_files bch_cache_files |
|
|
Closure.c |
Closure用於維護對象的引用計數和回調完成 |
|
|
該模塊爲底層機制 |
Stats.c |
|
包含一個timer用於時間統計 |
用於參數統計 |
|
Util.c |
|
1. CRC 2.uuid 3. bch_bio_map 4.字符串處理 |
輔助函數 |
|
Util.h |
|
Heap, Fifo, array |
封裝了這3種數據結構 |
|
Alloc.c |
Bucket的分配與回收管理 |
bch_bucket_alloc bch_allocator_thread |
桶分配,當剩餘量不足時啓動線程來分配 |
|
bch_bucket_free |
回收桶,但不直接回收而是標記爲GC。由GC統一回收 |
|
||
bch_alloc_sectors |
爲bkey分配新的桶,並更新bkey相關字段 |
|
||
Beset.c |
Bkey的集合管理 |
bch_btree_iter_init bch_btree_iter_next bch_btree_iter_next_filte |
Btreez結構中的bkey集合的訪問迭代器 |
該模塊實現了t->tree binary search點相關代碼目前還沒讀懂 |
bch_btree_sort_partial |
Btreez結構中的bkey的排序 |
|||
Extents.c |
對btree的key的訪問 |
bch_extent_keys_ops |
頁節點操作集合 |
mca_alloc中賦值,操作包含合法性判斷,合併與排序 |
bch_btree_keys_ops |
非頁節點操作結合 |
|||
Io.c |
對緩存設備與主設備的操作封裝 |
Bch_bio 開頭函數操作主設備 Bch_bbio開頭操作cache設備 |
|
該模塊爲底層機制,建立在bio機制上 |
Movinggc.c |
Bucket回收管理 |
bch_moving_gc |
根據bucket的標誌位做實際回收 |
|
Writeback.c |
緩存寫回機制 |
bch_cached_dev_writeback_init |
初始化, super.c調用 |
|
bch_writeback_thread |
Writeback線程 |
|
||
|
|
bcache_dev_sectors_dirty_add |
標記緩存設備的sector爲dirty |
Extents調用該函數 |
Btree.c |
Btree的建立,插入與替換操作,以及btree的垃圾標記 |
btree_gc_開頭函數爲gc相關 |
|
bch_gc_thread爲gc線程 |
bch_btree_insert_check_key bch_btree_insert |
節點插入操作 |
沒有直接的 delete操作,通過replace來實現key的替換 |
||
bch_btree_node_alloc bch_btree_set_root btree_node_free |
Btree節點的分配與回收 |
|
||
bch_btree_map_keys |
按bkey查找,並執行響應操作 |
|
||
Journal.c |
對btree頁節點的操作做 journal管理用於減少插入時的非順序讀寫 |
bch_journal |
向btree添加時,調用該函數建立journal |
|
bch_journal_replay |
下次打開時對未處理的btree insert做重新提交操作 |
|