17 存储的数据管理 #
CRUSH 算法通过计算数据存储位置来确定如何存储和检索数据。使用 CRUSH,Ceph 客户端无需通过中心服务器或中介程序,即可直接与 OSD 通讯。借助算法确定的数据存储和检索方法,Ceph 可避免单一故障点、性能瓶颈和可伸缩性物理限制。
CRUSH 需要获取集群的索引,它使用 CRUSH 索引以伪随机的方式在 OSD 中存储和检索数据,并以一致的方式在整个集群中分布数据。
CRUSH 索引包含一个 OSD 列表、一个用于将设备聚合到物理位置的“存储桶”列表,以及一个告知 CRUSH 应如何复制 Ceph 集群存储池中数据的规则列表。通过反映安装的底层物理组织,CRUSH 可对相关设备故障的潜在根源建模,从而解决故障的根源。典型的根源包括物理接近、共用电源和共用网络。通过将这些信息编码到集群索引中,CRUSH 归置策略可将对象副本分隔在不同的故障域中,同时维持所需的分布方式。例如,为了消除可能的并发故障,可能需要确保数据副本位于使用不同机架、机柜、电源、控制器和/或物理位置的设备上。
部署 Ceph 集群后,将会生成默认的 CRUSH 索引。这种模式适合 Ceph 沙箱环境。但是,在部署大规模的数据集群时,强烈建议您考虑创建自定义 CRUSH 索引,因为这样做有助于管理 Ceph 集群、提高性能并确保数据安全。
例如,如果某个 OSD 停机,而您需要使用现场支持或更换硬件,则 CRUSH 索引可帮助您定位到发生 OSD 故障的主机所在的物理数据中心、机房、设备排和机柜。
同样,CRUSH 可以帮助您更快地确定故障。例如,如果特定机柜中的所有 OSD 同时停机,故障可能是由某个网络交换机或者机柜或网络交换机的电源所致,而不是发生在 OSD 自身上。
当与故障主机关联的归置组(请参见第 17.4 节 “归置组”)处于降级状态时,自定义 CRUSH 索引还可帮助您确定 Ceph 存储数据冗余副本的物理位置。
CRUSH 索引包括三个主要部分。
17.1 OSD 设备 #
为了将归置组映射到 OSD,CRUSH 索引需要 OSD 设备(OSD 守护进程的名称)的列表。设备列表显示在 CRUSH 索引的最前面。
#devices device NUM osd.OSD_NAME class CLASS_NAME
例如:
#devices device 0 osd.0 class hdd device 1 osd.1 class ssd device 2 osd.2 class nvme device 3 osd.3 class ssd
一般而言,一个 OSD 守护进程映射到一个磁盘。
17.1.1 设备类型 #
Ceph 的优势之一是 CRUSH 索引能够灵活控制数据归置。这也是集群最难管理的环节之一。设备类型会自动对 CRUSH 索引执行最常见的更改,以前这些更改都需要由管理员手动完成。
17.1.1.1 CRUSH 管理问题 #
Ceph 集群常由多种存储设备构建而成:HDD、SSD、NVMe,甚至是以上这些类型的混合。我们将这些不同的存储设备类型称为设备类型,以避免与 CRUSH 桶的类型属性(例如 host、rack 和 row,请参见第 17.2 节 “存储桶”了解更多详细信息)产生混淆。受 SSD 支持的 Ceph OSD 比受旋转磁盘支持的 OSD 速度快得多,因此更适合特定工作负载。借助 Ceph,您可轻松为不同数据集或工作负载创建 RADOS 存储池,以及指定不同的 CRUSH 规则来控制这些存储池的数据归置。
不过,通过设置 CRUSH 规则将数据仅归置到特定类型的设备这个过程十分枯燥。规则是针对 CRUSH 层次结构运作的,但如果将某些设备混合到同一主机或机柜中(如上面的层次结构示例所示),则这些设备默认会混合在一起并显示在层次结构的同一子树中。要手动将它们分隔到单独的树中,需要针对先前版本的 SUSE Enterprise Storage 中的每个设备类型,为每个中间节点创建多个版本。
17.1.1.2 设备类型 #
Ceph 提供了一个较佳的解决方案,就是为每个 OSD 添加一个名为设备类型的属性。默认情况下,OSD 会根据 Linux 内核所公开的硬件属性,自动将自己的设备类型设置为“hdd”、“ssd”或“nvme”。ceph osd tree
命令输出的新列中会报告这些设备类型:
cephuser@adm >
ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 83.17899 root default
-4 23.86200 host cpach
2 hdd 1.81898 osd.2 up 1.00000 1.00000
3 hdd 1.81898 osd.3 up 1.00000 1.00000
4 hdd 1.81898 osd.4 up 1.00000 1.00000
5 hdd 1.81898 osd.5 up 1.00000 1.00000
6 hdd 1.81898 osd.6 up 1.00000 1.00000
7 hdd 1.81898 osd.7 up 1.00000 1.00000
8 hdd 1.81898 osd.8 up 1.00000 1.00000
15 hdd 1.81898 osd.15 up 1.00000 1.00000
10 nvme 0.93100 osd.10 up 1.00000 1.00000
0 ssd 0.93100 osd.0 up 1.00000 1.00000
9 ssd 0.93100 osd.9 up 1.00000 1.00000
如果设备类型自动检测失败(例如由于未通过 /sys/block
正确向设备驱动程序公开设备的相关信息而导致失败),您可以使用命令行调整设备类型:
cephuser@adm >
ceph osd crush rm-device-class osd.2 osd.3 done removing class of osd(s): 2,3cephuser@adm >
ceph osd crush set-device-class ssd osd.2 osd.3 set osd(s) 2,3 to class 'ssd'
17.1.1.3 设置 CRUSH 归置规则 #
CRUSH 规则可限制对特定设备类型执行归置操作。例如,您可以通过运行以下命令来创建仅将数据分布在 SSD 磁盘上的“fast”副本存储池:
cephuser@adm >
ceph osd crush rule create-replicated RULE_NAME ROOT FAILURE_DOMAIN_TYPE DEVICE_CLASS
例如:
cephuser@adm >
ceph osd crush rule create-replicated fast default host ssd
创建名为“fast_pool”的存储池并将其分配给“fast”规则:
cephuser@adm >
ceph osd pool create fast_pool 128 128 replicated fast
创建纠删码规则的过程略有不同。首先,创建包含所需设备类型对应属性的纠删码配置。然后,在创建纠删码存储池时使用该配置:
cephuser@adm >
ceph osd erasure-code-profile set myprofile \ k=4 m=2 crush-device-class=ssd crush-failure-domain=hostcephuser@adm >
ceph osd pool create mypool 64 erasure myprofile
为应对您需要手动编辑 CRUSH 索引来自定义规则的情况,该语法已经过扩展,允许指定设备类型。例如,上述命令生成的 CRUSH 规则如下所示:
rule ecpool {
id 2
type erasure
min_size 3
max_size 6
step set_chooseleaf_tries 5
step set_choose_tries 100
step take default class ssd
step chooseleaf indep 0 type host
step emit
}
此处的重要差别是“take”命令包含额外的“class CLASS_NAME”后缀。
17.1.1.4 其他命令 #
要列出 CRUSH 索引中使用的设备类型,请运行以下命令:
cephuser@adm >
ceph osd crush class ls
[
"hdd",
"ssd"
]
要列出现有的 CRUSH 规则,请运行以下命令:
cephuser@adm >
ceph osd crush rule ls
replicated_rule
fast
要查看名为“fast”的 CRUSH 规则的详细信息,请运行以下命令:
cephuser@adm >
ceph osd crush rule dump fast
{
"rule_id": 1,
"rule_name": "fast",
"ruleset": 1,
"type": 1,
"min_size": 1,
"max_size": 10,
"steps": [
{
"op": "take",
"item": -21,
"item_name": "default~ssd"
},
{
"op": "chooseleaf_firstn",
"num": 0,
"type": "host"
},
{
"op": "emit"
}
]
}
要列出属于“ssd”类型的 OSD,请运行以下命令:
cephuser@adm >
ceph osd crush class ls-osd ssd
0
1
17.1.1.5 从旧版 SSD 规则迁移到设备类型 #
在早于版本 5 的 SUSE Enterprise Storage 中,要写入适用于设备的规则,您需要手动编辑 CRUSH 索引并为每个具体的设备类型(例如 SSD)维护并行的层次结构。自 SUSE Enterprise Storage 5 起,设备类型特性透明地实现了这一目的。
您可以使用 crushtool
命令将旧版规则和层次结构转换为基于类型的新版规则。系统提供以下几种转换类型:
crushtool --reclassify-root ROOT_NAME DEVICE_CLASS
此命令会获取 ROOT_NAME 下的层次结构中的所有内容,并将通过
take ROOT_NAME
引用该根的所有规则调整为
take ROOT_NAME class DEVICE_CLASS
它会对存储桶重新编号,以便为指定类型的“shadow tree”使用旧 ID。因此,数据不会发生移动。
例 17.1︰crushtool --reclassify-root
#假设有以下现有规则:
rule replicated_ruleset { id 0 type replicated min_size 1 max_size 10 step take default step chooseleaf firstn 0 type rack step emit }
如果您将根“default”重新分类为“hdd”类型,规则将变为
rule replicated_ruleset { id 0 type replicated min_size 1 max_size 10 step take default class hdd step chooseleaf firstn 0 type rack step emit }
crushtool --set-subtree-class BUCKET_NAME DEVICE_CLASS
此方法会将根目录为 BUCKET_NAME 的子树中的每个设备标记为指定的设备类型。
--set-subtree-class
通常与--reclassify-root
选项结合使用,以确保该根中的所有设备均标为正确的类型。不过,其中一些设备可能特意使用了不同的类型,因此您不需要重新对它们进行标记。在此类情况下,请勿使用--set-subtree-class
选项。请记住,这样的重新映射并不完美,因为之前的规则是跨多个类型的设备分发的,而调整后的规则将仅映射到指定设备类型的设备。crushtool --reclassify-bucket MATCH_PATTERN DEVICE_CLASS DEFAULT_PATTERN
此方法允许将特定于类型的并行层次结构与常规层次结构合并。例如,许多用户会有类似以下的 CRUSH 索引:
例 17.2︰crushtool --reclassify-bucket
#host node1 { id -2 # do not change unnecessarily # weight 109.152 alg straw hash 0 # rjenkins1 item osd.0 weight 9.096 item osd.1 weight 9.096 item osd.2 weight 9.096 item osd.3 weight 9.096 item osd.4 weight 9.096 item osd.5 weight 9.096 [...] } host node1-ssd { id -10 # do not change unnecessarily # weight 2.000 alg straw hash 0 # rjenkins1 item osd.80 weight 2.000 [...] } root default { id -1 # do not change unnecessarily alg straw hash 0 # rjenkins1 item node1 weight 110.967 [...] } root ssd { id -18 # do not change unnecessarily # weight 16.000 alg straw hash 0 # rjenkins1 item node1-ssd weight 2.000 [...] }
此函数会将与给定模式相匹配的每个存储桶重新分类。模式的格式可能为
%suffix
或prefix%
。在上面的示例中,您需要使用%-ssd
模式。对于每个匹配的存储桶,与“%”通配符相匹配的名称的其余部分指定了基本存储桶。所匹配存储桶中的所有设备都会标记为指定的设备类型,随后会移至基本存储桶中。如果基本存储桶不存在(例如,如果“node12-ssd”存在,但“node12”不存在),则系统会创建基本存储桶,并将其关联到指定的默认父存储桶下。系统会为新的阴影存储桶保留旧的存储桶 ID,以防数据移动。系统会对包含引用旧存储桶的take
步骤的规则进行调整。crushtool --reclassify-bucket BUCKET_NAME DEVICE_CLASS BASE_BUCKET
您可以使用不包含通配符的
--reclassify-bucket
选项来映射单个存储桶。例如,在上面的示例中,我们希望将“ssd”存储桶映射到默认存储桶。用于转换由上述片段组成的索引的最后一个命令将如下所示:
cephuser@adm >
ceph osd getcrushmap -o originalcephuser@adm >
crushtool -i original --reclassify \ --set-subtree-class default hdd \ --reclassify-root default hdd \ --reclassify-bucket %-ssd ssd default \ --reclassify-bucket ssd ssd default \ -o adjusted要确认转换是否正确,可以使用
--compare
选项。该选项会测试大量对 CRUSH 索引的输入,并比较是否会产生相同的结果。这些输入通过适用于--test
的相同选项来控制。对于上面的示例,命令将如下所示:cephuser@adm >
crushtool -i original --compare adjusted rule 0 had 0/10240 mismatched mappings (0) rule 1 had 0/10240 mismatched mappings (0) maps appear equivalent提示如果存在差异,括号中将会显示重新映射的输入比率。
如果您对调整后的 CRUSH 索引满意,便可将其应用于集群:
cephuser@adm >
ceph osd setcrushmap -i adjusted
17.1.1.6 详细信息 #
有关 CRUSH 索引的更多详细信息,请参见第 17.5 节 “CRUSH 索引操作”。
有关 Ceph 存储池的更多一般详细信息,请参见第 18 章 “管理存储池”
有关纠删码存储池的更多详细信息,请参见第 19 章 “纠删码存储池”。
17.2 存储桶 #
CRUSH 索引包含 OSD 的列表,可将这些 OSD 组织成存储桶的树形结构排列形式,以便将设备聚合到物理位置。单个 OSD 构成树形结构中的树叶。
0 |
osd |
特定的设备或 OSD( |
1 |
host |
包含一个或多个 OSD 的主机的主机名。 |
2 |
chassis |
机架中包含该 |
3 |
rack |
计算机机柜。默认值为 |
4 |
row |
由一系列机柜组成的设备排。 |
5 |
pdu |
“Power Distribution Unit”(电源分配单元)的缩写。 |
6 |
pod |
“Point of Delivery”(分发点)的缩写。在此环境中为一组 PDU 或一组机架排。 |
7 |
room |
包含多排机架的房间。 |
8 |
datacenter |
包含一个或多个房间的物理数据中心。 |
9 |
region |
全球的地理地区(例如 NAM、LAM、EMEA、APAC 等) |
10 |
root |
OSD 存储桶的树形结构根节点(通常设为 |
您可以修改现有类型,以及创建自己的存储桶类型。
Ceph 的部署工具可生成 CRUSH 索引,其中包含每个主机的存储桶,以及名为“default”的根(可用于默认的 rbd
存储池)。剩余的存储桶类型提供了一种存储有关节点/存储桶的物理位置信息的方法,当 OSD、主机或网络硬件发生故障,并且管理员需要访问物理硬件时,这种方法可大大简化集群管理工作。
存储桶具有类型、唯一的名称(字符串)、以负整数表示的唯一 ID、相对于其项目总容量/权限的权重、存储桶算法(默认为 straw2
)和哈希(默认为 0
,代表 CRUSH 哈希 rjenkins1
)。一个存储桶可以包含一个或多个项目。项目可由其他存储桶或 OSD 组成。项目可能会有一个权重来反映该项目的相对权重。
[bucket-type] [bucket-name] { id [a unique negative numeric ID] weight [the relative capacity/capability of the item(s)] alg [the bucket type: uniform | list | tree | straw2 | straw ] hash [the hash type: 0 by default] item [item-name] weight [weight] }
下面的示例说明如何使用存储桶来聚合存储池,以及诸如数据中心、机房、机柜和设备排的物理位置。
host ceph-osd-server-1 { id -17 alg straw2 hash 0 item osd.0 weight 0.546 item osd.1 weight 0.546 } row rack-1-row-1 { id -16 alg straw2 hash 0 item ceph-osd-server-1 weight 2.00 } rack rack-3 { id -15 alg straw2 hash 0 item rack-3-row-1 weight 2.00 item rack-3-row-2 weight 2.00 item rack-3-row-3 weight 2.00 item rack-3-row-4 weight 2.00 item rack-3-row-5 weight 2.00 } rack rack-2 { id -14 alg straw2 hash 0 item rack-2-row-1 weight 2.00 item rack-2-row-2 weight 2.00 item rack-2-row-3 weight 2.00 item rack-2-row-4 weight 2.00 item rack-2-row-5 weight 2.00 } rack rack-1 { id -13 alg straw2 hash 0 item rack-1-row-1 weight 2.00 item rack-1-row-2 weight 2.00 item rack-1-row-3 weight 2.00 item rack-1-row-4 weight 2.00 item rack-1-row-5 weight 2.00 } room server-room-1 { id -12 alg straw2 hash 0 item rack-1 weight 10.00 item rack-2 weight 10.00 item rack-3 weight 10.00 } datacenter dc-1 { id -11 alg straw2 hash 0 item server-room-1 weight 30.00 item server-room-2 weight 30.00 } root data { id -10 alg straw2 hash 0 item dc-1 weight 60.00 item dc-2 weight 60.00 }
17.3 规则集 #
CRUSH 索引支持“CRUSH 规则”概念,这些规则确定存储池的数据归置。对于大型集群,您可能会创建许多存储池,其中每个存储池各自可能具有自己的 CRUSH 规则组和规则。默认 CRUSH 索引具有适用于默认根的规则。如果您想使用更多根和更多规则,则需稍后自行创建,或者在创建新存储池时让系统自动创建。
大多数情况下,无需修改默认规则。创建新存储池时,该存储池的默认规则组为 0。
规则采用以下格式:
rule rulename { ruleset ruleset type type min_size min-size max_size max-size step step }
- ruleset
一个整数。将规则分类,使其属于一个规则组。通过在存储池中设置规则组来激活。必须指定此选项。默认值为
0
。- type
一个字符串。描述了适用于“副本”或“纠删码”存储池的规则。必须指定此选项。默认值为
replicated
。- min_size
一个整数。如果存储池组创建的副本数小于此数字,CRUSH 将不选择此规则。必须指定此选项。默认值为
2
。- max_size
一个整数。如果存储池组创建的副本数大于此数字,CRUSH 将不选择此规则。必须指定此选项。默认值为
10
。- step take bucket
采用以名称指定的存储桶,并开始在树中向下迭代。必须指定此选项。有关在树中迭代的说明,请参见第 17.3.1 节 “迭代节点树”。
- step targetmodenum type bucket-type
target 可以是
choose
或chooseleaf
。如果设置为choose
,则会选择许多存储桶。chooseleaf
直接从存储桶集的每个存储桶的子树中选择 OSD(叶节点)。mode 可以是
firstn
或indep
。请参见第 17.3.2 节 “firstn 和 indep
”。
选择给定类型的存储桶的数量。其中,N 是可用选项的数量,如果 num > 0 且 < N,则选择该数量的存储桶;如果 num < 0,则表示 N - num;如果 num == 0,则选择 N 个存储桶(全部可用)。跟在
step take
或step choose
后使用。- step emit
输出当前值并清空堆栈。通常在规则的末尾使用,但也可在同一规则中用来构成不同的树。跟在
step choose
后使用。
17.3.1 迭代节点树 #
可采用节点树的形式来查看使用存储桶定义的结构。在此树中,存储桶是节点,OSD 是叶。
CRUSH 索引中的规则定义如何从此树中选择 OSD。规则从某个节点开始,然后在树中向下迭代,以返回一组 OSD。无法定义需要选择哪个分支。CRUSH 算法可确保 OSD 集能够满足复制要求并均衡分布数据。
使用 step take
bucket 时,节点树中的迭代从给定的存储桶(而不是存储桶类型)开始。如果要返回树中所有分支上的 OSD,该存储桶必须是根存储桶。否则,以下步骤只会在子树中迭代。
完成 step take
后,接下来会执行规则定义中的一个或多个 step choose
项。每个 step choose
项从前面选定的上层节点中选择定义数量的节点(或分支)。
最后,使用 step emit
返回选定的 OSD。
step chooseleaf
是一个便捷函数,可直接从给定存储桶的分支中选择 OSD。
图 17.2 “示例树”中提供了说明如何使用 step
在树中迭代的示例。在下面的规则定义中,橙色箭头和数字与 example1a
和 example1b
对应,蓝色箭头和数字与 example2
对应。
# orange arrows rule example1a { ruleset 0 type replicated min_size 2 max_size 10 # orange (1) step take rack1 # orange (2) step choose firstn 0 host # orange (3) step choose firstn 1 osd step emit } rule example1b { ruleset 0 type replicated min_size 2 max_size 10 # orange (1) step take rack1 # orange (2) + (3) step chooseleaf firstn 0 host step emit } # blue arrows rule example2 { ruleset 0 type replicated min_size 2 max_size 10 # blue (1) step take room1 # blue (2) step chooseleaf firstn 0 rack step emit }
17.3.2
firstn 和 indep
#
CRUSH 规则定义有故障节点或 OSD 的替换项(请参见第 17.3 节 “规则集”)。关键字 step
要求使用 firstn
或 indep
参数。图 17.3 “节点替换方法”提供了示例。
firstn
将替换节点添加到工作节点列表的末尾。如果某个节点发生故障,其后的正常节点会移位到左侧,以填充有故障节点留下的空缺。这是副本存储池的默认方法,也是需要采取的方法,因为次要节点已包含所有数据,因此可立即接管主要节点的职责。
indep
为每个工作节点选择固定的替换节点。替换有故障节点不会更改剩余节点的顺序。这对于纠删码存储池而言是所需的行为。在纠删码存储池中,节点上存储的数据取决于在选择节点时它所在的位置。如果节点的顺序发生变化,受影响节点上的所有数据都需要重新放置。
17.4 归置组 #
Ceph 会将对象映射到归置组 (PG)。归置组是指逻辑对象存储池的分片或片段,可将对象以组形式归置到 OSD 中。归置组可减少 Ceph 将数据存储到 OSD 中时每个对象的元数据量。如果归置组的数量较多(例如,每个 OSD 有 100 个归置组),将能实现较佳的平衡。
17.4.1 使用归置组 #
归置组 (PG) 聚合了存储池内的对象。主要原因是基于每个对象来跟踪对象归置和元数据的计算成本较高。例如,包含数百万个对象的系统无法直接跟踪各个对象的归置。
Ceph 客户端负责计算对象将属于哪个归置组。它会对对象 ID 进行哈希处理,并根据所定义存储池中的 PG 数及存储池的 ID 来应用操作。
归置组内的对象内容存储在一组 OSD 中。例如,在大小为 2 的副本存储池中,每个归置组将对象存储到两个 OSD 中:
如果 OSD 2 发生故障,则系统会将另一个 OSD 指定给归置组 1,并在该 OSD 中填充 OSD 1 内所有对象的副本。如果存储池大小从 2 变为 3,则系统会向归置组另外再分配一个 OSD,并在该 OSD 中填充归置组内所有对象的副本。
归置组并不拥有 OSD,它们与同一存储池甚至其他存储池内的其他归置组共享 OSD。如果 OSD 2 发生故障,归置组 2 也将需要使用 OSD 3 来恢复对象的副本。
当归置组的数量增加时,系统会向新归置组分配 OSD。CRUSH 函数的结果也会发生更改,而且系统会将之前的归置组的部分对象复制到新归置组并将它们从旧归置组删除。
17.4.2 确定 PG_NUM 的值 #
从 Ceph Nautilus (v14.x) 开始,您可以使用 Ceph Manager pg_autoscaler
模块根据需要自动扩展 PG。如果要启用此功能,请参考Section 8.1.1.1, “Default PG and PGP counts”。
创建新存储池时,您仍可手动选择 PG_NUM 的值:
#
ceph osd pool create POOL_NAME PG_NUM
PG_NUM 无法自动计算得出。以下是一些常用的值,选择哪个值取决于集群中的 OSD 数量:
- 少于 5 个 OSD:
将 PG_NUM 设置为 128。
- 5 到 10 个 OSD:
将 PG_NUM 设置为 512。
- 10 到 50 个 OSD:
将 PG_NUM 设置为 1024。
随着 OSD 数量的增加,选择正确的 PG_NUM 值也变得愈加重要。PG_NUM 对集群的行为以及 OSD 发生故障时的数据持久性具有很大影响。
17.4.2.1 计算超过 50 个 OSD 的归置组 #
如果 OSD 数量低于 50,请使用第 17.4.2 节 “确定 PG_NUM 的值”中所述的预选值。如果 OSD 数量超过 50,建议为每个 OSD 使用约 50 到 100 个归置组,以平衡资源的使用、数据持久性和数据分布。对于单个对象存储池,您可以使用以下公式来计算基线数量:
total PGs = (OSDs * 100) / POOL_SIZE
其中,POOL_SIZE 是副本的个数(如果是副本存储池)或 ceph osd erasure-code-profile get
命令所返回的“k”和“m”之和(如果是纠删码存储池)。应将结果舍入到最接近的 2 的幂。对于 CRUSH 算法,建议进行舍入,以便均衡归置组之间的对象数。
例如,如果集群包含 200 个 OSD 和大小为 3 个副本的存储池,您需要按如下方式预估 PG 数:
(200 * 100) / 3 = 6667
最接近的 2 的幂为 8192。
使用多个数据存储池存储对象时,您需要确保在每个存储池的归置组数与每个 OSD 的归置组数之间取得平衡。您需要采用合理的归置组总数,在不过度占用系统资源或导致互联过程过慢的前提下,确保每个 OSD 的差异保持在合理的较低水平。
例如,如果集群包含 10 个存储池,每个存储池有 512 个归置组(位于 10 个 OSD 中),则表示共有 5,120 个归置组分布于 10 个 OSD 中,即每个 OSD 有 512 个归置组。这样的设置不会使用过多资源。但是,如果创建了 1000 个存储池,且每个存储池有 512 个归置组,那么每个 OSD 需要处理约 50,000 个归置组,这样完成互联所需的资源和时间便会显著增加。
17.4.3 设置归置组数量 #
从 Ceph Nautilus (v14.x) 开始,您可以使用 Ceph Manager pg_autoscaler
模块根据需要自动扩展 PG。如果要启用此功能,请参考Section 8.1.1.1, “Default PG and PGP counts”。
如果您仍需手动指定存储池中的归置组数量,则需要在创建存储池时指定(请参见第 18.1 节 “创建存储池”)。为存储池设置归置组后,您可以运行以下命令来增加归置组的数量:
#
ceph osd pool set POOL_NAME pg_num PG_NUM
增加归置组数量后,您还需要增加要归置的归置组数量 (PGP_NUM
),以便您的集群重新达到平衡。PGP_NUM
是考虑要通过 CRUSH 算法归置的归置组数。增加 PG_NUM
会分割归置组,但在增加 PGP_NUM
之前数据不会迁移到较新的归置组。PGP_NUM
应等于 PG_NUM
。要增加应归置的归置组数量,请运行以下命令:
#
ceph osd pool set POOL_NAME pgp_num PGP_NUM
17.4.4 获取归置组数量 #
要获取存储池中的归置组数量,请运行以下 get
命令:
#
ceph osd pool get POOL_NAME pg_num
17.4.5 获取集群的 PG 统计数据 #
要获取集群内归置组的统计数据,请运行以下命令:
#
ceph pg dump [--format FORMAT]
有效格式为“plain”(默认值)和“json”。
17.4.6 获取卡住的 PG 统计数据 #
要获取所有卡在指定状态的归置组的统计数据,请运行以下命令:
#
ceph pg dump_stuck STATE \
[--format FORMAT] [--threshold THRESHOLD]
可能的状态有:“inactive”(PG 由于在等待拥有最新数据的 OSD 恢复启用状态而无法处理读取或写入)、“unclean”(PG 包含未复制所需次数的对象)、“stale”(PG 处于未知状态,即托管 PG 的 OSD 未在 mon_osd_report_timeout
选项所指定的时间间隔内向 Monitor 集群报告相关信息)、“undersized”或“degraded”。
有效格式为“plain”(默认值)和“json”。
该阈值定义归置组至少卡住多少秒(默认为 300 秒)后系统会将其包含到返回的统计数据中。
17.4.7 搜索归置组索引 #
要搜索特定归置组的索引,请运行以下命令:
#
ceph pg map PG_ID
Ceph 将返回归置组索引、归置组和 OSD 状态:
#
ceph pg map 1.6c
osdmap e13 pg 1.6c (1.6c) -> up [1,0] acting [1,0]
17.4.8 检索归置组统计数据 #
要检索特定归置组的统计数据,请运行以下命令:
#
ceph pg PG_ID query
17.4.9 洗刷归置组 #
要洗刷(第 17.6 节 “洗刷归置组”)归置组,请运行以下命令:
#
ceph pg scrub PG_ID
Ceph 会检查主节点和副本节点、生成归置组内所有对象的编目,并对它们进行比较,以确保没有缺少或不匹配的对象且对象的内容均一致。假设所有副本均匹配,最后的语义整理便可确保所有与快照相关的对象元数据均一致。错误通过日志来报告。
17.4.10 设置归置组回填和恢复的优先顺序 #
您可能会遇到数个归置组需要恢复和/或回填,而其中一些归置组存储的数据比其他归置组更为重要的情况。例如,这些 PG 可能存储着运行中计算机所使用的映像数据,其他 PG 则可能存储的是由非活跃计算机使用的数据或相关度较低的数据。在该情况下,您可能需要优先恢复这些归置组,以便更早地恢复存储在这些归置组中的数据的性能和可用性。要将特定归置组标记为在回填或恢复过程中优先处理,请运行以下命令:
#
ceph pg force-recovery PG_ID1 [PG_ID2 ... ]#
ceph pg force-backfill PG_ID1 [PG_ID2 ... ]
这将导致 Ceph 先对指定归置组执行恢复或回填,然后再处理其他归置组。这并不会中断当前正在进行的回填或恢复,而是会使指定的 PG 尽快得到处理。如果您改变了主意或将错误的归置组设为优先处理,请使用以下命令取消优先顺序:
#
ceph pg cancel-force-recovery PG_ID1 [PG_ID2 ... ]#
ceph pg cancel-force-backfill PG_ID1 [PG_ID2 ... ]
cancel-*
命令会删除 PG 的“force”标志,使其按默认顺序接受处理。同样,这并不会影响当前正在处理的归置组,只会影响仍在排队的归置组。完成归置组恢复或回填后,系统即会自动清除“force”标志。
17.4.11 还原丢失的对象 #
如果集群丢失了一个或多个对象,而您已决定放弃搜索丢失的数据,则需要将未找到的对象标记为“lost”。
如果在查询过所有可能的位置后仍未找到这些对象,您可能需要放弃这些丢失的对象。这可能是由于几种故障同时发生(这种情况很少见)导致的,致使集群在写入本身恢复之前便得知写入已执行。
目前唯一支持的选项为“revert”,该选项会回滚到对象的先前版本,或在有新对象时完全忽略丢失的对象。要将“未找到”的对象标记为“lost”,请运行以下命令:
cephuser@adm >
ceph pg PG_ID mark_unfound_lost revert|delete
17.4.12 启用 PG 自动扩展器 #
归置组 (PG) 是 Ceph 分布数据方式的详细内部实现。通过启用 PG 自动扩展功能,您可以允许集群根据集群的使用情况创建或自动调整 PG。
系统中的每个存储池都有一个 pg_autoscale_mode
属性,可将其设为 off
、on
或 warn
:
自动扩展器按存储池配置,可在以下三种模式下运行:
- off
为此存储池禁用自动扩展功能。由管理员为每个存储池选择合适的 PG 数量。
- on
为给定存储池启用 PG 计数自动调整功能。
- warn
一旦应调整 PG 计数,系统将发出健康状况告警。
要为现有存储池设置自动扩展模式,请运行以下命令:
cephuser@adm >
ceph osd pool set POOL_NAME pg_autoscale_mode mode
您也可以运行以下命令,以配置将应用于日后创建的所有存储池的默认 pg_autoscale_mode
:
cephuser@adm >
ceph config set global osd_pool_default_pg_autoscale_mode MODE
您可以运行以下命令来查看每个存储池、它的相关使用情况,以及对 PG 计数的任何更改建议:
cephuser@adm >
ceph osd pool autoscale-status
17.5 CRUSH 索引操作 #
本节介绍基本的 CRUSH 索引操作方法,例如编辑 CRUSH 索引、更改 CRUSH 索引参数,以及添加/移动/删除 OSD。
17.5.1 编辑 CRUSH 索引 #
要编辑现有的 CRUSH 索引,请执行以下操作:
获取 CRUSH 索引。要获取集群的 CRUSH 索引,请执行以下命令:
cephuser@adm >
ceph osd getcrushmap -o compiled-crushmap-filenameCeph 会将编译的 CRUSH 索引输出 (
-o
) 到您指定名称的文件。由于该 CRUSH 索引采用编译格式,您必须先将其反编译,然后才能对其进行编辑。反编译 CRUSH 索引。要反编译 CRUSH 索引,请执行以下命令:
cephuser@adm >
crushtool -d compiled-crushmap-filename \ -o decompiled-crushmap-filenameCeph 将对已编译的 CRUSH 索引进行反编译 (
-d
),并将其输出 (-o
) 到您指定名称的文件。至少编辑“设备”、“存储桶”和“规则”中的其中一个参数。
编译 CRUSH 索引。要编译 CRUSH 索引,请执行以下命令:
cephuser@adm >
crushtool -c decompiled-crush-map-filename \ -o compiled-crush-map-filenameCeph 会将编译的 CRUSH 索引存储到您指定名称的文件。
设置 CRUSH 索引。要设置集群的 CRUSH 索引,请执行以下命令:
cephuser@adm >
ceph osd setcrushmap -i compiled-crushmap-filenameCeph 将输入您所指定文件名的已编译 CRUSH 索引,作为集群的 CRUSH 索引。
请为导出并修改过的 CRUSH 索引文件使用 git 或 svn 这样的版本控制系统。这可以让可能发生的回滚变得简单。
请使用 crushtool --test
命令测试经过调整的新 CRUSH 索引,并与应用新 CRUSH 索引之前的状态进行比较。以下命令开关十分有用:--show-statistics
、--show-mappings
、--show-bad-mappings
、--show-utilization
、--show-utilization-all
、--show-choose-tries
17.5.2 添加或移动 OSD #
要在运行中集群的 CRUSH 索引中添加或移动 OSD,请执行以下命令:
cephuser@adm >
ceph osd crush set id_or_name weight root=pool-name
bucket-type=bucket-name ...
- id
一个整数。OSD 的数字 ID。必须指定此选项。
- name
一个字符串。OSD 的全名。必须指定此选项。
- weight
一个双精度值。OSD 的 CRUSH 权重。必须指定此选项。
- root
一个键/值对。默认情况下,CRUSH 层次结构包含 default 存储池作为根。必须指定此选项。
- bucket-type
键/值对。可在 CRUSH 层次结构中指定 OSD 的位置。
下面的示例将 osd.0
添加到层次结构,或移动之前某个位置的 OSD。
cephuser@adm >
ceph osd crush set osd.0 1.0 root=data datacenter=dc1 room=room1 \
row=foo rack=bar host=foo-bar-1
17.5.3 ceph osd reweight
与 ceph osd crush reweight
之间的差异 #
有两个相似的命令都可更改 Ceph OSD 的权重。它们的使用情境不同,可能会造成混淆。
17.5.3.1 ceph osd reweight
#
用法:
cephuser@adm >
ceph osd reweight OSD_NAME NEW_WEIGHT
ceph osd reweight
用于对 Ceph OSD 设置覆盖权重。此值介于 0 到 1 之间,会强制 CRUSH 重新放置将以其他方式存储于此驱动器上的数据。该命令不会更改为 OSD 上方的存储桶指定的权重,它是一种在正常 CRUSH 分布出现问题时的纠正措施。例如,如果您的其中一个 OSD 处于 90%,而其他 OSD 处于 40%,则您可缩小此权重,以尝试对其进行补偿。
请注意,ceph osd reweight
并非永久性设置。当某个 OSD 被标记为“out”时,它的权重会被设置为 0,当它一旦重新被标记为“in”,其权重又会更改为 1。
17.5.3.2 ceph osd crush reweight
#
用法:
cephuser@adm >
ceph osd crush reweight OSD_NAME NEW_WEIGHT
ceph osd crush reweight
用于设置 OSD 的 CRUSH 权重。此权重可以是任意值(通常是以 TB 为单位的磁盘大小),用于控制系统尝试分配给 OSD 的数据量。
17.5.4 删除 OSD #
要从运行中集群的 CRUSH 索引中删除 OSD,请执行以下命令:
cephuser@adm >
ceph osd crush remove OSD_NAME
17.5.5 添加存储桶 #
要向运行中集群的 CRUSH 索引添加某个存储桶,请执行 ceph osd crush add-bucket
命令:
cephuser@adm >
ceph osd crush add-bucket BUCKET_NAME BUCKET_TYPE
17.5.6 移动存储桶 #
要将某个存储桶移到 CRUSH 索引层次结构中的不同位置,请执行以下命令:
cephuser@adm >
ceph osd crush move BUCKET_NAME BUCKET_TYPE=BUCKET_NAME [...]
例如:
cephuser@adm >
ceph osd crush move bucket1 datacenter=dc1 room=room1 row=foo rack=bar host=foo-bar-1
17.5.7 删除存储桶 #
要从 CRUSH 索引层次结构中删除某个存储桶,请执行以下命令:
cephuser@adm >
ceph osd crush remove BUCKET_NAME
从 CRUSH 层次结构中只能删除空存储桶。
17.6 洗刷归置组 #
除了为对象创建多个副本外,Ceph 还可通过洗刷归置组来确保数据完整性(请参见第 1.3.2 节 “归置组”了解有关归置组的详细信息)。Ceph 的洗刷类似于在对象存储层运行 fsck
。对于每个归置组,Ceph 都会生成一个包含所有对象的编目,并比较每个主对象及其副本,以确保不会有缺失或不匹配的对象。每天的浅层洗刷会检查对象大小和属性,而每周的深层洗刷则会读取数据并使用校验和来确保数据完整性。
洗刷对于维护数据完整性非常重要,但该操作可能会降低性能。您可以通过调整以下设置来增加或减少洗刷操作:
osd max scrubs
同时针对一个 Ceph OSD 执行的洗刷操作数量上限。默认值为 1。
osd scrub begin hour
、osd scrub end hour
按小时定义的一天内可以执行洗刷的时间段(0 到 24)。默认开始时间为 0,结束时间为 24。
重要如果归置组的洗刷间隔超出
osd scrub max interval
设置的值,则无论您定义了何种洗刷时间段,都将执行洗刷。osd scrub during recovery
允许恢复期间执行洗刷。如果将此选项设置为“false”,则当存在工作的恢复进程时,将禁止安排新的洗刷。已在运行的洗刷将继续执行。此选项有助于降低忙碌集群上的负载。默认值为“true”。
osd scrub thread timeout
洗刷线程超时前的最长时间(以秒为单位)。默认值为 60。
osd scrub finalize thread timeout
洗刷完成线程超时前的最长时间(以秒为单位)。默认值为 60*10。
osd scrub load threshold
规范化的最大负载。当系统负载(由
getloadavg()
与online cpus
数量之比定义)高于此数字时,Ceph 将不会执行洗刷。默认值为 0.5。osd scrub min interval
当 Ceph 集群负载较低时洗刷 Ceph OSD 的最短间隔(以秒为单位)。默认值为 60*60*24(一天一次)。
osd scrub max interval
无论集群负载如何都洗刷 Ceph OSD 的最长间隔(以秒为单位)。默认值为 7*60*60*24(一周一次)。
osd scrub chunk min
单次操作期间要洗刷的对象存储块数量下限。洗刷期间,Ceph 会阻止向单个块写入数据。默认值为 5。
osd scrub chunk max
单次操作期间要洗刷的对象存储块数量上限。默认值为 25。
osd scrub sleep
洗刷下一组块之前休眠的时间。增大此值会降低整个洗刷操作的速度,但对客户端操作的影响较小。默认值为 0。
osd deep scrub interval
深层洗刷(完整读取所有数据)的间隔。
osd scrub load threshold
选项不会影响此设置。默认值为 60*60*24*7(一周一次)。osd scrub interval randomize ratio
在安排归置组的下一次洗刷作业时,为
osd scrub min interval
值增加一个随机延迟。该延迟为一个随机的值,小于osd scrub min interval
*osd scrub interval randomized ratio
所得结果。因此,该默认设置实际上是将洗刷随机地安排在允许的时间段 [1, 1.5] *osd scrub min interval
内执行。默认值为 0.5。osd deep scrub stride
执行深层洗刷时读取的大小。默认值为 524288 (512 kB)。