flashcache的實現與用法

工做須要,看了些flashcache的內容,記錄以下: php

實現

flashcache,是facebook技術團隊開發的新開源項目,主要目的是用SSD硬盤來緩存數據以加速MySQL的一個內核模塊。能夠看到,它最初是用來作數據庫加速,但同時,它也被做爲通用的緩存模塊而設計,可以用於任何搭建在塊設備上的應用程序。 html

工做原理。基於Device Mapper,它將快速的SSD硬盤和普通的硬盤映射成一個 帶緩存的邏輯塊設備,做爲用戶操做的接口。用戶直接對這個邏輯設備執行讀寫操做,而不直接對底層的SSD或者普通硬盤操做。若是對底層的這些塊設備操做, 那麼會失去做爲一個總體提供的緩存功能。 node

內核層次。flashcache,它是經過在文件系統和塊設備驅動層中間 增長一緩存層次實現的,這裏不得不提到DM層的映射機制。因爲DM是做爲虛擬的塊設備驅動在內核中被註冊的,它不是一個真實的設備驅動,不能完成bio的 處理,所以,它主要是基於映射表對bio進行分解、克隆和重映射,而後,bio到達底層真實的設備驅動,啓動數據傳輸。在Device mapper中,引入了target_driver,每一個target_driver由target_type類型描述,表明了一類映射,它們分別用來具 體實現塊設備的映射過程。經過調用某一target_driver的map方法,來映射從上層分發下來的bio,也便是,找到正確的目標設備,並將bio 轉發到目標設備的請求隊列,完成操做。flashcache_target就是這樣一個新的target_driver(做爲一個新的映射類 型,target_type是必須的),以模塊化的方式加入到了DM層。 linux

邏輯架構。從源代碼層次分析,能夠將flashcache分爲這個四個模 塊,調度模塊(也稱‘讀寫模塊’)、邏輯處理模塊(也稱「讀寫後處理模塊」)、底層存儲模塊、以及後臺清理模塊,它們都是基於SSD Layout實現的,構建在SSD佈局(後面會分析)之上。其中,調度模塊,在代碼中對應flashcache_map映射函數,它是 flashcache緩存層次數據入口,因此到達邏輯設備的讀寫請求,最終都會通過DM層的處理,經過flashcache_map進入調度模塊。稱之爲 「調度」,主要是指,接收到數據後,它會根據bio請求的讀寫類型、是否命中緩存等因素,選擇不一樣的處理分支,如 flashcache_read/write或者flashcache_uncached_io,在read和write中會選擇是 flashcache_read_hit/miss仍是flashcache_write_hit/miss。通過不一樣分支的讀寫,會調用底層存儲模塊來 完成磁盤或cache的數據讀寫。邏輯處理模塊,在代碼中對應flashcache_io_callback,它在調度模塊經過底層存儲模塊執行數據讀寫 操做完成後回調執行,因此說它是「讀寫後處理模塊」,它是採用狀態機實現的,根據調度模塊中的讀寫類型進行後續的處理,如讀未命中狀況下,磁盤讀完成後, 回調到邏輯處理模塊,由它負責將從磁盤讀取的數據寫回到SSD,或者寫未命中狀況下,寫SSD完成後,回調到邏輯處理模塊執行元數據的更新,再有就是對調 度模塊中讀寫操做的錯誤進行處理。底層存儲模塊,主要提供了兩種方式來完成真實的數據讀寫,一是由DM提供的dm_io函數,它最終仍是經過 submit_bio的方式,將由調度模塊處理過的bio提交到通用塊層,進行轉發到真實的設備驅動,完成數據讀寫;另外,一種方式,kcopyd,是由 內核提供的一種底層拷貝函數,主要負責髒塊的寫回(從SSD到磁盤),會引發元數據的更新。然後臺清理模塊,是針對每一個set進行數據清理,它會基於兩種 策略對髒塊作回收:(1)set內臟塊超過了閾值;(2)髒塊超過了設定的空閒時間,即fallow_delay,通常是15分鐘,在15分鐘沒有被操做 則會被優先回收。要注意的是,並無單獨的線程在後臺作按期空閒塊回收,必須由IO操做觸發,若是長時間沒有對某set操做,則其中的髒數據很長期保持, 容易危害數據安全。 ios

源代碼佈局。兩個工做隊列。結合device mapper代碼,特別是dm.c能夠知道,在調用flashcache_create工具建立flashcache設備時,會調用 flashcache_ctl函數,執行建立工具,它會建立一工做隊列_delay_clean,主要負責對整個cache設備的髒塊清理,由 flashcache_clean_set在特定條件下調用(見代碼),經過flashcache_clean_all執行對全部sets的掃描與清理。 另一個工做隊列,_kq_xxx(記不清了),在flashcache_init中,由flashcache模塊加載時執行,經過對5個job鏈表進行 處理,執行元數據的更新與完成處理函數、讀磁盤後的SSD寫入、以及對等待隊列的處理,主要就是負責讀寫後的處理工做隸屬於邏輯處理模塊,即「讀寫後處理 模塊」,由磁盤或SSD讀寫後不一樣狀況下被調度。 git

調度的時機能夠看flashcache_map函數,處理邏輯則主要在函數flashcache_io_callback內部判斷,the same block的等待隊列是否爲空,若是不爲空,則一樣會調用flashcache_do_handler,執行對等待隊列的處理。 github

數據調度。對讀,接收到bio,首先,根據 bio->bi_sector,即硬盤的扇區號,獲得SSD上的set。其次,在set內查找是否命中,若是命中,則將硬盤的扇區號轉換爲SSD的 扇區號,而後將此bio向SSD提交,進行讀取;若是未命中,則首先向硬盤驅動提交bio,從硬盤讀數據,讀取完成後,由回調函數啓動回寫SSD操做,將 bio的扇區號轉換爲SSD的=扇區號,而後向SSD驅動程序提交,將硬盤讀取的數據寫入SSD。對寫,同文件系統頁緩衝,並不直接寫入硬盤,而是寫入 SSD,同時,保持一個閥值,通常爲20%,在髒塊數目達到此數值時,寫回磁盤。 shell

安裝

具體的安裝過程能夠參考這裏。我在編譯過linux-3.15.5內核的centos-6.5上直接make和make install,安裝成功。 數據庫

make -j 4 KERNEL_TREE=/usr/src/kernels/2.6.32-131.0.15.el6.x86_64
sudo make install

最第一版本的Flashcache只支持writeback,後來單獨開了一個支持writethrough的分支在flashcache-wt目錄,但目前最新的版本已經將write through合併到主版本,而且增長了write around策略。 centos

最新的源碼能夠到Github獲取。

env GIT_SSL_NO_VERIFY=true git clone https://github.com/facebook/flashcache.git
建議下載完源碼後的第一件事,就是去doc下閱讀 flashcache-doc.txtflashcache-sa-guide.txt

模擬實驗

不是每一個人都有SSD/PCI-E Flash的硬件,因此這裏能夠給你們一個構建虛擬混合存儲設備的小技巧,這樣即便是在本身的筆記本上,也能夠輕鬆的模擬Flashcache的試驗環境,並且隨便折騰。

首先,咱們能夠用內存來模擬一個性能很好的Flash設備,固然這有一個缺點,就是主機重啓後就啥都沒了,不過用於實驗測試這應該不是什麼大問題。 用內存來模擬塊設備有兩種方法,ramdisk或者tmpfs+loop device。因爲ramdisk要調整大小須要修改grub並重啓,這裏咱們用tmpfs來實現。

# 限制tmpfs最大不超過10G,避免耗盡內存(測試機器有24G物理內存)
$sudo mount tmpfs /dev/shm -t tmpfs -o size=10240m
# 建立一個2G的文件,用來模擬2G的flash設備
$dd if=/dev/zero of=/dev/shm/ssd.img bs=1024k count=2048
# 將文件模擬成塊設備
$sudo losetup /dev/loop0 /dev/shm/ssd.img

解決了cache設備,還須要有disk持久設備。一樣的,可以使用普通磁盤上的文件來虛擬成一個loop device。

# 在普通磁盤的文件系統中建立一個4G的文件,用來模擬4G的disk設備
$dd if=/dev/zero of=/u01/jiangfeng/disk.img bs=1024k count=4096
$sudo losetup /dev/loop1 /u01/jiangfeng/disk.img

這樣咱們就有了一個快速的設備/dev/loop0,一個慢速的磁盤設備/dev/loop1,能夠開始建立一個Flashcache混合存儲設備了。

$sudo flashcache_create -p back cachedev /dev/loop0 /dev/loop1
cachedev cachedev, ssd_devname /dev/loop0, disk_devname /dev/loop1 cache mode WRITE_BACK
block_size 8, md_block_size 8, cache_size 0
Flashcache metadata will use 8MB of your 48384MB main memory

$sudo mkfs.ext3 /dev/mapper/cachedev
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
262144 inodes, 1048576 blocks
52428 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=1073741824
32 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 28 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

$sudo mount /dev/mapper/cachedev /u03

Ok,檢查一下,就能夠開始作一些模擬測試啦。

$sudo dmsetup table
cachedev: 0 8388608 flashcache conf:
        ssd dev (/dev/loop0), disk dev (/dev/loop1) cache mode(WRITE_BACK)
        capacity(2038M), associativity(512), data block size(4K) metadata block size(4096b)
        skip sequential thresh(0K)
        total blocks(521728), cached blocks(83), cache percent(0)
        dirty blocks(0), dirty percent(0)
        nr_queued(0)
Size Hist: 4096:84 

$sudo dmsetup status
cachedev: 0 8388608 flashcache stats:
        reads(84), writes(0)
        read hits(1), read hit percent(1)
        write hits(0) write hit percent(0)
        dirty write hits(0) dirty write hit percent(0)
        replacement(0), write replacement(0)
        write invalidates(0), read invalidates(0)
        pending enqueues(0), pending inval(0)
        metadata dirties(0), metadata cleans(0)
        metadata batch(0) metadata ssd writes(0)
        cleanings(0) fallow cleanings(0)
        no room(0) front merge(0) back merge(0)
        disk reads(83), disk writes(0) ssd reads(1) ssd writes(83)
        uncached reads(0), uncached writes(0), uncached IO requeue(0)
        uncached sequential reads(0), uncached sequential writes(0)
        pid_adds(0), pid_dels(0), pid_drops(0) pid_expiry(0)

$sudo sysctl -a | grep flashcache
dev.flashcache.loop0+loop1.io_latency_hist = 0
dev.flashcache.loop0+loop1.do_sync = 0
dev.flashcache.loop0+loop1.stop_sync = 0
dev.flashcache.loop0+loop1.dirty_thresh_pct = 20
dev.flashcache.loop0+loop1.max_clean_ios_total = 4
dev.flashcache.loop0+loop1.max_clean_ios_set = 2
dev.flashcache.loop0+loop1.do_pid_expiry = 0
dev.flashcache.loop0+loop1.max_pids = 100
dev.flashcache.loop0+loop1.pid_expiry_secs = 60
dev.flashcache.loop0+loop1.reclaim_policy = 0
dev.flashcache.loop0+loop1.zero_stats = 0
dev.flashcache.loop0+loop1.fast_remove = 0
dev.flashcache.loop0+loop1.cache_all = 1
dev.flashcache.loop0+loop1.fallow_clean_speed = 2
dev.flashcache.loop0+loop1.fallow_delay = 900
dev.flashcache.loop0+loop1.skip_seq_thresh_kb = 0
我是dd一個ssd.img和一個disk.img,而後fio進行測試,效果比非flashcache設備提升3-4倍。

flashcache命令行

假設咱們的ssd盤是/dev/sdb,sas盤是/dev/sdc。

建立flashcache設備:

flashcache_create -p back cachedev /dev/sdb /dev/sdc

-p back:指定cache模式是writeback

cachedev:flashcache設備名

注意將sdd盤放在前面,sas盤放在後面。

這樣Linux就虛擬出了一個帶緩存的塊設備:

[root@osd0 loop2+loop3]# ll /dev/mapper/cachedev 
lrwxrwxrwx 1 root root 7 Aug 18 11:08 /dev/mapper/cachedev -> ../dm-1
這樣就能夠像使用通常的塊設備同樣,來使用該設備了。若是原來分區/dev/sdc上已經有文件系統,mount後還能夠正常使用;若是沒有文件系統,也能夠和通常的設備同樣作先作文件系統,而後mount並使用之。
mount /dev/mapper/cachedev /mnt
重作Flashcache,首先須要umount相應分區,而後若是須要從新作Flashcache:
umount /mnt
dmsetup remove cachedev
flashcache_destroy /dev/sdb

若是須要重建,再安裝上面的flashcache_create重建就能夠了。

參考資料:

http://blog.csdn.net/kidd_3/article/category/905673

http://www.sebastien-han.fr/blog/2012/11/15/make-your-rbd-fly-with-flashcache/

http://www.sebastien-han.fr/blog/2014/10/06/ceph-and-enhanceio/

http://www.orczhou.com/index.php/2010/10/how-to-setup-flashcace/

http://www.ningoo.net/html/2012/all_things_about_flashcache_4.html

相關文章
相關標籤/搜索