对于存储在后备存储层中的数据子集,缓存层为 Ceph 客户端提供了更好的 I/O 性能。缓存分层涉及创建一个配置为缓存层的相对快速/昂贵的存储设备(例如,固态驱动器)池,以及配置为经济存储的纠删码或相对较慢/更便宜的设备的后备池层。Ceph 对象器处理对象的放置位置,分层代理决定何时将对象从缓存刷新到后备存储层。所以缓存层和后备存储层对 Ceph 客户端是完全透明的。
缓存分层代理自动处理缓存层和后备存储层之间的数据迁移。但是,管理员可以通过cache-mode
设置。主要有两种情况:
writeback模式:当管理员使用writeback
模式配置层时,Ceph 客户端将数据写入缓存层并从缓存层接收 ACK。随着时间的推移,写入缓存层的数据会迁移到存储层并从缓存层中刷新。从概念上讲,缓存层覆盖在后备存储层的“前面”。当 Ceph 客户端需要存储层中的数据时,缓存分层代理会在读取时将数据迁移到缓存层,然后将其发送到 Ceph 客户端。此后,Ceph 客户端可以使用缓存层执行 I/O,直到数据变为非活动状态。这对于可变数据(例如,照片/视频编辑、事务数据等)非常理想。
readproxy模式:此模式将使用缓存层中已存在的任何对象,但如果缓存中不存在对象,则请求将被代理到基本层。这对于从writeback
模式转换到禁用的缓存很有用,因为它允许工作负载在缓存耗尽时正常运行,而无需向缓存添加任何新对象。
其他缓存模式有:
readonly:仅在读取操作时将对象提升到缓存;写操作被转发到基础层。此模式适用于不需要存储系统强制执行一致性的只读工作负载。(警告:当基础层中的对象更新时,Ceph不会尝试将这些更新同步到缓存中的相应对象。由于这种模式被认为是实验性的, 因此必须传递一个--yes-i-really-mean-it
选项才能启用它。)
none:用于完全禁用缓存。
缓存分层会降低大多数工作负载的性能。用户在使用此功能之前应格外小心。
工作负载依赖:缓存是否会提高性能在很大程度上取决于工作负载。因为将对象移入或移出缓存是有成本的,所以只有在数据集中的访问模式存在较大偏差时才会有效,这样大多数请求都会触及少量对象。缓存池应该足够大,以便为您的工作负载捕获工作集以避免颠簸。
难以进行基准测试:用户运行来衡量性能的大多数基准测试都会显示缓存分层的糟糕性能,部分原因是它们中很少有人将请求偏向一小部分对象,缓存可能需要很长时间才能“预热 ”,而且因为热身成本可能很高。
通常较慢:对于缓存分层不友好的工作负载,性能通常比未启用缓存分层的普通 RADOS 池慢。
librados 对象枚举:librados 级别的对象枚举 API 并不意味着在存在案例的情况下是连贯的。如果您的应用程序直接使用 librados 并依赖于对象枚举,则缓存分层可能无法按预期工作。(这对于 RGW、RBD 或 CephFS 来说不是问题。)
复杂性:启用缓存分层意味着在 RADOS 集群中使用了许多额外的机制和复杂性。这增加了您在系统中遇到其他用户尚未遇到的错误的可能性,并将您的部署置于更高级别的风险中。
RGW time-skewed:如果 RGW 工作负载几乎所有读取操作都针对最近写入的对象,那么在可配置的时间段后将最近写入的对象从缓存中转移到基本层的简单缓存分层配置可以很好地工作。
已知以下配置在缓存分层方面效果不佳。
带有复制缓存和纠删码基层的 RBD:这是一个常见的请求,但通常表现不佳。即使是合理倾斜的工作负载仍然会向冷对象发送一些小写入,并且由于纠删码池尚不支持小写入,因此必须将整个(通常为 4 MB)对象迁移到缓存中以满足小(通常为 4 KB) 写入。只有少数用户成功部署了这个配置,而且它只对他们有效,因为他们的数据非常冷(备份),而且他们对性能不敏感。
具有复制缓存和基层的 RBD:具有复制基层的 RBD 比使用纠删码的基层做得更好,但它仍然高度依赖于工作负载中的偏差量,并且非常难以验证。用户需要很好地了解他们的工作负载,并且需要仔细调整缓存分层参数。
要设置缓存分层,您必须有两个池。一个将充当后备存储,另一个将充当缓存。
设置后备存储池通常涉及以下两种情况之一:
标准存储:在这种情况下,池在 Ceph 存储集群中存储一个对象的多个副本。
纠删码:在这种情况下,池使用纠删码来更有效地存储数据,但性能折衷很小。
设置缓存池遵循与标准存储方案相同的过程,但有一点不同:缓存层的驱动器通常是高性能驱动器,它们驻留在自己的服务器中并具有自己的 CRUSH 规则。设置此类规则时,应考虑具有高性能驱动器的主机,而忽略不具有高性能驱动器的主机。
在随后的示例中,我们将缓存池称为hot-storage
,将后备池称为cold-storage
。
设置缓存层涉及将后备存储池与缓存池相关联
ceph osd tier add {storagepool} {cachepool}
例如:
ceph osd tier add cold-storage hot-storage
要设置缓存模式,请执行以下命令:
ceph osd tier cache-mode {cachepool} {cache-mode}
例如:
ceph osd tier cache-mode hot-storage writeback
缓存层覆盖了后备存储层,因此它们需要一个额外的步骤:您必须将所有客户端流量从存储池引导到缓存池。要将客户端流量直接引导到缓存池,请执行以下命令:
ceph osd tier set-overlay {storagepool} {cachepool}
例如:
ceph osd tier set-overlay cold-storage hot-storage
缓存层有几个配置选项。您可以使用以下用法设置缓存层配置选项:
ceph osd pool set {cachepool} {key} {value}
Ceph 的生产缓存层使用Bloom Filter来处理hit_set_type
:
ceph osd pool set {cachepool} hit_set_type bloom
例如:
ceph osd pool set hot-storage hit_set_type bloom
hit_set_count
和hit_set_period
定义要存储多少这样的 HitSet,以及每个 HitSet 应该覆盖多少时间。
ceph osd pool set {cachepool} hit_set_count 12 ceph osd pool set {cachepool} hit_set_period 14400 ceph osd pool set {cachepool} target_max_bytes 1000000000000
笔记:较大的
hit_set_count
结果会导致ceph-osd
进程消耗更多的 RAM 。
随着时间的推移对访问进行分箱,Ceph 可以确定 Ceph 客户端是否在一段时间内至少访问了一次对象,还是多次访问(“年龄”与“温度”)。
定义了在处理读取操作时检查对象是否存在的min_read_recency_for_promote
HitSet 数量。检查结果用于决定是否异步提升对象。它的值应该在 0 和 hit_set_count
之间。如果设置为 0,则始终提升对象。如果设置为 1,则检查当前的 HitSet。如果这个对象在当前的 HitSet 中,它就会被提升。否则不行。对于其他值,将检查归档 HitSet 的确切数量。如果在任何最近的min_read_recency_for_promote
HitSet 中找到对象,则提升该对象。
可以为写操作设置一个类似的参数,即 min_write_recency_for_promote
.
ceph osd pool set {cachepool} min_read_recency_for_promote 2 ceph osd pool set {cachepool} min_write_recency_for_promote 2
笔记:周期越长,
min_read_recency_for_promote
andmin_write_recency_for_promote``values,
守护进程ceph-osd
的RAM消耗就越高。特别是,当代理处于活动状态以刷新或驱逐缓存对象时,所有hit_set_count
HitSet 都将加载到 RAM 中。
缓存分层代理执行两个主要功能:
刷新:代理识别修改(或脏)对象,并将其转发到存储池进行长期存储。
驱逐:代理识别尚未修改(或清理)的对象,并从缓存中驱逐最近最少使用的对象。
缓存分层代理可以根据字节总数或对象总数刷新或驱逐对象。要指定最大字节数,请执行以下命令:
ceph osd pool set {cachepool} target_max_bytes {#bytes}
例如,要以 1 TB 刷新或驱逐,请执行以下命令:
ceph osd pool set hot-storage target_max_bytes 1099511627776
要指定最大对象数,请执行以下命令:
ceph osd pool set {cachepool} target_max_objects {#objects}
例如,要刷新或驱逐 1M 个对象,请执行以下操作:
ceph osd pool set hot-storage target_max_objects 1000000
笔记:Ceph 无法自动确定缓存池的大小,所以这里需要配置绝对大小,否则刷新/驱逐将不起作用。如果您同时指定这两个限制,则缓存分层代理将在触发任一阈值时开始刷新或逐出。
笔记:所有客户端请求只有在
target_max_bytes
或target_max_objects
到达时才会被阻止。
缓存分层代理可以相对于缓存池的大小(在 Absolute 中由sizingtarget_max_bytes
/target_max_objects
指定)刷新或驱逐对象。当缓存池包含一定比例的修改(或脏)对象时,缓存分层代理会将它们刷新到存储池。要设置cache_target_dirty_ratio
,请执行以下命令:
ceph osd pool set {cachepool} cache_target_dirty_ratio {0.0..1.0}
例如,将值设置为0.4
将在修改(脏)对象达到缓存池容量的 40% 时开始刷新:
ceph osd pool set hot-storage cache_target_dirty_ratio 0.4
当脏对象达到其容量的一定百分比时,以更高的速度刷新脏对象。设置cache_target_dirty_high_ratio
:
ceph osd pool set {cachepool} cache_target_dirty_high_ratio {0.0..1.0}
例如,将值设置为0.6
将在脏对象达到缓存池容量的 60% 时开始积极刷新脏对象。显然,我们最好设置dirty_ratio和full_ratio之间的值:
ceph osd pool set hot-storage cache_target_dirty_high_ratio 0.6
当缓存池达到其容量的一定百分比时,缓存分层代理将驱逐对象以保持空闲容量。要设置 cache_target_full_ratio
,请执行以下命令:
ceph osd pool set {cachepool} cache_target_full_ratio {0.0..1.0}
例如,将值设置为0.8
将在未修改(干净)对象达到缓存池容量的 80% 时开始刷新:
ceph osd pool set hot-storage cache_target_full_ratio 0.8
您可以在缓存分层代理将最近修改(或脏)的对象刷新到后备存储池之前指定对象的最小年龄:
ceph osd pool set {cachepool} cache_min_flush_age {#seconds}
例如,要在 10 分钟后刷新已修改(或脏)的对象,请执行以下命令:
ceph osd pool set hot-storage cache_min_flush_age 600
您可以指定对象从缓存层中逐出之前的最小年龄:
ceph osd pool {cache-tier} cache_min_evict_age {#seconds}
例如,要在 30 分钟后驱逐对象,请执行以下命令:
ceph osd pool set hot-storage cache_min_evict_age 1800
删除缓存层取决于它是写回缓存还是只读缓存。
由于只读缓存没有修改过的数据,因此您可以禁用和删除它,而不会丢失对缓存中对象的任何最近更改。
将缓存模式更改none
为禁用它。
ceph osd tier cache-mode {cachepool} none
例如:
ceph osd tier cache-mode hot-storage none
从后备池中删除缓存池。
ceph osd tier remove {storagepool} {cachepool}
例如:
ceph osd tier remove cold-storage hot-storage
由于写回缓存可能已修改数据,因此您必须采取措施确保在禁用和删除缓存之前不会丢失对缓存中对象的任何最新更改。
将缓存模式更改为proxy
,以便新的和修改的对象将刷新到后备存储池。
ceph osd tier cache-mode {cachepool} proxy
例如:
ceph osd tier cache-mode hot-storage proxy
确保缓存池已刷新。这可能需要几分钟的时间:
rados -p {cachepool} ls
如果缓存池仍有对象,您可以手动刷新它们。例如:
rados -p {cachepool} cache-flush-evict-all
删除覆盖,以便客户端不会将流量定向到缓存。
ceph osd tier remove-overlay {storagetier}
例如:
ceph osd tier remove-overlay cold-storage
最后,从后备存储池中删除缓存层池。
ceph osd tier remove {storagepool} {cachepool}
例如:
ceph osd tier remove cold-storage hot-storage