编写策略指南¶
尽量避免事务性。核心代码会谨慎地避免查询任何正在迁移的事物。这虽然很麻烦,但能让策略的编写更容易。
映射在构建时加载到策略中。
目标映射的每个 bio 都将参考策略。策略可以返回简单的“命中 (HIT)”或“未命中 (MISS)”,或发起迁移。
目前策略无法发起后台工作,例如开始写回即将被逐出的脏块。
因为我们映射的是 bio 而不是请求,所以策略很容易被许多小的 bio 欺骗。因此,核心目标会定期向策略发出“心跳”。建议策略在每个心跳周期内,不要为一个块多次更新状态(例如,命中计数)。核心通过观察 bio 完成来发出心跳,从而尝试了解 I/O 调度程序何时允许 I/O 运行。
提供的缓存替换策略概述¶
多队列 (mq)¶
此策略现在是 smq 的别名(见下文)。
接受以下可调参数,但它们不起作用
'sequential_threshold <#nr_sequential_ios>'
'random_threshold <#nr_random_ios>'
'read_promote_adjustment <value>'
'write_promote_adjustment <value>'
'discard_promote_adjustment <value>'
随机多队列 (smq)¶
此策略是默认策略。
随机多队列 (smq) 策略解决了多队列 (mq) 策略的一些问题。
与 mq 策略相比,smq 策略有望降低内存使用、提高性能并在工作负载变化时增强适应性。smq 也没有任何繁琐的调优旋钮。
用户只需适当地重新加载使用缓存目标的 DM 表,即可从“mq”切换到“smq”。这样做会导致 mq 策略的所有提示都被丢弃。此外,缓存性能可能会略有下降,直到 smq 重新计算出应缓存的源设备热点。
内存使用¶
mq 策略占用大量内存;在 64 位机器上每个缓存块占用 88 字节。
smq 使用 28 位索引而不是指针来实现其数据结构。它避免为每个块存储显式的命中计数。它有一个“热点”队列,而不是预缓存,该队列使用四分之一的条目(每个热点块覆盖的区域比单个缓存块更大)。
所有这些意味着 smq 每个缓存块使用约 25 字节。尽管仍然占用大量内存,但这仍然是一个显著的改进。
级别平衡¶
mq 根据命中计数(约 ln(命中计数))将条目放置在多队列结构的不同级别中。这意味着底层通常包含最多的条目,而顶层则很少。这种不平衡的级别降低了多队列的效率。
smq 不维护命中计数,而是将命中的条目与来自上一层最不常使用的条目进行交换。整体排序是这种随机过程的副作用。通过这种方案,我们可以决定每个多队列级别占用多少条目,从而做出更好的提升/降级决策。
适应性:mq 策略为每个缓存块维护一个命中计数。要将不同的块提升到缓存中,其命中计数必须超过当前缓存中最低的。这意味着缓存适应不同的 I/O 模式可能需要很长时间。
smq 不维护命中计数,因此很多问题都迎刃而解。此外,它还会跟踪热点队列的性能,热点队列用于决定提升哪些块。如果热点队列性能不佳,它会开始更快地在级别之间移动条目。这使得它能够非常快速地适应新的 I/O 模式。
性能¶
测试表明 smq 的性能显著优于 mq。
清理器¶
清理器会将缓存中所有脏块写回以将其解除服务。
示例¶
表的语法是
cache <metadata dev> <cache dev> <origin dev> <block size>
<#feature_args> [<feature arg>]*
<policy> <#policy_args> [<policy arg>]*
使用 dmsetup 命令发送消息的语法是
dmsetup message <mapped device> 0 sequential_threshold 1024
dmsetup message <mapped device> 0 random_threshold 8
使用 dmsetup
dmsetup create blah --table "0 268435456 cache /dev/sdb /dev/sdc \
/dev/sdd 512 0 mq 4 sequential_threshold 1024 random_threshold 8"
creates a 128GB large mapped device named 'blah' with the
sequential threshold set to 1024 and the random_threshold set to 8.