Loading

bcache总结

参考链接

https://www.bbsmax.com/A/ZOJPXRpxJv/

https://blog.csdn.net/tao_627/article/details/78296332

https://www.cnblogs.com/zimufeng/p/6640439.html

https://www.cnblogs.com/sunhaohao/archive/2017/07/03/sunhaohao.html

https://www.pianshen.com/article/397441087/

https://ypdai.github.io/2018/07/13/bcache%E9%85%8D%E7%BD%AE%E4%BD%BF%E7%94%A8/

定义:

bcache是linux内核块层cache.它使用类似SSD来作为HDD硬盘的cache,从而起到加速作用。

bcache使用SSD作为其他块设备的cache.类似ZFS的L2Arc,但bcache还增加了写回策略,并且是与文件系统无关的。默认状态下bcache不缓存顺序IO,只缓存随机读写。

bcache是数据安全的。对于写回策略缓存来说,可靠性是非常重要的,出错就意味着丢失数据。bcache是用电池备份阵列控制器的替代选择,同时也要求bcache在异常掉电时也是数据安全的。对于写而言,必须在所有数据写到可靠介质之后才能向上层返回写成功。如果在写一个大文件时掉电了,则写入是失败的。异常掉电数据安全是指 cache 中的脏数据是不会丢的,不像内存中的脏数据掉电就没了。

特性:

  1. 一个缓存设备可以作为多个设备的缓存,并且可以在设备运行时动态添加和删除缓存。
  2. 只有当写到磁盘后缓存才会确认写完成。
  3. 正确处理写阻塞和刷缓存。
  4. 支持writethrough, writeback和writearound等写缓存模式。
  5. 检测并避开顺序IO(可配置关闭该选项)。
  6. 当检测到SSD延迟超过配置边界值,减少到SSD流量(当一个SSD作为多个磁盘缓存时使用)。
  7. 缓存不命中时预读(默认关闭)
  8. 高性能的 writeback 实现:脏数据都是排序后再回写。如果设置了 writeback 水位线,PD控制器会根据脏数据比例来平滑处理到后台的writeback流量。
  9. 使用高效率的B+树,bcache随机读可以达到1M IOPS。
  10. 稳定。

设计细节:

  1. bcache针对SSD的性能测试设计--它仅分配可擦写块(erase block size)的bucket,使用混合bree/log去追踪缓存内容(从单个扇区到bucket大小的任何地方),它以不惜任何代价来设计避免随机写;它顺序地填满一个个可擦写块(erase block), 然后在重用该块之前清除该块。
  2. 支持writethrough和writeback缓存模式。writeback默认关闭,但可以在运行时随时打开或关闭。bcache竭尽全力来保护你的数据--它可靠地处理unclean的关闭。(甚至根本就没有clean shutdown的概念,因为数据写到可靠的磁盘,完成之前不会返回)。
  3. writeback缓存能用于绝大部分buffering write的缓存--总是顺序地write脏数据到后端设备,从index的起始到末尾扫描。
  4. writeback缓存能用于绝大部分buffering write的缓存--总是顺序地write脏数据到后端设备,从index的起始到末尾扫描。
  5. SSD擅长随机IO,通常对缓存大序列化IO,没有优化空间,Bcache会探测顺序IO并跳过它,SSD只优化随机IO。bcache也会对每次task中的IO size的平均大小持续跟踪,只要平均大小超过cutoff,它将会跳过该task中的所有IO,而非在每次查找后缓存前512K字节,备份和大文件复制会整个跳过缓存设备。
  6. 当flash闪存上发生data IO error时,它会尽量从磁盘读取数据来恢复,恢复失败就使缓存对象失效。对不可恢复的错误(元数据或脏数据),caching设备会自动禁用;假如caching设备中有脏数据存在,首先会禁用writeback,等所有的脏数据都写到磁盘里。

使用操作:

你需要使用bcache-tools代码库中的make-bcache,在使用之前,cache设备和backing设备都必须格式化:

  1. make-bcache -B /dev/sdb make-bcache -C /dev/sdc

  2. make-bcache可以同时格式化多个设备,假如你同时格式化后端设备和缓存设备,无须手动绑定

    make-bcache -B /dev/sda /dev/sdb -C /dev/sdc

  3. bcache-tools现在加入了udev rules,bcache设备能立即被内核探测到,如果没有udev,你需要手动这样注册

    echo /dev/sdb > /sys/fs/bcache/register echo /dev/sdc > /sys/fs/bcache/register

    注册后端设备将可在/dev中看到bcache,然后你可以格式化它,之后可以像普通磁盘一样使用。

    注意:第一次使用全新bcache设备,它通常会运行在passthrough模式,所有读写的操作都在硬盘上,直到你将他板到一台缓存设备,如果你想以后使用bcache,推荐你搭建所有的慢速设备为bcache的后端设备,不带caching设备,你能在以后选择追加一台caching设备。

  4. 设备实现

    /dev/bcache
    以及(和udev)
    /dev/bcache/by-uuid/ /dev/bcache/by-label/

错误处理

总体原则:

Bcache尝试透明地处理来自缓存设备的 IO 错误,而不会影响正常操作;如果它看到太多错误(阈值可配置,并且默认为0),它将关闭缓存设备并将所有 backing device 切换到 passthrough 模式。

  1. 对于从缓存读取,如果它们出现错误,将从 backing device 重新尝试读取
  2. 对于 writethroungh writes,如果写入缓存错误,我们只需切换到缓存中的 lba(Logical Block Address, LBA) 上使数据无效(即我们为绕过 cache write 将数据写到后端设备)
  3. 对于writeback writes,我们目前将该错误传递给文件系统/用户空间。这可以改进 - 我们可以尝试绕过缓存的写入,所以小心避免写入错误。
  4. 对于分离操作,我们首先尝试刷新任何脏数据到后端设备(如果我们以 writeback 模式运行)。但是,如果它无法读取脏数据,当前它将不会做任何操作。

How to

  1. 从一个丢失的caching设备启动bcache

    echo /dev/sdb1 > /sys/fs/bcache/register
    [ 119.844831] bcache: register_bcache() error opening /dev/sdb1: device already registered
    
    # 下一步,如果有cache设备的话,你尽量注册它,然而假如没有,或是cache设备因为某种原因注册失败,在没有cache设备的情况下,你仍然能够启动bcache,像下面这样
    host:/sys/block/sdb/sdb1/bcache
    echo 1 > running
    # 注意如果当前在writeback模式下,这会导致数据丢失。
    
    
  2. bcache找不到cache

    echo 0226553a-37cf-41d5-b3ce-8b1e944543a8 > attach
    [ 1933.455082] bcache: bch_cached_dev_attach() Couldn't find uuid for md5 in set[ 1933.478179] bcache: __cached_dev_store() Can't attach 0226553a-37cf-41d5-b3ce-8b1e944543a8
    [ 1933.478179] : cache set not found
    这种情况,cache设备可能在系统启动时没有注册,或是消失后又回来了,需要再次注册一下
    echo /dev/sdh2 > /sys/fs/bcache/register
    
  3. 擦除缓存设备

    wipefs -a /dev/sdh
    216 bytes were erased at offset 0x1018 (bcache)they were: c6 85 73 f6 4e 1a 45 ca 82 65 f5 7f 48 ba 6d 81
    在重启系统后,开启bcache,重建cache设备并开启它:
    
    make-bcache -C /dev/sdh
    
    UUID: 7be7e175-8f4c-4f99-94b2-9c904d227045Set UUID: 5bc072a8-ab17-446d-9744-e247949913c1version: 0nbuckets: 106874block_size: 1bucket_size: 1024nr_in_set: 1nr_this_dev: 0first_bucket: 1[ 650.511912] bcache: run_cache_set() invalidating existing data[ 650.549228] bcache: register_cache() registered cache device sdh2
    
    /sys/block/md5/bcache
    echo 1 > running
    绑定新的cache设备
    host:/sys/block/md5/bcache
    echo 5bc072a8-ab17-446d-9744-e247949913c1 > attach
    [ 865.276616] bcache: bch_cached_dev_attach() Caching md5 as bcache0 on set 5bc072a8-ab17-446d-9744-e247949913c1
    
  4. 移除或是替换缓存设备

    host:/sys/block/sda/sda7/bcache
    echo 1 > detach
    [ 695.872542] bcache: cached_dev_detach_finish() Caching disabled for sda7
    host:~#wipefs -a /dev/nvme0n1p4wipefs: error: /dev/nvme0n1p4: probing initialization failed: Device or resource busyOoops, it's disabled, but not unregistered, so it's still protected我们需要取消注册host:/sys/fs/bcache/b7ba27a1-2398-4649-8ae3-0959f57ba128# ls -l cache0lrwxrwxrwx 1 root root 0 Feb 25 18:33 cache0 -> ../../../devices/pci0000:00/0000:00:1d.0/0000:70:00.0/nvme/nvme0/nvme0n1/nvme0n1p4/bcache/host:/sys/fs/bcache/b7ba27a1-2398-4649-8ae3-0959f57ba128# echo 1 > stopkernel: [ 917.041908] bcache: cache_set_free() Cache set b7ba27a1-2398-4649-8ae3-0959f57ba128 unregistered现在我们才能清除数据host:~# wipefs -a /dev/nvme0n1p4/dev/nvme0n1p4: 16 bytes were erased at offset 0x00001018 (bcache): c6 85 73 f6 4e 1a 45 ca 82 65 f5 7f 48 ba 6d 81
    
  5. dm-crypt和bcache

    首先搭建非加密的bcache,然后在/dev/bcache上层安装dmcrypt,这会更快,假如你dmcrypt后端和caching设备的时候,同时在顶层安装bcache。[需要benchmarks?]

  6. 停止并释放一个注册过的bcache,擦除之后重新生成

    假如你需要释放所有的bcache引用,以便你能运行fdisk并重新注册一个变动的分区表,假如上面有任何活跃的backing或是caching设备,这都不会成功
    1)/dev/bcache*有东西吗?(有时没有)
    假如存在,很简单:
    host:/sys/block/bcache0/bcache# echo 1 > stop
    2)但是假如你的后端设备不在,这不会成功:
    host:/sys/block/bcache0# cd bcachebash: cd: bcache: No such file or directory
    这种情况,你或许必须注销引用该待释放bcache的dmcrypt的块设备
    host:~# dmsetup remove oldds1bcache: bcache_device_free() bcache0 stoppedbcache: cache_set_free() Cache set 5bc072a8-ab17-446d-9744-e247949913c1 unregistered
    这导致后端bcache从/sys/fs/bcache中移除,然后再次重用,This would be true of any block device stacking where bcache is a lower device.
    
    3)另一方面,你也能看看/sys/fs/bcache/
    host:/sys/fs/bcache# ls -l */{cache?,bdev?}lrwxrwxrwx 1 root root 0 Mar 5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/bdev1 -> ../../../devices/virtual/block/dm-1/bcache/lrwxrwxrwx 1 root root 0 Mar 5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/cache0 -> ../../../devices/virtual/block/dm-4/bcache/lrwxrwxrwx 1 root root 0 Mar 5 09:39 5bc072a8-ab17-446d-9744-e247949913c1/cache0 -> ../../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/ata10/host9/target9:0:0/9:0:0:0/block/sdl/sdl2/bcache/
    设备名将显示哪个UUID是相关的,在该目录下cd,然后stop the cache:
    host:/sys/fs/bcache/5bc072a8-ab17-446d-9744-e247949913c1# echo 1 > stop
    这将会释放bcache引用,让你重用其它目的的分区。
    

性能调优

  1. Backing device 对齐

    bcache中的默认(metadata)元数据大小为8k。

    如果你的 Backing device 是基于 RAID 的,那么请务必使用make-bcache --data-offset将其与你的 RAID 条带大小对齐(即设置为 raid 条带大小的倍数)。--可避免写放大。如果考虑未来RAID的扩展,则用RAID条带大小乘以一序列素数,来得到你想要的磁盘倍数,建议这样计算data-offset的值。

    For example: If you have a 64k stripe size, then the following offset
    would provide alignment for many common RAID5 data spindle counts:
    64k * 2223357 bytes = 161280k

  2. 写入性能差

    假如写入性能不达预期,你或许想运行在writeback模式下面,这并非默认的模式。(writeback模式之所以不是默认模式,不是因为不成熟,而是因为该模式可能在某些情况下丢失数据。)
    默认 bcache 的 cache_mode 是 writeround,改成 writeback,提高写入性能。

    echo writeback > /sys/block/bcache0/bcache/cache_mode

  3. 性能差,或者到SSD的流量未达预期

    默认情况下,bcache不会缓存所有内容.它尝试跳过顺序IO,因为你真正想要缓存的是随机IO。
    如果你复制一个10GB的文件,你可能也不希望将 cache 中10GB 的随机访问数据从缓存中刷新走(cache 可用空间不够时,根据lru算法将冷数据回写到backing device)。
    但是假如你要对读缓存进行基准测试,使用 fio写一个8 GB的测试文件,你需要禁用它(允许顺序IO):
    echo 0 > /sys/block/bcache0/bcache/sequential_cutoff
    调整 backing 设备的顺序IO 阈值,表示 bcache0 设备的顺序IO大于4MB 时,大于 4MB 的部分不会走 SSD 设备,也不会缓存到 ssd,而是直接读写 backing 设备。(default:4M)
    echo 4M > /sys/block/bcache0/bcache/sequential_cutoff

  4. 流量仍然进入后端设备(spindle)/仍旧得到cache miss

    现实中SSD并不总是能跟上硬盘的速度,特别是那些慢速的SSD,在一块SSD为很多HDD做缓存设备,或者出现大比例的序列化IO的情况下。假如你想避免SSD成为瓶颈,就让每件事慢下来。
    bcache会跟踪每个IO,如果IO的时间超过阈值,则旁路cache设备,直接读写backing设备。

  5. 为避免bcache追踪缓存设备的延迟,假如延迟超过阈值时,逐步阻塞流量(通过降低顺序旁路来实现)

    如果你的SSD足够强大,可以不跟踪,减少跟踪的开销。
    如果你需要的话,可以设置阈值为0来禁用它

    echo 0 > /sys/fs/bcache//congested_read_threshold_us

    echo 0 > /sys/fs/bcache//congested_write_threshold_us

    关闭旁路的另一个好处是,所有的离散读写都会经过cache设备,从而不会导致cache missing。

    默认情况下当读请求超过2ms,写请求超过20ms时,旁路cache设备。
    The default is 2000 us (2 milliseconds) for reads, and 20000 for writes.

  6. 某些数据仍然cache miss

    最后一个困扰人们的问题事实上是个老bug,由于缓存连贯性(cache coherency)对cache miss的处理方式。
    当btree node慢了之后,cache miss时并不能对新数据插入key,对应数据也不能写到cache中。
    事实上这并不是问题,因为只要cache写到来,将会导致btree node分裂(split),根本无需可观的
    写流量,这很难观察到(特别当bcache的btree nodes很多,要索引设备上大部分区域的时候)
    但当benchmark的时候,假如你想通过大量数据,让它成为缓存中的热点时,不需要其它流量,这可能是个问题。

    解决方法:

    通过写操作来让cache形成热点,或使用测试分支的代码(那里对该问题做了修复)

实际操作

知识点:

  1. lsblk看到的是后端存储,缓存只是在配置那里。
# 查询缓存盘信息
bcache-super-show

# 配置前端缓存盘。
make-bcache -C /dev/sdb
# 删除前端缓存盘
echo 1 >/sys/fs/bcache/8cae4fac-1312-4b0a-8bf7-2142dae5a334/unregister

# 配置后端缓存盘之前先擦除数据
wipefs -a /dev/sdc /dev/sdbd

# 配置后端存储盘
make-bcache -B /dev/sdb
# 移除后端存储盘
echo 1 > /sys/block/bcache0/bcache/stop

# 将缓存盘给bcache0, 将缓存盘给bcache1
# 建立映射关系
echo "8cae4fac-1312-4b0a-8bf7-2142dae5a334" > /sys/block/bcache0/bcache/attach

#将缓存盘从bcache0中移除。
# 解除映射关系
echo "8cae4fac-1312-4b0a-8bf7-2142dae5a334" > /sys/block/bcache0/bcache/detach
posted @ 2021-10-09 13:52  Test002  阅读(159)  评论(0)    收藏  举报