注意
本文档适用于 Ceph 的开发版本。
CRUSH 映射
CRUSH 算法计算存储位置,以确定如何存储和检索数据。CRUSH 允许 Ceph 客户端直接与 OSD 通信,而不是通过集中式服务器或代理。通过使用算法确定的存储和检索数据方法,Ceph 避免了单点故障、性能瓶颈和可扩展性的物理限制。
CRUSH 使用集群的映射(CRUSH 映射)将数据映射到 OSD,根据配置的复制策略和故障域在集群中分发数据。有关 CRUSH 的详细讨论,请参阅 CRUSH - Controlled, Scalable, Decentralized Placement of Replicated Data
CRUSH 映射包含一个 OSD 列表和一个“桶”层次结构(host、rack),以及管理 CRUSH 如何在集群池中复制数据的规则。通过反映安装的底层物理组织,CRUSH 可以建模(并因此解决)相关设备故障的可能性。与 CRUSH 层次结构相关的一些因素包括机箱、机架、物理距离、共享电源、共享网络和故障域。通过将这些信息编码到 CRUSH 映射中,CRUSH 放置策略在故障域之间分发对象副本,同时保持所需的分发。例如,为了解决并发故障的可能性,可能需要确保数据副本位于位于或依赖于不同货架、机架、电源、控制器或物理位置的设备上。
部署 OSD 时,它们会自动添加到 CRUSH 映射中,位于以 OSD 运行节点命名的 host 桶下。这种行为与配置的 CRUSH 故障域相结合,确保副本或纠删码分片分布在主机上,并且单个主机故障或其他类型的故障不会影响可用性。对于大型集群,管理员必须仔细考虑其故障域的选择。例如,对于中型到大型集群,在机架之间分发副本是很典型的。
CRUSH 位置
OSD 在 CRUSH 映射层次结构中的位置称为其 CRUSH 位置。CRUSH 位置的规范采用键值对列表的形式。例如,如果一个 OSD 位于特定的行、机架、机箱和主机中,并且也是“default”CRUSH 根的一部分(大多数集群都是这种情况),则其 CRUSH 位置可以指定如下
root=default row=a rack=a2 chassis=a2a host=a2a1
注意
键的顺序无关紧要。
键名(
=左侧)必须是有效的 CRUSHtype。默认情况下,有效的 CRUSH 类型包括root、datacenter、room、row、pod、pdu、rack、chassis和host。这些定义的类型足以满足几乎所有集群的需求,但可以通过修改 CRUSH 映射进行自定义。
可以通过在 ceph.conf 中添加 crush_location 选项来设置 OSD 的 CRUSH 位置,例如
crush_location = root=default row=a rack=a2 chassis=a2a host=a2a1
添加此选项后,每次 OSD 启动时,它都会验证自己在 CRUSH 映射中的位置是否正确,如果不正确则自行移动。要禁用此自动 CRUSH 映射管理,请在 ceph.conf 配置文件的 [osd] 部分添加以下内容
osd_crush_update_on_start = false
请注意,在大多数情况下,此操作是不必要的。
如果未明确设置 crush_location,则对于 OSD,默认使用 root=default host=HOSTNAME,其中主机名由 hostname -s 命令的输出确定。
注意
如果您从默认设置切换到显式设置的 crush_location,请不要忘记包含 root=default,因为现有的 CRUSH 规则引用了它。
自定义位置挂钩
自定义位置挂钩可用于在启动时生成更完整的 CRUSH 位置。
当在编写 ceph.conf 时某些位置字段未知(例如,在多个数据中心部署单个配置时的字段 rack 或 datacenter)时,这很有用。
如果配置、执行和解析成功,挂钩的输出将替换任何先前设置的 CRUSH 位置。
可以通过提供可执行文件(通常是脚本)的路径来在中央配置存储或旧版 ceph.conf 中启用挂钩,例如
crush_location_hook = /path/to/customized-ceph-crush-location
此挂钩会传递几个参数(见下文)。挂钩将包含 CRUSH 位置描述的单行输出到 stdout。参数类似于以下内容:
--id ID --type TYPE
这里的 id 是守护程序标识符或(对于 OSD)OSD 编号,守护程序类型是 osd、mds、mgr 或 mon。
例如,一个简单的挂钩,通过文件 /etc/rack 中的值指定机架位置(假设它不包含空格),可能如下所示
#!/bin/sh
echo "root=default rack=$(cat /etc/rack) host=$(hostname -s)"
CRUSH 结构
CRUSH 映射由 (1) 描述集群物理拓扑的层次结构和 (2) 定义数据放置策略的一组规则组成。层次结构具有叶子处的设备 (OSD) 和对应于其他物理特征或分组的内部节点:主机、机架、行、数据中心等。规则确定如何根据该层次结构放置副本(例如,“三个副本位于不同的机架中”)。
设备
设备是存储数据的单个 OSD(通常每个存储驱动器一个设备)。设备由 id(一个非负整数)和 name(通常是 osd.N,其中 N 是设备的 id)标识。
在 Luminous 及更高版本中,OSD 可以分配一个 *设备类*(例如,hdd 或 ssd 或 nvme),允许 CRUSH 规则以它们为目标。当在主机内混合设备类型时,设备类特别有用。
类型和桶
“桶”(Bucket),在 CRUSH 的上下文中,是层次结构中任何内部节点的术语:主机、机架、行等。CRUSH 映射定义了一系列用于标识这些节点的 *类型*。默认类型包括
osd(或device)hostchassisrackrowpdupodroomdatacenterzoneregionroot
大多数集群只使用其中少数几种类型,可以根据需要定义其他类型。
层次结构由叶子处的设备(通常是 osd 类型)和非设备类型作为内部节点构建。根节点是 root 类型。例如
层次结构中的每个节点(设备或桶)都有一个 *权重*,指示应由该设备或层次结构子树存储的总数据相对比例。权重在叶子处设置,指示设备的大小。这些权重会自动以“向上树”方向求和:即,root 节点的权重将是其下所有设备权重的总和。权重通常以 tebibytes (TiB) 为单位测量。
要获取集群 CRUSH 层次结构的简单视图,包括权重,请运行以下命令
ceph osd tree
规则
CRUSH 规则定义了管理数据如何分发到层次结构中的设备的策略。规则定义了放置以及复制策略或分发策略,允许您精确指定 CRUSH 如何放置数据副本。例如,您可以创建一条规则来选择一对目标进行双向镜像,另一条规则用于在两个不同数据中心中选择三个目标进行三向复制,还有另一条规则用于跨六个存储设备进行纠删码。有关 CRUSH 规则的详细讨论,请参阅 CRUSH - Controlled, Scalable, Decentralized Placement of Replicated Data 的 第 3.2 节。
CRUSH 规则可以通过命令行创建,通过指定它们将管理的 *池类型*(复制或纠删码)、*故障域*,以及可选的 *设备类*。在极少数情况下,必须通过手动编辑 CRUSH 映射来创建 CRUSH 规则。
要查看为集群定义的规则,请运行以下命令
ceph osd crush rule ls
要查看规则的内容,请运行以下命令
ceph osd crush rule dump
设备类
每个设备都可以选择分配一个 *类*。默认情况下,OSD 会在启动时根据它们所支持的设备类型自动将其类设置为 hdd、ssd 或 nvme。
要显式设置一个或多个 OSD 的设备类,请运行以下形式的命令
ceph osd crush set-device-class <class> <osd-name> [...]
设置设备类后,在取消设置旧类之前,不能将其更改为另一个类。要删除一个或多个 OSD 的旧类,请运行以下形式的命令
ceph osd crush rm-device-class <osd-name> [...]
此限制允许管理员设置设备类,而不会在 OSD 重新启动或脚本运行时更改。
要创建针对特定设备类的放置规则,请运行以下形式的命令
ceph osd crush rule create-replicated <rule-name> <root> <failure-domain> <class>
要将新放置规则应用于特定池,请运行以下形式的命令
ceph osd pool set <pool-name> crush_rule <rule-name>
设备类通过创建(一个或多个)“影子”CRUSH 层次结构来实现。对于每个使用的设备类,都会有一个影子层次结构,其中只包含该类的设备。然后,CRUSH 规则可以跨相关的影子层次结构分发数据。此方法与旧版 Ceph 客户端完全向后兼容。要查看显示影子项的 CRUSH 层次结构,请运行以下命令
ceph osd crush tree --show-shadow
一些在 Luminous 版本之前创建的旧集群依赖于手动制作的 CRUSH 映射来维护按设备类型划分的层次结构。对于这些集群,可以使用 *reclassify* 工具帮助它们过渡到设备类,而不会触发不需要的数据移动(请参阅 从旧版 SSD 规则迁移到设备类)。
权重集
*权重集* 是用于计算数据放置的备用权重集。CRUSH 映射中与每个设备关联的正常权重是根据设备大小设置的,并指示应该存储多少数据。然而,由于 CRUSH 是一个概率性的伪随机放置过程,因此总会与这种理想分布存在一些偏差(就像掷骰子六十次不太可能正好得到十个一和十个六一样)。权重集允许集群根据集群的特定情况(例如:层次结构、池)执行数值优化,以实现平衡分布。
Ceph 支持两种类型的权重集
一个 compat 权重集是集群中每个设备和每个节点的单个备用权重集。不能指望 compat 权重集纠正所有异常(例如,不同池的 PG 可能大小不同,负载水平也不同,但平衡器大多将它们视为相似)。然而,它们的主要优点是与以前版本的 Ceph *向后兼容*。这意味着即使权重集最初是在 Luminous v12.2.z 中引入的,旧客户端(例如 Firefly)仍可以在使用 compat 权重集平衡数据时连接到集群。
一个 per-pool 权重集更灵活,因为它允许针对每个数据池优化放置。此外,可以针对放置的每个位置调整权重,允许优化器纠正数据向与其对等设备相比权重较小的设备微妙倾斜的问题(这种效应通常只在非常大的集群中才明显,但可能导致平衡问题)。
使用权重集时,层次结构中与每个节点关联的权重在以下命令的输出中显示在单独的列中(标记为 (compat) 或池名称)
ceph osd tree
如果同时使用 *compat* 和 *per-pool* 权重集,特定池的数据放置将使用其自己的 per-pool 权重集(如果存在)。如果仅使用 *compat* 权重集,数据放置将使用 compat 权重集。如果两者都不使用,数据放置将使用正常的 CRUSH 权重。
虽然权重集可以手动设置和调整,但如果集群运行的是 Luminous 或更高版本,我们建议启用 ceph-mgr *balancer* 模块来自动执行这些任务。
修改 CRUSH 映射
添加/移动 OSD
注意
在正常情况下,OSD 在创建时会自动将自己添加到 CRUSH 映射中。本节中的命令很少需要。
要在正在运行的集群的 CRUSH 映射中添加或移动 OSD,请运行以下形式的命令
ceph osd crush set {name} {weight} root={root} [{bucket-type}={bucket-name} ...]
有关此命令参数的详细信息,请参阅以下内容
name- 描述:
OSD 的全名。
- 类型:
String
- 必需:
是
- 示例:
osd.0
weight- 描述:
OSD 的 CRUSH 权重。通常,它是以太字节 (TB) 测量的其大小。
- 类型:
Double
- 必需:
是
- 示例:
2.0
root- 描述:
OSD 所在的 CRUSH 层次结构的根节点(通常为
default)。- 类型:
键值对。
- 必需:
是
- 示例:
root=default
bucket-type- 描述:
OSD 在 CRUSH 层次结构中的位置。
- 类型:
键值对。
- 必需:
否
- 示例:
datacenter=dc1 room=room1 row=foo rack=bar host=foo-bar-1
在以下示例中,该命令将 osd.0 添加到层次结构中,或者将 osd.0 从以前的位置移动
ceph osd crush set osd.0 1.0 root=default datacenter=dc1 room=room1 row=foo rack=bar host=foo-bar-1
调整 OSD 权重
注意
在正常情况下,OSD 在创建时会自动以正确的权重将自己添加到 CRUSH 映射中。本节中的命令很少需要。
要在正在运行的集群中调整 OSD 的 CRUSH 权重,请运行以下形式的命令
ceph osd crush reweight {name} {weight}
有关此命令参数的详细信息,请参阅以下内容
name- 描述:
OSD 的全名。
- 类型:
String
- 必需:
是
- 示例:
osd.0
weight- 描述:
OSD 的 CRUSH 权重。
- 类型:
Double
- 必需:
是
- 示例:
2.0
删除 OSD
注意
OSD 通常是通过 ceph osd purge` 命令从 CRUSH 映射中删除的。此命令很少需要。
要在正在运行的集群的 CRUSH 映射中删除 OSD,请运行以下形式的命令
ceph osd crush remove {name}
有关 name 参数的详细信息,请参阅以下内容
name- 描述:
OSD 的全名。
- 类型:
String
- 必需:
是
- 示例:
osd.0
添加 CRUSH 桶
注意
当添加 OSD 且创建它的命令指定 {bucket-type}={bucket-name} 作为 OSD 位置的一部分时(前提是不存在同名的桶),桶会被隐式创建。本节中的命令通常用于在 OSD 已创建后手动调整层次结构。此命令的一种用途是将一系列主机移动到新的机架级别桶。此命令的另一种用途是将新的 host 桶(OSD 节点)添加到虚拟 root 中,以便在它们准备好接收数据之前不会接收任何数据。当它们准备好时,将桶移动到 default 根或如下所述的任何其他根。
要在正在运行的集群的 CRUSH 映射中添加桶,请运行以下形式的命令
ceph osd crush add-bucket {bucket-name} {bucket-type}
有关此命令参数的详细信息,请参阅以下内容
bucket-name- 描述:
桶的全名。
- 类型:
String
- 必需:
是
- 示例:
rack12
bucket-type- 描述:
桶的类型。此类型必须已存在于 CRUSH 层次结构中。
- 类型:
String
- 必需:
是
- 示例:
rack
在以下示例中,该命令将 rack12 桶添加到层次结构中
ceph osd crush add-bucket rack12 rack
移动桶
要将桶移动到 CRUSH 映射层次结构中的不同位置或位置,请运行以下形式的命令
ceph osd crush move {bucket-name} {bucket-type}={bucket-name}, [...]
有关此命令参数的详细信息,请参阅以下内容
bucket-name- 描述:
您正在移动的桶的名称。
- 类型:
String
- 必需:
是
- 示例:
foo-bar-1
bucket-type- 描述:
桶在 CRUSH 层次结构中的新位置。
- 类型:
键值对。
- 必需:
否
- 示例:
datacenter=dc1 room=room1 row=foo rack=bar host=foo-bar-1
重命名桶
要重命名桶同时保持其在 CRUSH 映射层次结构中的位置,请运行以下形式的命令
ceph osd crush rename-bucket {oldname} {newname}
删除桶
要从 CRUSH 层次结构中删除桶,请运行以下形式的命令
ceph osd crush remove {bucket-name}
注意
桶必须已为空才能从 CRUSH 层次结构中删除。换句话说,其中不得有 OSD 或任何其他 CRUSH 桶。
有关 bucket-name 参数的详细信息,请参阅以下内容
bucket-name- 描述:
正在删除的桶的名称。
- 类型:
String
- 必需:
是
- 示例:
rack12
在以下示例中,该命令从层次结构中删除 rack12 桶
ceph osd crush remove rack12
创建 compat 权重集
注意
通常,如果需要,此操作由 balancer 模块自动完成(前提是该模块已启用)。
要创建 *compat* 权重集,请运行以下命令
ceph osd crush weight-set create-compat
要调整 compat 权重集的权重,请运行以下形式的命令
ceph osd crush weight-set reweight-compat {name} {weight}
要销毁 compat 权重集,请运行以下命令
ceph osd crush weight-set rm-compat
创建 per-pool 权重集
要为特定池创建权重集,请运行以下形式的命令
ceph osd crush weight-set create {pool-name} {mode}
注意
Per-pool 权重集仅在所有服务器和守护程序都运行 Luminous v12.2.z 或更高版本时才能使用。
有关此命令参数的详细信息,请参阅以下内容
pool-name- 描述:
RADOS 池的名称。
- 类型:
String
- 必需:
是
- 示例:
rbd
mode- 描述:
可以是
flat或positional。*flat* 权重集为所有设备或桶分配一个权重。*positional* 权重集对于生成的放置映射中的每个位置具有潜在不同的权重。例如:如果池的副本数为3,则 positional 权重集将为每个设备和桶提供三个权重。- 类型:
String
- 必需:
是
- 示例:
flat
要调整权重集中某个项的权重,请运行以下形式的命令
ceph osd crush weight-set reweight {pool-name} {item-name} {weight [...]}
要列出现有权重集,请运行以下命令
ceph osd crush weight-set ls
要删除权重集,请运行以下形式的命令
ceph osd crush weight-set rm {pool-name}
为复制池创建规则
为复制池创建 CRUSH 规则时,需要做出一个重要决定:选择故障域。例如,如果您选择 host 作为故障域,则 CRUSH 将确保数据的每个副本都存储在唯一的主机上。或者,如果您选择 rack 作为故障域,则数据的每个副本将存储在不同的机架中。您选择的故障域应根据大小及其 CRUSH 拓扑来指导。
整个集群层次结构通常嵌套在名为 default 的根节点下。如果您自定义了层次结构,您可能希望在层次结构中的某个其他节点下创建规则。在为自定义层次结构创建此规则时,节点类型并不重要,特别是规则不必嵌套在 root 节点下。
可以创建一条规则,将数据放置限制为特定 *类* 的设备。默认情况下,Ceph OSD 会根据所使用的底层设备类型自动将自己分类为 hdd 或 ssd。这些设备类可以自定义。可以将 OSD 的 device class 设置为 nvme 以将其与 SATA SSD 区分开来,或者将其设置为任意内容,如 ssd-testing 或 ssd-ethel,以便可以根据特定要求灵活地将规则和池约束为使用(或避免使用)特定的 OSD 子集。
要为复制池创建规则,请运行以下形式的命令
ceph osd crush rule create-replicated {name} {root} {failure-domain-type} [{class}]
有关此命令参数的详细信息,请参阅以下内容
name- 描述:
规则的名称。
- 类型:
String
- 必需:
是
- 示例:
rbd-rule
root- 描述:
数据将放置在其中的 CRUSH 层次结构节点的名称。
- 类型:
String
- 必需:
是
- 示例:
default
failure-domain-type- 描述:
用于故障域副本的 CRUSH 节点类型。
- 类型:
String
- 必需:
是
- 示例:
rack
class- 描述:
数据将放置在其中的设备类。
- 类型:
String
- 必需:
否
- 示例:
ssd
为纠删码池创建规则
对于纠删码池,需要做出类似的决策:故障域是什么,数据将放置在层次结构中的哪个节点下(通常为 default),以及放置是否限于特定设备类。然而,纠删码池的创建方式不同:需要参考正在使用的纠删码插件仔细构建它们。因此,这些决策必须纳入到 erasure-code profile 中。然后,将从 erasure-code profile 创建 CRUSH 规则,无论是在创建新池时还是为现有池创建新规则时显式或自动创建。
要列出 erasure-code profile,请运行以下命令
ceph osd erasure-code-profile ls
要查看特定的现有配置文件,请运行以下形式的命令
ceph osd erasure-code-profile get {profile-name}
在正常情况下,不应修改配置文件;相反,应创建新配置文件,并在创建新池或现有池的新规则时使用。
erasure-code profile 由一组键值对组成。其中大多数键值对控制编码池中数据的纠删码的行为。然而,以 crush- 开头的键值对控制创建的 CRUSH 规则。
相关的 erasure-code profile 属性如下
crush-root:数据放置在其中的 CRUSH 节点名称 [默认值:
default]。crush-failure-domain:用于分发纠删码分片的 CRUSH 桶类型 [默认值:
host]。crush-osds-per-failure-domain:每个故障域中放置的 OSD 最大数量——默认为 1。使用大于 1 的值将导致创建 CRUSH MSR 规则,见下文。如果指定了
crush-num-failure-domains,则必须指定此项。crush-num-failure-domains:要映射的故障域数量。如果指定了
crush-osds-per-failure-domain,则必须指定此项。导致创建 CRUSH MSR 规则。crush-device-class:数据放置在其中的设备类 [默认值:无,这意味着使用所有设备]。
k 和 m(以及对于
lrc插件,l):这些确定纠删码分片的数量,影响生成的 CRUSH 规则。定义配置文件后,可以通过运行以下形式的命令创建 CRUSH 规则
ceph osd crush rule create-erasure {name} {profile-name}
CRUSH MSR 规则
使用大于 1 的 crush-osds-per-failure-domain 值创建 erasure-code profile 将导致创建 CRUSH MSR 规则类型,而不是正常的 CRUSH 规则。正常的 crush 规则在遇到 out OSD 时无法重试先前的步骤,并依赖 CHOOSELEAF 步骤来允许将 OSD 移动到新主机。然而,CHOOSELEAF 规则不支持每个故障域有多个 OSD。MSR 规则(Squid 中新增)通过在遇到 out OSD 时重试所有先前步骤来支持每个故障域有多个 OSD。使用 MSR 规则要求 OSD 和客户端支持 CRUSH_MSR 功能位(Squid 或更高版本)。
删除规则
要删除未被池使用的规则,请运行以下形式的命令
ceph osd crush rule rm {rule-name}
可调参数
用于计算数据放置的 CRUSH 算法随着时间的推移不断改进。为了支持行为更改,我们为用户提供了一组可调参数,用于确定使用哪个旧版或优化版 CRUSH。
为了使用较新的可调参数,所有 Ceph 客户端和守护程序都必须支持 CRUSH 的新主要版本。由于此要求,我们创建了以引入它们的 Ceph 版本命名的 profiles。例如,firefly 可调参数首先由 Firefly 版本支持,不适用于旧客户端(例如,运行 Dumpling 的客户端)。将集群的可调参数配置文件从旧版集更改为较新或 optimal 集后,ceph-mon 和 ceph-osd 选项将阻止不支持新 CRUSH 功能的旧客户端连接到集群。
argonaut (legacy)
Argonaut 和更旧版本使用的旧 CRUSH 行为对于大多数集群来说工作正常,前提是没有很多 OSD 被标记为 out。
bobtail (CRUSH_TUNABLES2)
bobtail 可调参数配置文件提供了以下改进
对于叶子桶中设备数量较少的层次结构,一些 PG 可能会映射到少于所需数量的副本,导致
undersizedPG。已知这发生在每个主机下嵌套少量 OSD(1 到 3 个)的host节点层次结构中。对于大型集群,一小部分 PG 可能会映射到少于所需数量的 OSD。已知这发生在使用了多个层次结构层(例如,
row、rack、host、osd)的情况下。当一个或多个 OSD 被标记为
out时,数据倾向于重新分发到附近的 OSD,而不是分布在整个层次结构中。
Bobtail 版本中引入的可调参数如下
choose_local_tries:本地重试次数。旧版值为2,最佳值为0。
choose_local_fallback_tries:旧版值为5,最佳值为 0。
choose_total_tries:选择项目的总尝试次数。旧版值为19,但随后的测试表明,50的值更适合典型集群。对于超大型集群,可能需要更大的值。
chooseleaf_descend_once:递归chooseleaf尝试是否会重试,或者只尝试一次并允许原始放置重试。旧版默认值为0,最佳值为1。
迁移影响
从
argonaut可调参数移动到bobtail可调参数会触发适量的数据移动。在已经填充数据的集群上要小心使用。
firefly (CRUSH_TUNABLES3)
chooseleaf_vary_r
此 firefly 可调参数配置文件修复了 chooseleaf CRUSH 步骤行为中的问题。当大部分 OSD 被标记为 out 时,就会出现此问题,导致 PG 映射的 OSD 过少。
此配置文件是在 Firefly 版本中引入的,并添加了一个新的可调参数如下
chooseleaf_vary_r:递归 chooseleaf 尝试是否会以非零r值开始,该值由父级已进行的尝试次数决定。旧版默认值为0,但使用此值时 CRUSH 有时无法找到映射。最佳值(就计算成本和正确性而言)为1。
迁移影响
对于存储大量数据的现有集群,将此可调参数从
0更改为1将触发大量数据迁移;值4或5将允许 CRUSH 仍然找到有效的映射,并且会导致较少的数据移动。
straw_calc_version tunable
CRUSH 映射中为 straw 算法桶计算和存储的内部权重存在问题。当桶的 CRUSH 权重为 0 或混合了不同且唯一的权重时,CRUSH 会错误地分发数据(即,不成比例地分发给权重)。
此可调参数是在 Firefly 版本中引入的,如下所示
straw_calc_version:值为0可保留旧的、有缺陷的内部权重计算;值为1可修复此问题。
迁移影响
如果集群符合其中一个问题条件,将此可调参数更改为
1,然后调整 straw 桶(通过添加、删除或重新加权项目,或使用 reweight-all 命令)可能会触发少量到适量的数据移动。
此可调选项值得注意,因为它对客户端所需的内核版本绝对没有影响。
hammer (CRUSH_V4)
hammer 可调参数配置文件不会仅仅通过更改配置文件来影响现有 CRUSH 映射的映射。然而
支持一种新的桶算法:
straw2。这种新算法修复了原始straw中的几个限制。更具体地说,旧的straw桶在调整权重时会更改一些不应更改的映射,而straw2实现了仅更改权重已更改的桶项目的映射的原始目标。
straw2类型是任何新创建的桶的默认类型。
迁移影响
将桶类型从
straw更改为straw2将触发少量数据移动,具体取决于桶项目权重的相互差异程度。当权重都相同时,不会移动数据,权重差异越大,移动越多。
jewel (CRUSH_TUNABLES5)
jewel 可调参数配置文件改进了 CRUSH 的整体行为。结果是,当 OSD 被标记为 out 时,更改的映射明显减少。这种改进显着减少了数据移动。
Jewel 版本中引入的新可调参数如下
chooseleaf_stable:确定递归 chooseleaf 尝试是否使用内循环的更好值,从而在 OSD 被标记为out时大大减少映射更改次数。旧版值为0,新值1使用新方法。
迁移影响
在现有集群上更改此值将导致非常大量的数据移动,因为几乎每个 PG 映射都可能更改。
支持 CRUSH_TUNABLES2 的客户端版本
v0.55 及更高版本,包括 Bobtail (v0.56.x)
Linux 内核版本 v3.9 及更高版本(对于 CephFS 和 RBD 内核客户端)
支持 CRUSH_TUNABLES3 的客户端版本
v0.78 (Firefly) 及更高版本
Linux 内核版本 v3.15 及更高版本(对于 CephFS 和 RBD 内核客户端)
支持 CRUSH_V4 的客户端版本
v0.94 (Hammer) 及更高版本
Linux 内核版本 v4.1 及更高版本(对于 CephFS 和 RBD 内核客户端)
支持 CRUSH_TUNABLES5 的客户端版本
v10.0.2 (Jewel) 及更高版本
Linux 内核版本 v4.5 及更高版本(对于 CephFS 和 RBD 内核客户端)
“非最佳可调参数”警告
在 v0.74 及更高版本中,如果任何当前 CRUSH 可调参数具有非最佳值,Ceph 将发出健康检查警告(“HEALTH_WARN crush map has non-optimal tunables”):即,如果任何值未能具有 :ref:` default 配置文件 <rados_operations_crush_map_default_profile_definition>` 中的最佳值。有两种不同的方法可以消除警报
调整现有集群上的 CRUSH 可调参数以使其最佳。进行此调整将触发一些数据移动(可能高达 10%)。通常首选此方法而不是另一种方法,但在数据移动可能影响性能的情况下必须特别小心:例如,在生产集群中。要启用最佳可调参数,请运行以下命令
ceph osd crush tunables optimal有几个潜在问题可能使得恢复到可调参数的先前值更可取。新值可能会为集群带来过多的负载,新值可能会导致集群操作不可接受地变慢,或者可能存在客户端兼容性问题。此类客户端兼容性问题在使用旧内核 CephFS 或 RBD 客户端或 pre-Bobtail
librados客户端时可能出现。要恢复到可调参数的先前值,请运行以下命令ceph osd crush tunables legacy要消除警报而不对 CRUSH 进行任何更改,请在 ceph.conf 文件中的
[mon]部分添加以下选项mon_warn_on_legacy_crush_tunables = false
为了使此更改生效,您需要重新启动监视器或运行以下命令以在监视器仍在运行时将选项应用于它们
ceph tell mon.\* config set mon_warn_on_legacy_crush_tunables false
调整 CRUSH
在调整 CRUSH 可调参数时,请记住以下注意事项
调整 CRUSH 可调参数的值将导致一个或多个 PG 从一个存储节点转移到另一个存储节点。如果 Ceph 集群已经存储了大量数据,请准备好应对大量数据移动。
当
ceph-osd和ceph-mon守护程序获取更新的映射时,它们会立即开始拒绝来自不支持新功能的客户端的新连接。然而,已连接的客户端实际上是祖父级的,任何不支持新功能的客户端都会发生故障。如果 CRUSH 可调参数设置为较新(非旧版)值,随后又恢复为旧版值,则不需要
ceph-osd守护程序支持与较新(非旧版)值相关的任何较新 CRUSH 功能。然而,OSD 对等过程需要检查和理解旧映射。因此,**如果集群以前使用过非旧版 CRUSH 值,则不要运行旧版本的**ceph-osd**守护程序**——即使最新版本的映射已恢复为使用旧版默认值。
调整 CRUSH 可调参数的最简单方法是以称为 *profiles* 的匹配集应用它们。截至 Octopus 版本,Ceph 支持以下配置文件
legacy:来自 Argonaut 及更早版本的旧版行为。
argonaut:Argonaut 版本支持的旧版值。
bobtail:Bobtail 版本支持的值。
firefly:Firefly 版本支持的值。
hammer:Hammer 版本支持的值。
jewel:Jewel 版本支持的值。
optimal:当前 Ceph 版本的最佳值。.. _rados_operations_crush_map_default_profile_definition
default:从头开始安装的新集群的默认值。这些值取决于当前的 Ceph 版本,是硬编码的,通常是最佳值和旧版值的混合。这些值通常对应于上一个 LTS(长期服务)版本或大多数用户预计拥有最新客户端的最新版本的optimal配置文件。
要将配置文件应用于正在运行的集群,请运行以下形式的命令
ceph osd crush tunables {PROFILE}
此操作可能会触发大量数据移动。在更改正在运行的集群上的配置文件之前,请查阅发行说明和文档。考虑限制恢复和回填参数,以限制由特定更改导致的回填。
调整主 OSD 选择
当 Ceph 客户端读取或写入数据时,它首先联系每个受影响 PG 的 acting set 中的主 OSD。默认情况下,acting set 中的第一个 OSD 是主 OSD(也称为“lead OSD”)。例如,在 acting set [2, 3, 4] 中,osd.2 列在首位,因此是主 OSD。然而,有时很明显 OSD 不适合充当主 OSD(例如,如果 OSD 驱动器慢或控制器慢)。为了防止性能瓶颈(尤其是在读取操作上),同时最大化硬件利用率,您可以通过调整“primary affinity”值,或者通过制作一个 CRUSH 规则来选择更适合充当主 OSD 的 OSD,而不是其他 OSD,来影响主 OSD 的选择。
要确定调整 Ceph 对主 OSD 的选择是否会提高集群性能,必须考虑池冗余策略。对于复制池,这种调整特别有用,因为默认情况下,读取操作由每个 PG 的主 OSD 提供服务。然而,对于纠删码池,可以通过启用 **fast read** 来提高读取操作的速度(请参阅 Pool settings)。
Primary Affinity
**Primary affinity** 是 OSD 的一个特征,它控制给定 OSD 在给定 acting set 中被选为主要 OSD(或“lead OSD”)的可能性。Primary affinity 值可以是 0 到 1(含)范围内的任何实数。
作为调整 primary affinity 值有用的常见场景示例,让我们假设一个集群包含混合的驱动器大小:例如,假设它包含一些带有 1.9 TB SATA SSD 的旧机架和一些带有 3.84 TB SATA SSD 的新机架。后者平均将被分配两倍的 PG 数量,因此将提供两倍的写入和读取操作——它们将比前者更繁忙。在这种情况下,您可以将 primary affinity 大致分配为与 OSD 大小成反比。这样的分配不会是 100% 最佳的,但通过更均匀地利用 SATA 接口带宽和 CPU 周期,可以轻松实现整体读取吞吐量 15% 的改进。这个例子不仅仅是为了说明调整 primary affinity 值的理论好处而进行的思想实验;这个百分之十五的改进是在实际的 Ceph 集群上实现的。
默认情况下,每个 Ceph OSD 的 primary affinity 值为 1。在每个 OSD 都具有此默认值的集群中,所有 OSD 都同样有可能充当主 OSD。
通过降低 Ceph OSD 的 primary affinity 值,您使 CRUSH 选择 OSD 作为 PG acting set 中的主 OSD的可能性降低。要更改与特定 OSD primary affinity 相关的权重值,请运行以下形式的命令
ceph osd primary-affinity <osd-id> <weight>
OSD 的 primary affinity 可以设置为 [0-1](含)范围内的任何实数,其中 0 表示 OSD 不得用作主 OSD,1 表示 OSD 作为主 OSD的可能性最大。当权重介于这些极端之间时,其值大致表示 CRUSH 选择与之关联的 OSD 作为主 OSD的可能性。
CRUSH 选择 lead OSD 的过程不仅仅是取决于相对 affinity 值确定的简单概率函数。尽管如此,即使对理想 primary affinity 值进行一阶近似,也可以实现可衡量的结果。
自定义 CRUSH 规则
一些集群通过在同一个复制池中混合 SSD 和 HDD 来平衡成本和性能。通过将 HDD OSD 的 primary affinity 设置为 0,操作将被导向到每个 acting set 中的 SSD OSD。或者,您可以定义一个 CRUSH 规则,该规则始终选择 SSD OSD 作为主 OSD,然后选择 HDD 作为其余 OSD。给定此规则,每个 PG 的 acting set 将包含一个 SSD OSD 作为主 OSD,并且其余 OSD 位于 HDD 上。
例如,请参阅以下 CRUSH 规则
rule mixed_replicated_rule {
id 11
type replicated
step take default class ssd
step chooseleaf firstn 1 type host
step emit
step take default class hdd
step chooseleaf firstn 0 type host
step emit
}
此规则选择 SSD 作为第一个 OSD。对于 N 次复制池,此规则选择 N+1 个 OSD,以保证 N 个副本位于不同的主机上,因为第一个 SSD OSD 可能与任何 N 个 HDD OSD 位于同一位置。
为了避免这种额外的存储要求,您可以将 SSD 和 HDD 放置在不同的主机中。然而,采用这种方法意味着所有客户端请求都将由带有 SSD 的主机接收。因此,建议为 SSD OSD 配备更快的 CPU,为 HDD OSD 配备更适度的 CPU,因为后者在正常情况下只执行恢复操作。在这里,CRUSH 根 ssd_hosts 和 hdd_hosts 严格要求不包含任何相同的服务器,如下所示的 CRUSH 规则所示
rule mixed_replicated_rule_two {
id 1
type replicated
step take ssd_hosts class ssd
step chooseleaf firstn 1 type host
step emit
step take hdd_hosts class hdd
step chooseleaf firstn -1 type host
step emit
}
注意
如果主 SSD OSD 发生故障,则对关联 PG 的请求将暂时由较慢的 HDD OSD 提供服务,直到 PG 的数据已复制到替换的主 SSD OSD 上。