注意

本文档适用于 Ceph 的开发版本。

缓存分层

警告

缓存分层已在 Reef 版本中弃用。缓存分层已很长时间没有维护者。这并不意味着它一定会被移除,但它可能会在没有太多通知的情况下被移除。

上游 Ceph 社区强烈建议不要部署新的缓存分层。上游 Ceph 社区还建议从旧版部署中进行迁移。

缓存分层为 Ceph 客户端提供存储在后端存储层中的部分数据的更好 I/O 性能。缓存分层涉及创建一个配置为充当缓存层的相对快速/昂贵的存储设备(例如,固态驱动器)池,以及一个配置为充当经济型存储层的纠删码或相对较慢/便宜的设备后端池。Ceph 对象器处理对象的放置位置,分层代理确定何时将对象从缓存刷新到后端存储层。因此,缓存层和后端存储层对 Ceph 客户端是完全透明的。

缓存分层代理自动处理缓存层和后端存储层之间的数据迁移。但是,管理员可以通过设置 cache-mode 来配置此迁移的发生方式。有两种主要情况

  • writeback 模式:如果基础层和缓存层配置为 writeback 模式,则 Ceph 客户端每次向其写入数据时都会收到来自基础层的 ACK。然后缓存分层代理确定是否已设置 osd_tier_default_cache_min_write_recency_for_promote。如果已设置并且数据在每个间隔内写入了指定次数以上,则数据将提升到缓存层。

    当 Ceph 客户端需要访问存储在基础层中的数据时,缓存分层代理从基础层读取数据并将其返回给客户端。在从基础层读取数据时,缓存分层代理会查阅 osd_tier_default_cache_min_read_recency_for_promote 的值,并决定是否将该数据从基础层提升到缓存层。当数据从基础层提升到缓存层时,Ceph 客户端能够使用缓存层对其执行 I/O 操作。这非常适合可变数据(例如,照片/视频编辑、事务数据)。

  • readproxy 模式:此模式将使用缓存层中已存在的任何对象,但如果对象不在缓存中,则请求将代理到基础层。这对于从 writeback 模式过渡到禁用缓存非常有用,因为它允许工作负载在缓存排空时正常运行,而无需向缓存添加任何新对象。

其他缓存模式有

  • readonly 仅在读取操作时将对象提升到缓存;写入操作转发到基础层。此模式适用于不需要存储系统强制执行一致性的只读工作负载。(警告:当对象在基础层中更新时,Ceph 不会尝试将这些更新同步到缓存中的相应对象。由于此模式被认为是实验性的,因此必须传入 --yes-i-really-mean-it 选项才能启用它。)

  • none 用于完全禁用缓存。

注意事项

缓存分层将降低大多数工作负载的性能。用户在使用此功能之前应极其谨慎。

  • 取决于工作负载:缓存是否能提高性能高度取决于工作负载。因为将对象移入或移出缓存会产生开销,所以只有当数据集中的访问模式存在较大偏差时才有效,即大多数请求只触及少量对象。缓存池应足够大,以捕获工作负载的工作集,从而避免抖动。

  • 难以基准测试:大多数用户运行的用于衡量性能的基准测试在启用缓存分层时会显示出糟糕的性能,部分原因是很少有基准测试将请求偏向一小部分对象,缓存可能需要很长时间才能“预热”,并且预热成本可能很高。

  • 通常较慢:对于不适合缓存分层的工作负载,性能通常比未启用缓存分层的普通 RADOS 池慢。

  • librados 对象枚举:在有缓存存在的情况下,librados 级别的对象枚举 API 并非旨在保持一致性。如果您的应用程序直接使用 librados 并依赖对象枚举,则缓存分层可能无法按预期工作。(对于 RGW、RBD 或 CephFS,这不是问题。)

  • 复杂性:启用缓存分层意味着使用了 RADOS 集群中的许多额外机制和复杂性。这增加了您遇到其他用户尚未遇到的系统错误的概率,并会使您的部署处于更高的风险级别。

已知良好工作负载

  • RGW 时间偏差:如果 RGW 工作负载的特点是几乎所有读取操作都针对最近写入的对象,则简单的缓存分层配置(在可配置时间段后将最近写入的对象从缓存卸载到基础层)可以很好地工作。

已知不良工作负载

以下配置已知与缓存分层配合不佳

  • RBD 具有复制缓存和纠删码基础:这是一个常见的请求,但通常性能不佳。即使是合理偏差的工作负载,仍然会向冷对象发送一些小写入,并且由于纠删码池尚不支持小写入,因此必须将整个(通常为 4 MB)对象迁移到缓存中才能满足小(通常为 4 KB)写入。只有少数用户成功部署了此配置,并且仅在他们的数据非常冷(备份)并且他们对性能不敏感的情况下才有效。

  • RBD 具有复制缓存和基础:RBD 具有复制基础层比基础为纠删码时表现更好,但它仍然高度依赖于工作负载中的偏差程度,并且非常难以验证。用户需要对其工作负载有很好的理解,并且需要仔细调整缓存分层参数。

设置池

要设置缓存分层,您必须有两个池。一个将充当后端存储,另一个将充当缓存。

设置后端存储池

设置后端存储池通常涉及以下两种情况之一

  • 标准存储:在这种情况下,池在 Ceph 存储集群中存储对象的多个副本。

  • 纠删码: 在这种情况下,池使用纠删码以更高的效率存储数据,但会牺牲少量性能。

在标准存储场景中,您可以设置 CRUSH 规则来建立故障域(例如 osd、host、chassis、rack、row 等)。当规则中的所有存储驱动器具有相同的大小、速度(RPM 和吞吐量)和类型时,Ceph OSD 守护程序才能以最佳方式运行。有关创建规则的详细信息,请参阅 CRUSH 映射。创建规则后,创建后端存储池。

在纠删码场景中,池创建参数将自动生成适当的规则。有关详细信息,请参阅 创建池

在后续示例中,我们将后端存储池称为 cold-storage

设置缓存池

设置缓存池遵循与标准存储场景相同的过程,但有一个区别:缓存层的驱动器通常是高性能驱动器,位于自己的服务器中并有自己的 CRUSH 规则。设置此类规则时,应考虑具有高性能驱动器的主机,同时忽略没有高性能驱动器的主机。有关详细信息,请参阅 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 的生产缓存层使用 布隆过滤器 作为 hit_set_type

ceph osd pool set {cachepool} hit_set_type bloom

例如

ceph osd pool set hot-storage hit_set_type bloom

hit_set_counthit_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_promotemin_write_recency_for_promote 值越高,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_bytestarget_max_objects 达到时,所有客户端请求才会被阻止

相对大小调整

缓存分层代理可以根据缓存池的大小(由 绝对大小调整中的 target_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

移除缓存分层

移除缓存分层取决于它是写回缓存还是只读缓存。

移除只读缓存

由于只读缓存没有修改过的数据,您可以禁用并移除它,而不会丢失缓存中对象的任何最新更改。

  1. 将 cache-mode 更改为 none 以禁用它。

    ceph osd tier cache-mode {cachepool} none
    

    例如

    ceph osd tier cache-mode hot-storage none
    
  2. 从后端池中移除缓存池。

    ceph osd tier remove {storagepool} {cachepool}
    

    例如

    ceph osd tier remove cold-storage hot-storage
    

移除写回缓存

由于写回缓存可能具有修改过的数据,因此您必须采取措施确保在禁用和移除它之前不会丢失缓存中对象的任何最新更改。

  1. 将缓存模式更改为 proxy,以便新对象和修改后的对象将刷新到后端存储池。

    ceph osd tier cache-mode {cachepool} proxy
    

    例如

    ceph osd tier cache-mode hot-storage proxy
    
  2. 确保缓存池已刷新。这可能需要几分钟

    rados -p {cachepool} ls
    

    如果缓存池中仍有对象,您可以手动刷新它们。例如

    rados -p {cachepool} cache-flush-evict-all
    
  3. 移除覆盖层,以便客户端不会将流量定向到缓存。

    ceph osd tier remove-overlay {storagetier}
    

    例如

    ceph osd tier remove-overlay cold-storage
    
  4. 最后,从后端存储池中移除缓存层池。

    ceph osd tier remove {storagepool} {cachepool}
    

    例如

    ceph osd tier remove cold-storage hot-storage
    

对未找到对象进行故障排除

在某些情况下,重新启动 OSD 可能会导致未找到对象。

这是在从 Ceph 14.2.6 升级到 Ceph 14.2.7 期间出现未找到对象的示例

2/543658058 objects unfound (0.000%)
pg 19.12 has 1 unfound objects
pg 19.2d has 1 unfound objects

Possible data damage: 2 pgs recovery_unfound
pg 19.12 is active+recovery_unfound+undersized+degraded+remapped, acting [299,310], 1 unfound
pg 19.2d is active+recovery_unfound+undersized+degraded+remapped, acting [290,309], 1 unfound

# ceph pg 19.12 list_unfound
{
    "num_missing": 1,
    "num_unfound": 1,
    "objects": [
        {
            "oid": {
                "oid": "hit_set_19.12_archive_2020-02-25 13:43:50.256316Z_2020-02-25 13:43:50.325825Z",
                "key": "",
                "snapid": -2,
                "hash": 18,
                "max": 0,
                "pool": 19,
                "namespace": ".ceph-internal"
            },
            "need": "3312398'55868341",
            "have": "0'0",
            "flags": "none",
            "locations": []
        }
    ],
    "more": false

现场的一些测试表明,可以删除未找到的对象而不会产生不利影响(请参阅 Tracker Issue #44286, Note 3)。Pawel Stefanski 建议,只要对象是 .ceph-internal::hit_set_PGID_archive 的一部分,删除丢失或未找到的对象就是安全的。

上游 Ceph 社区的成员在 Tracker Issue #44286 中报告称,以下版本的 Ceph 受此问题影响

  • 14.2.8

  • 14.2.16

  • 15.2.15

  • 16.2.5

  • 17.2.7

有关此问题的历史记录,请参阅 Tracker Issue #44286

由 Ceph 基金会为您呈现

Ceph 文档是由非营利性 Ceph 基金会 资助和托管的社区资源。如果您希望支持这项工作和我们的其他努力,请考虑 立即加入