快速缓存层是在客户端与标准存储之间实施的附加存储层。该层用于加快访问低速硬盘中存储的存储池以及纠删码池的速度。
通常,快速缓存分层涉及到创建一个配置为充当快速缓存层的相对快速且昂贵的存储设备(例如 SSD 驱动器)池,以及一个配置为充当存储层的较慢但较便宜的设备后备池。
快速缓存分层识别两种类型的池:快速缓存池和存储池。
在 Ceph 存储集群中存储一个对象的多个副本的标准副本池,或纠删码池(请参见第 9 章 “纠删码池”)。
存储池有时称为“后备”存储或“冷”存储。
标准副本池,存储在相对较小但速度较快的存储设备上,在 CRUSH 地图中具有自己的规则组。
快速缓存池也称为“热”存储。
快速缓存分层可能会降低特定工作负载的集群性能。以下几点指出了您需要考虑的有关快速缓存分层的几个方面:
取决于工作负载:快速缓存能否提高性能取决于工作负载。由于将对象移入或移出快速缓存会耗费资源,因此,如果大多数请求只涉及到少量的对象,则使用快速缓存可能更高效。快速缓存池的大小应该足以接收工作负载的工作集,以避免性能大幅波动。
难以进行基准测试:大多数性能基准测试可能会反映使用快速缓存分层时性能会较低。原因在于,这些基准测试请求了大量的对象,而快速缓存的“预热”需要较长时间。
性能可能较低:对于不适合进行快速缓存分层的工作负载而言,其性能往往比不启用快速缓存分层的普通副本池更低。
librados
对象枚举:如果应用直接使用 librados
并依赖于对象枚举,则快速缓存分层可能无法按预期工作(对于对象网关、RBD 或 CephFS 而言,这不会造成问题)。
在以下情况下,请考虑使用快速缓存分层:
需要通过 RADOS 块设备 (RBD) 访问纠删码池。
需要通过 iSCSI(因为它沿袭了 RBD 的限制)访问纠删码池。有关 iSCSI 的详细信息,请参见第 12 章 “Ceph iSCSI 网关”。
您的高性能存储数量有限,而低性能存储众多,您需要更快地访问存储的数据。
快速缓存分层代理可处理快速缓存层与后备存储层之间的数据迁移。管理员可以配置如何进行这种迁移。主要有两种方案:
在写回模式下,Ceph 客户端将数据写入快速缓存层,并从快速缓存层接收确认响应。一段时间后,写入快速缓存层的数据将迁移到存储层,并从快速缓存层中清除。从概念上讲,快速缓存层叠加在后备存储层的“前面”。当 Ceph 客户端需要驻留在存储层中的数据时,快速缓存分层代理会在读取时将数据迁移到快速缓存层,然后,数据将发送到 Ceph 客户端。因此,在数据变为不活动状态前,Ceph 客户端可以使用快速缓存层执行 I/O。这种做法非常适合可变的数据,例如,编辑的照片或视频,或事务数据。
在只读模式下,Ceph 客户端将数据直接写入后备层。在读取时,Ceph 将请求的对象从后备层复制到快速缓存层。过时对象将会根据定义的策略从快速缓存层中删除。这种做法非常适合不可变的数据,例如,在社交网络上呈现的图片或视频、DNA 数据或 X 光成像,因为从可能包含过时数据的快速缓存池中读取数据会导致一致性很差。不要对可变的数据使用只读模式。
使用命中集参数可以优化快速缓存池。Ceph 中的命中集通常是布隆过滤器,提供节省内存用量的方式来跟踪已存放于快速缓存池的对象。
命中集是一个位数组,用于存储针对对象名称应用的一组哈希函数的结果。最初,所有的位都设为 0
。将对象添加到命中集后,该对象的名称将经过哈希处理,结果将映射在命中集中的不同位置,那时,位的值便会设置为 1
。
为了确定某个对象是否存在于快速缓存中,将会再次对对象名称进行哈希处理。如果有任何位是 0
,则表示该对象肯定不在快速缓存中,需要从冷存储中检索它。
不同对象的结果可能会存储在命中集的同一位置。在巧合的情况下,可能所有位都是 1
,而对象却不在快速缓存中。因此,处理布隆过滤器的命中集只能确定某个对象是否一定不在快速缓存中,需要从冷存储检索它。
一个快速缓存池可以使用多个命中集来跟踪各时间段的文件访问。设置 hit_set_count
定义所用的命中集数量,hit_set_period
定义每个命中集已使用了多长时间。该期限过期后,将使用下一个命中集。如果用尽了命中集,将会释放最旧命中集的内存,并创建新的命中集。将 hit_set_count
和 hit_set_period
的值相乘可定义已跟踪对象访问的整个时间范围。
与哈希处理对象的数量相比,基于布隆过滤器的命中集非常地节省内存用量。只需使用不到 10 个位即可将误报率降低到 1% 以下。可以使用 hit_set_fpp
定义误报率。Ceph 可根据归置组中的对象数量及误报率自动计算命中集的大小。
可以使用 min_write_recency_for_promote
和 min_read_recency_for_promote
限制快速缓存池中所需的存储。如果将值设置为 0
,则所有对象在被读取或写入后,会立即提升到快速缓存池,并且在被逐出之前会一直保持这种模式。使用大于 0
的任何值可定义在其中搜索对象的命中集(已按期限排序)的数量。如果在某个命中集中找到了该对象,会将该对象提升到快速缓存池。
如果有大量的存储,但只有少量的 RAM 可用,则所有对象在被访问后可立即提升到快速缓存池。命中集保持较小的规模。下面是一组示例配置值:
hit_set_count = 1 hit_set_period = 3600 hit_set_fpp = 0.05 min_write_recency_for_promote = 0 min_read_recency_for_promote = 0
如果只有少量的存储,但可用的内存量相对较大,则可以将快速缓存层配置为将有限数量的对象提升到快速缓存池。如果有 12 个命中集,并且在 14,400 秒期限内可以使用其中每个命中集,则这些命中集总共可提供 48 小时的跟踪。如果在过去 8 小时内访问了某个对象,该对象将提升到快速缓存池。这种情况的一组示例配置值如下:
hit_set_count = 12 hit_set_period = 14400 hit_set_fpp = 0.01 min_write_recency_for_promote = 2 min_read_recency_for_promote = 2
本节举例说明如何在标准硬盘(冷存储)的前面设置一个高速 SSD 快速缓存层(热存储)。
下面的示例仅用于说明目的,其中的设置包含单个 Ceph 节点上存在的 SSD 部件的一个根及一条规则。
在生产环境中,集群设置通常包含热存储以及混合节点(配有 SSD 和 SATA 磁盘)的更多根项和规则项。
准备一台配有 SSD 等高速驱动器的主机。此集群节点将充当高速缓存层。
使用 DeepSea 将该计算机转变成 Ceph 节点。根据第 1.1 节 “添加新的集群节点”中所述安装软件并配置主机计算机。我们假设此节点名为 node-4。此节点需要有 4 个 OSD 磁盘。
这可能会在 CRUSH 地图中生成类似下方所示的项:
[...] host node-4 { id -5 # do not change unnecessarily # weight 0.012 alg straw hash 0 # rjenkins1 item osd.6 weight 0.003 item osd.7 weight 0.003 item osd.8 weight 0.003 item osd.9 weight 0.003 } [...]
编辑热存储池(已映射到基于高速 SSD 驱动器的 OSD)的 CRUSH 地图。定义另一个包含 SSD 的根节点的层次结构(命令为“root ssd”)。此外,请更改 SSD 的权重和 CRUSH 规则。有关 CRUSH 地图的详细信息,请参见 http://docs.ceph.com/docs/master/rados/operations/crush-map/。
使用 getcrushmap
和 crushtool
等命令行工具直接编辑 CRUSH 地图。
检索当前地图,并将其另存为 c.map
:
cephadm >
sudo ceph osd getcrushmap -o c.map
反编译 c.map
,并将其另存为 c.txt
:
cephadm >
crushtool -d c.map -o c.txt
编辑 c.txt
:
[...] host node-4 { id -5 # do not change unnecessarily # weight 4.000 alg straw hash 0 # rjenkins1 item osd.6 weight 1.000 item osd.7 weight 1.000 item osd.8 weight 1.000 item osd.9 weight 1.000 } root ssd { # newly added root for the SSD hot-storage id -6 alg straw hash 0 item node-4 weight 4.00 } rule ssd { ruleset 4 type replicated min_size 0 max_size 4 step take ssd step chooseleaf firstn 0 type host step emit } [...]
编译已编辑的 c.txt
文件,并将其另存为 ssd.map
:
cephadm >
crushtool -c c.txt -o ssd.map
最后,安装 ssd.map
,作为新的 CRUSH 地图:
cephadm >
sudo ceph osd setcrushmap -i ssd.map
创建用于快速缓存分层的热存储池。对该池使用新的“ssd”规则:
cephadm >
sudo ceph osd pool create hot-storage 100 100 replicated ssd
使用默认的“replicated_ruleset”规则创建冷存储池:
cephadm >
sudo ceph osd pool create cold-storage 100 100 replicated replicated_ruleset
然后,设置快速缓存层的过程涉及到将后备存储池关联到快速缓存池,在本例中,需要将冷存储(即存储池)关联到热存储(即快速缓存池):
cephadm >
sudo ceph osd tier add cold-storage hot-storage
要将快速缓存模式设置为“写回”,请执行以下命令:
cephadm >
sudo ceph osd tier cache-mode hot-storage writeback
有关快速缓存模式的详细信息,请参见第 10.4 节 “快速缓存模式”。
写回快速缓存层叠加在后备存储池上,因此需要执行一个额外的步骤:必须将来自存储池的所有客户端流量定向到快速缓存池。例如,要将客户端流量直接定向到快速缓存池,请执行以下命令:
cephadm >
sudo ceph osd tier set-overlay cold-storage hot-storage
可以使用多个选项来配置快速缓存层。使用以下语法:
cephadm >
sudo ceph osd pool set cachepool key value
以下步骤说明如何使用第 10.5.2.2 节 “小型快速缓存池和大量内存”中提供的值配置快速缓存池
Ceph 的生产快速缓存层针对 hit_set_type
使用布隆过滤器:
cephadm >
sudo ceph osd pool set cachepool hit_set_type bloom
hit_set_count
和 hit_set_period
定义每个命中集应该经历的时长,以及要存储多少个这样的命中集。
cephadm >
sudo ceph osd pool set cachepool hit_set_count 12cephadm >
sudo ceph osd pool set cachepool hit_set_period 14400cephadm >
sudo ceph osd pool set cachepool target_max_bytes 1000000000000
hit_set_count
越大,ceph-osd
进程耗费的 RAM 就越多。
min_read_recency_for_promote
定义在处理读取操作时,要在多少个命中集中检查某个对象是否存在。检查结果用于确定是否要以异步方式提升该对象。此参数的值应介于 0 到 hit_set_count
之间。如果设置为 0,则始终提升该对象。如果设置为 1,则检查当前命中集。如果此对象在当前命中集中,则提升此对象。否则,将不提升。如果设置为其他值,则检查相应数量的存档命中集。如果在任何最近的 min_read_recency_for_promote
命中集中找到了该对象,则提升该对象。
可以针对写入操作设置类似的参数,即 min_write_recency_for_promote
:
cephadm >
sudo ceph osd pool set cachepool min_read_recency_for_promote 2cephadm >
sudo ceph osd pool set cachepool min_write_recency_for_promote 2
期限越长,min_read_recency_for_promote
和 min_write_recency_for_promote
的值越大,ceph-osd
守护进程耗费的 RAM 就越多。特别是,当代理正在清理或逐出快速缓存对象时,所有 hit_set_count
命中集都会加载到 RAM 中。
快速缓存分层代理执行两项主要功能:
代理识别已修改的(脏)对象,并将其转发到存储池长期存储。
代理识别未曾修改的(干净)对象,并将其中最近用得最少的对象从快速缓存中逐出。
快速缓存分层代理可根据字节总数或对象总数来清理或逐出对象。要指定最大字节数,请执行以下命令:
cephadm >
sudo ceph osd pool set cachepool target_max_bytes num_of_bytes
要指定最大对象数,请执行以下命令:
cephadm >
sudo ceph osd pool set cachepool target_max_objects num_of_objects
Ceph 无法自动确定快速缓存池的大小,因此,便需要配置绝对大小。否则,清理和逐出功能将无法正常工作。如果这两项限制都指定,则一旦触发任一阈值,快速缓存分层代理就会开始执行清理或逐出。
仅当达到 target_max_bytes
或 target_max_objects
时,才会阻止所有客户端请求。
快速缓存分层代理可以根据快速缓存池的相对大小(通过第 10.6.1.2.1 节 “绝对大小调整”中所述的 target_max_bytes
或 target_max_objects
指定)清理或逐出对象。当快速缓存池中的已修改(脏)对象达到特定百分比时,快速缓存分层代理会将这些对象清理到存储池。要设置 cache_target_dirty_ratio
,请执行以下命令:
cephadm >
sudo ceph osd pool set cachepool cache_target_dirty_ratio 0.0...1.0
例如,如果将值设置为 0.4,则当已修改(脏)对象的大小达到快速缓存池容量的 40% 时,就会开始清理这些对象。
cephadm >
sudo ceph osd pool set hot-storage cache_target_dirty_ratio 0.4
当脏对象的大小达到容量的特定百分比时,将以更高的速度清理。使用 cache_target_dirty_high_ratio
:
cephadm >
sudo ceph osd pool set cachepool cache_target_dirty_high_ratio 0.0..1.0
当快速缓存池的大小达到其容量的特定百分比时,快速缓存分层代理会逐出对象,以维持可用容量。要设置 cache_target_full_ratio
,请执行以下命令:
cephadm >
sudo ceph osd pool set cachepool cache_target_full_ratio 0.0..1.0
您可以指定在快速缓存分层代理将最近已修改的(脏)对象清理到后备存储池之前,这些对象至少可保留的期限:
cephadm >
sudo ceph osd pool set cachepool cache_min_flush_age num_of_seconds
您可以指定在将某个对象逐出快速缓存层之前,该对象至少可保留的期限:
cephadm >
sudo ceph osd pool set cachepool cache_min_evict_age num_of_seconds
快速缓存层设置包含一个称作命中集的布隆过滤器。该过滤器测试某个对象是属于一组热对象还是冷对象。对象将添加到命中集,其名称后面附有时戳。
如果集群计算机位于不同的时区,且时戳根据当地时间派生,则命中集中对象的名称可能包含将来或过去的时戳,致使用户产生误解。在最坏的情况下,对象可能根本不在命中集中。
为防止这种问题发生,在新建的快速缓存层设置中,use_gmt_hitset
默认设为“1”。这样,您便可以在创建命中集的对象名称时,强制 OSD 使用 GMT(格林威治标准时间)时戳。
不要更改 use_gmt_hitset
的默认值“1”。如果与此选项相关的错误不是因集群设置造成,切勿手动更改此选项。否则,集群的行为可能变得无法预测。