Facebook flashcache介绍与使用

1、简介

传统的HDD具备大容量的优势,但是性能相对偏低,尤其是随机IO性能,经常成为系统的性能瓶颈,在虚拟机化环境下表现的更明显,因为虚拟化场景会加剧IO随机化。相比HDD,SSD具有高性能的优势,尤其在随机IO这方面,优势非常明显,但是SSD的硬件成本比较高。目前业界在结合HDD的大容量和SSD的高性能方面做了一些优化,基本思路是使用SSD作为HDD的cache,计算机领域,cache的思想无处不在,比如CPU的L1、L2 cache,raid card上的cache,TLB cache等。关于SSD作为HDD的cache的优化方案,主要有Linux bcache,Linux dm-cache,Facebook flashcache,btier,IBM flashcache等,本文主要介绍Facebook flashcache,它目前由Facebook维护,没有merge到kernel mainstream。

2、原理介绍

flashcache是建立在Linux devicemapper之上的,由devicemapper在SSD和backing HDD之上创建了一个逻辑的mapped device,用户使用的就是这个mapped device。flashcache把cache(SSD)按照哈希的方式进行结构化管理,如下图所示,每个方格代表一个block,默认大小是4KB,每个block对应一个per-block metadata,存放在flash中,metadata中记录了该block缓存的backing device的sector号,以及cache的状态(DIRTY, VALID, INVALID);每一行是一个cache set,set大小(buckets)默认是512。总的cache大小,block大小,set大小在创建flashcache时可以指定,根据flashcache的大小以及buckets的大小,一个每个block的大小,就可以计算出buckets数。
flashcache.png

当访问一个sector N时,其对应的cache set为:(N / block size / set size) mod (number of sets),number of sets也就是上图中的n,一旦找到cache set,就可以在该set中查找对应的block。这么做可以做到一个范围的顺序disk block可以cache在一个set中。

flashcache的cache mode分为以下三种:
writethrough:disk write会在cache中保留一份,但同时也会把数据write到backing disk中,直到write backing disk完成才会返回。
writearound:disk write会bypass cache,直接写到backing disk中,disk read会把从backing disk中读取的数据在cache中缓存。
针对writethrough和writearound,disk read首先根据目的sector找到对应的cache set,然后查找有没有相应的block,如果找到了,也就是cache hit,则直接从cache中读取,如果没有找到,就从backing disk中读取数据,同时也在cache中进行缓存。
writeback:write首先会写到cache中,然后更新metadata中得dirty bit,数据并不会立即同步到backing disk中。

另外,flashcache还会在flash上保存cache superblock,用来记录flashcache create时的一些参数(这些参数可以用来reload恢复),以及cache shutdown有没有clean,正常关机会clean,但是crash或者掉电时不会clean的,cache clean后,block对应的metadata中的状态会标识为~dirty。在一个clean cache shutdown,所有cache block的metadata都会刷到flash中,如果是正常关机,下次开机后做flashcache reload时,VALID和DITRY cache都会存在ssd中,如果时crash或者掉电后重新开机,只有DIRTY cache会在SSD中,crash和掉电不会导致数据丢失,只是会失去VALID和non-DIRTY cache。

cache block metadata的更新是有可能会合并的,如果pending的几个write的目标sector对应的cache block metadata是同一个则会合并。

dirty cache是在后台以lazy的方式刷到backing disk中,这个可以通过dirty threshold来控制,flashcache会把每个cache set的dirty percent保持在dirty threshold以下,当超过了dirty threshold,flashcache会根据策略把一部分cache同步到backing disk中。同时,还有一个dirty cache idle clean功能,即根据cache block的idle时间(也就是距离该block最近一次读写的时间)超过一个值(可以通过dev.flashcache.fallow_delay配置)进行同步,当fallow_delay=0时,则关闭idle clean。

当发生了dirty cache block clean时,flashcache会遍历该block set中得block,然后进行排序,合并成大IO同步到backing disk中。

有一点需要注意,devicemapper会根据blocksize把它接收到得IO进行划分,然后再递交给flashcache,如果IO size小于blocksize,flashcache则不会缓存该IO,而是先查找cache中有没有overlap的脏数据,如果有的花,就先刷脏数据,然后再把刚才从devicemapper传来的IO写到backing disk上,如果没有脏数据,则直接写到backing disk上,这也就是为什么当使用fio测试小于4KB的随机IO时,flashcache几乎没有效果。

3、使用方法

【获取flashcache source】
https://github.com/facebook/flashcache
上面有很多版本,针对centos6.x,下载flashcache-stable-v3.1.3或者flashcache-3.1.2

【编译,安装】
make && make install

【创建flashcache】
flashcache_create [-v] -p back|around|thru [-s cache size] [-b block size] cachedevname ssd_devname disk_devname
-v : verbose.
-p : cache mode (writeback/writethrough/writearound).
-s : cache size. Optional. If this is not specified, the entire ssd device
is used as cache. The default units is sectors. But you can specify
k/m/g as units as well.
-b : block size. Optional. Defaults to 4KB. Must be a power of 2.
The default units is sectors. But you can specify k as units as well.
(A 4KB blocksize is the correct choice for the vast majority of
applications. But see the section "Cache Blocksize selection" below).
-f : force create. by pass checks (eg for ssd sectorsize).
Examples :
flashcache_create -p back -s 1g -b 4k cachedev /dev/sdc /dev/sdb
Creates a 1GB writeback cache volume with a 4KB block size on ssd
device /dev/sdc to cache the disk volume /dev/sdb. The name of the device
created is "cachedev".
以上来自:https://github.com/facebook/flashcache/blob/3.1.2/doc/flashcache-sa-guide.txt

【格式化,mount】
flashcache_create创建出来的逻辑磁盘,其实就是devicemapper创建出来的逻辑磁盘,你可以像使用普通磁盘一样去使用它,分区,格式化文件系统都可以。
mkfs.ext4 /dev/mapper/cachedev
mount -t ext4 /dev/mapper/cachedev [mount point]

【tuning & configuration】
sysctls common for all cache modes:
dev.flashcache..cache_all: 该参数有两个取值,0和1,前者代表cache nothing,后者代表cache everything,默认是cache everything。cache everything时,可以通过进程ID black list指定哪些进程的IO不进行cache,cache nothing时,可以使用进程ID white list指定哪些进程进行cache。有一点需要注意的是black list只对O_DIRECT IOs有效果,因为针对buffered IOs,pdflush,kswapd会在后台write这些buffered IOs,flashcache仍然会cache这些IOs,那么black list就没有效果了。我们可以通过cat /proc/flashcache/[cache name]/flashcache_pidlists查看具体的white list和black list设置。我们可以通过ioctl(/dev/mapper/cachedev, CMD, pidlist)来设置进程的white/black list,具体CMD如下,
FLASHCACHEADDBLACKLIST: add the pid (or tgid) to the blacklist.
FLASHCACHEDELBLACKLIST: Remove the pid (or tgid) from the blacklist.
FLASHCACHEDELALLBLACKLIST: Clear the blacklist. This can be used to cleanup if a process dies.
FLASHCACHEADDWHITELIST: add the pid (or tgid) to the whitelist.
FLASHCACHEDELWHITELIST: Remove the pid (or tgid) from the whitelist.
FLASHCACHEDELALLWHITELIST: Clear the whitelist. This can be used to cleanup if a process dies.

dev.flashcache..zero_stats: FIFO (0) vs LRU (1). 默认是 FIFO. 支持运行时切换。

dev.flashcache..io_latency_hist: 用来计算IOs的时延,并可以通过柱状图显示出来,可以通过dmsetup status查看。单位是250us。该功能默认是关闭的,因为flashcache是使用gettimeofday()来计算时延的,对于某些时钟源来说,这个开销太大,一般很少开启这个功能。

dev.flashcache..max_pids: 进程pid white/black list中允许设置的最多pid数。

dev.flashcache.do_pid_expiry: enable/disable white/black list中的pid的expiry。

dev.flashcache.pid_expiry_secs: 设置white/black list中pid的expiry时间。

dev.flashcache..skip_seq_thresh_kb: 配置是不是对满足一定条件的IO不进行cache,条件就是如果顺序IO大于这个threshold,则不进行cache,当threshold为0时(默认值)意味着cache所有的IO,不管时顺序的还是随机的。顺序IO是根据最近的IO判断的。

sysctls for writeback mode only:
dev.flashcache..fallow_delay: idle clean的idle时间,单位是秒,当距离该cache block最近一次访问的时间大于该idle时,就会触发同步该block所在的cache set同步dirty block。
默认值时900s,0表示禁止idle clean功能。

dev.flashcache..fallow_clean_speed: 该值是精确控制idle clean的,每个cache block每秒允许clean的最多block数,默认是2。

ev.flashcache..fast_remove: 决定当remove cache时要不要同步 dirty cache,0代表同步,1代表不同步,默认是同步。如果不同步,在reload时,dirty和valid block都在cache中。这个选项可以用于快速的cache remove。

dev.flashcache.dirty_thresh_pct: ditry block的threshold,flashcache会尽量让一个cache set中的dirty block的低于这个threshold,一旦达到这个值就会触发flashcache sync 该cache set中的部分dirty block到backing disk。当这个值比较小时,会触发比较多得IO write,但是会增加更多的backing disk sector放到cache中。

dev.flashcache..stop_sync: 停止正在进行的IO同步操作。

dev.flashcache..do_sync: 触发同步所有的dirty block到backing disk。

【注意事项】
1)创建flashcache前,要确保backing hdd没有被挂载,因为一旦创建好flashcache后,backing hdd上以前的数据就没办法获取到了,正常情况下在创建flashcache后,也会对新生成的mapped device进行格式化文件系统。

2)在关机前最好调用dmset remove cachedev,这样会把所有的dirty cache同步到backing disk上。针对writeback mode,开机时需要调用flashcache_load [SSD]来恢复之前的flashcache配置,保证不会发生数据丢失。这些可以通过在/etc/init.d/下增加一个init脚本来做,可以参考https://github.com/facebook/flashcache/blob/3.1.2/doc/flashcache-doc.txt中的“Using Flashcache sysVinit script”。

3)当devicemapper递交给flashcache的IO小于cache block size,flashcache不会缓存这些IO。

4)关于顺序IO,flashcache有没有效果,取决于你的HDD的顺序IO性能怎么样,如果你的HDD的顺序IO性能比SSD的性能还好,建议配置dev.flashcache..skip_seq_thresh_kb=[256,512,1024,...]参数跳过cache满足条件的顺序IO,具体参见上面关于dev.flashcache..skip_seq_thresh_kb的说明。

4、测试验证

配置:HDD partition size 16G, SSD partition size 8GB,
flashcache创建命令:flashcache_create -p back -s 8g cachedev1 /dev/sdb /dev/sda2
综合测试结果如下图所示,
flashcache2.png

以下是详细测试命令及结果,
【fio测试】
随机写:
raw HDD, fio -filename=/dev/sda2 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=4k -size=5G -numjobs=8 -runtime=300 -group_reporting -name=mytest
flashcache-test-randwrite-hdd.png

flashcache, fio -filename=/dev/mapper/cachedev1 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=4k -size=5G -numjobs=8 -runtime=300 -group_reporting -name=mytest
flashcache-randwrite-flashcache.png

随机读:
raw HDD, fio -filename=/dev/sda2 -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=4k -size=5G -numjobs=8 -runtime=300 -group_reporting -name=mytest
flashcache-randread-hdd.png

flashcache,fio -filename=/dev/sda2 -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=4k -size=5G -numjobs=8 -runtime=300 -group_reporting -name=mytest
flashcache-randread-flashcache.png

随机混合读写,读写各占50%:
raw HDD,fio -filename=/dev/sda2 -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=50 -ioengine=psync -bs=4k -size=5G -numjobs=8 -runtime=300 -group_reporting -name=mytest
flashcache-randrw-hdd.png

flashcache,fio -filename=/dev/mapper/cachedev1 -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=50 -ioengine=psync -bs=4k -size=5G -numjobs=8 -runtime=300 -group_reporting -name=mytest
flashcache-randrw-flashcache.png

5、结论

针对随机IO(包括随机写、随机读、随机混合读写),flashcache可以数十倍的提高IOPS,并显著的降低IO latency。
另外,关于顺序IO,flashcache有没有效果,取决于你的HDD的顺序IO性能怎么样,像我以上测试环境用的是曙光I620r-T,它上面的HDD的顺序写性能达到46K IOPS,而SSD的性能只有20K IOPS左右,所以这时要通过配置dev.flashcache..skip_seq_thresh_kb=x,以使得不对大于xKB顺序IO进行cache,x值可以根据具体情况进行调整,一般可以选择128,256,512等。

猜你喜欢

转载自weitao1026.iteye.com/blog/2327854