Ceph osdmaptool 完全指南:OSD Map 创建、CRUSH 操作、PG 映射分析与 upmap 平衡模拟
2026/9/23 1:08:02 网站建设 项目流程
  • 存储
  • 分布式文件系统
  • 对象存储
  • 后端
  • 高可用

【免费下载链接】ceph

Ceph is a distributed object, block, and file storage platform

项目地址:https://gitcode.com/gh_mirrors/ce/ceph
点击查看免费下载

osdmaptool是 Ceph 发行版内置的 OSD Cluster Map 离线操作工具,用于创建、查看与修改 OSD Map,提取或嵌入 CRUSH Map,模拟 upmap 平衡器以评估 PG 分布,并计算 PG 到 OSD 的映射关系。本文以 doc/man/8/osdmaptool.rst 为骨架,结合 src/tools/osdmaptool.cc 的选项解析实现与 src/test/cli/osdmaptool 下的 CLI 测试用例,完整讲解每个选项的用法、输出含义与底层机制。读完本文,你将掌握:如何离线构造并检验 OSD Map、如何在不解集群的情况下验证 CRUSH 映射是否均衡、如何生成可直接执行的 upmap 平衡命令,以及如何模拟读平衡(primary 平衡)效果。

一、工具定位与适用场景

osdmaptool是 Ceph 分布式存储系统中的 OSD 集群映射(OSD cluster map)操作工具,其核心能力包括:

  • 创建:离线生成一份全新的 OSD Map(--createsimple--create-from-conf);
  • 查看:以纯文本或 JSON 形式打印 OSD Map 内容(--print--dump--tree--health);
  • CRUSH 操作:从 OSD Map 中导出内嵌的 CRUSH Map,或导入新的 CRUSH Map(--export-crush--import-crush);
  • 映射分析:模拟 PG 到 OSD 的映射(--test-map-pgs系列、--test-map-pg--test-map-object--test-crush--test-random);
  • 平衡模拟:模拟 upmap 平衡器模式,预先评估为平衡 PG 所需的上调操作数量与内容(--upmap--upmap-active),以及模拟读平衡(primary 平衡,--read)。

典型使用场景包括:离线测试新建集群的 PG 分布是否均衡、在批量 OSD 上线前预演 upmap 平衡会产生多少条命令、调试 CRUSH 规则对映射的影响,以及在测试环境中快速生成一份可用的 OSD Map。该工具不需要运行中的集群,只需一个 OSD Map 文件即可工作,非常适合脚本化与自动化验证。

从源码看,工具入口位于 src/tools/osdmaptool.cc 的main()函数:先通过ceph_argparse_*系列函数解析全部命令行参数,再执行对应的创建、标记、映射测试或 upmap 计算逻辑;工具以CEPH_ENTITY_TYPE_CLIENT类型初始化,并设置CINIT_FLAG_NO_DEFAULT_CONFIG_FILE,意味着它不依赖默认配置文件即可运行。

二、命令行语法总览

原文档给出了完整的 Synopsis,其语法为:

osdmaptool mapfilename [--print] [--createsimple numosd [--pgbits bitsperosd]] [--clobber] osdmaptool mapfilename [--import-crush crushmap] osdmaptool mapfilename [--export-crush crushmap] osdmaptool mapfilename [--upmap file] [--upmap-max max-optimizations] [--upmap-deviation max-deviation] [--upmap-pool poolname] [--save] [--upmap-active] osdmaptool mapfilename [--upmap-cleanup] [--upmap file]

mapfilename是唯一的位置参数,其余均为可选开关。需要注意:若未指定--createsimple/--create-from-conf且文件已存在,osdmaptool 会直接读取该文件;若创建模式且目标文件已存在,则必须显式携带--clobber才允许覆盖(源码 src/tools/osdmaptool.cc 中通过::stat检查文件存在性并报错exists, --clobber to overwrite)。

选项的默认值在源码中有明确定义(src/tools/osdmaptool.cc):pg_bits = 6pgp_bits = 6upmap_max = 10upmap_deviation = 5upmap_file = "-"(即 stdout)。此外,工具还要求upmap-deviation >= 1,否则报错退出;--osd-size-aware仅在 read 模式下可用。

三、选项详解与源码印证

3.1 查看类选项

选项说明
--print在所有修改完成后,以纯文本形式打印 Map 的完整内容
--dump <format>以纯文本显示 Map;当指定格式不受支持时回退为 JSON。是--print的替代方案
--tree以层级树形式显示 Map 的 OSD 拓扑
--health输出健康检查(health checks)信息

源码中--dump--tree都支持携带格式参数:当参数为空或等于plain时使用默认文本输出,否则通过Formatter::create(val, "", "json")创建指定格式的 formatter(src/tools/osdmaptool.cc),这与文档所述"格式不支持时回退 JSON"一致。

3.2 创建类选项

选项说明
--createsimple numosd [--pg_bits bitsperosd] [--pgp_bits bits]创建一份包含numosd个设备的通用 OSD Map
--create-from-conf使用默认配置创建 OSD Map
--with-default-pool创建 Map 时包含默认 pool(rbd)
--clobber允许 osdmaptool 覆盖已存在的mapfilename

--createsimple的 PG 数量计算规则是:pg_num = numosd << pg_bits(即numosd左移bitsperosd位),pgp_num = numosd << pgp_bits。在 src/tools/osdmaptool.cc 中,创建路径调用osdmap.build_simple()build_simple_with_pool()完成初始化;默认pg_bitspgp_bits均为 6。

--create-from-conf需要结合-c ceph.conf使用(参见测试 src/test/cli/osdmaptool/upmap.t 中的osdmaptool --create-from-conf om -c $TESTDIR/ceph.conf.withracks --with-default-pool),此时num_osd被置为-1,Map 结构由配置文件中的osd_pool_default_*等参数决定。

验证示例(对应 src/test/cli/osdmaptool/create-print.t):

$ osdmaptool --createsimple 3 myosdmap --with-default-pool osdmaptool: osdmap file 'myosdmap' osdmaptool: writing epoch 1 to myosdmap

随后打印出的 Map 摘要显示pool 1 'rbd' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 192 pgp_num 192——这里 3 个 OSD、默认 6 bit,得到pg_num = 3 << 6 = 192,与文档规则完全吻合。

3.3 CRUSH 导入导出与权重调整

选项说明
--import-crush mapfilemapfile加载 CRUSH Map 并嵌入 OSD Map
--export-crush mapfile从 OSD Map 提取 CRUSH Map 并写入mapfile
--adjust-crush-weight osdid:weight[,osdid:weight,...]修改指定 OSD 的 CRUSH 权重(默认不持久化)

导出使用osdmap.crush->encode()编码后写入文件(src/tools/osdmaptool.cc);导入则会先解码校验(CrushWrapper::decode),并检查crushmap max_devices是否超过osdmap max_osd,随后通过OSDMap::Incremental增量应用到 OSD Map(src/tools/osdmaptool.cc)。将导出的 CRUSH Map 交给crushtool --decompile即可查看文本形式的 CRUSH 结构(见 src/test/cli/osdmaptool/create-print.t)。

--adjust-crush-weight使用osdid:weight的逗号分隔格式,内部通过osdmap.crush->adjust_item_weightf()修改权重;若同时指定--save,则会构造 Incremental 并将修改持久化到文件(src/tools/osdmaptool.cc)。测试 src/test/cli/osdmaptool/crush.t 演示了不带--save(仅打印 "Adjusted osd.0 CRUSH weight to 5"、不落盘)与带--save(写入 epoch 5)的差异。

3.4 PG 映射测试类选项

选项说明
--test-map-pgs [--pool poolid] [--range-first first --range-last last]打印所有 PG 到 OSD 的映射
--test-map-pgs-dump [--pool poolid] [--range-first first --range-last last]打印所有 PG 的摘要及其到映射 OSD 的映射
--test-map-pgs-dump-all [--pool poolid] [--range-first first --range-last last]打印所有 PG 的摘要及其到全部 OSD 的映射
--test-map-pg <pgid>将特定 PG 映射到 OSD
--test-map-object <objectname> [--pool poolid]将特定对象映射到 OSD
--test-crush [--range-first first --range-last last]将 PG 映射到 acting OSD
--test-random对 PG 做随机映射(用于对照实验)

--range-first/--range-last的作用是:当mapfilename指向一个目录时,依次读取该目录下以0,1,2,...命名的多个 OSD Map 文件并逐个解码(src/tools/osdmaptool.cc),例如:

osdmaptool --test-map-pgs --range-first 0 --range-last 2 osdmap_dir

会迭代读取osdmap_dir目录中名为 0、1、2 的文件。此外--test-map-pgs还额外支持--pg_num <pg_num>临时覆盖 pool 的 PG 数(见 src/tools/osdmaptool.cc)。

--test-map-object的完整映射链路为:object_locator_to_pg()计算对象归属的原始 PG →raw_pg_to_pg()规整 PG 号 →pg_to_acting_osds()得到 acting 集合(src/tools/osdmaptool.cc);未指定--pool时默认假设 pool 1。--test-map-pg则直接解析pgid(形如1.2f),同时输出 raw / up / acting 三套集合及其各自的 primary(src/tools/osdmaptool.cc),可以清晰看到"原始 CRUSH 结果"与"经过 upmap/primary-affinity 调整后的实际生效结果"之间的差异。

3.5 状态标记类选项

选项说明
--mark-up-in将所有 OSD 标记为 up 且 in(不持久化)
--mark-out <osdid>将 OSD 标记为 out(不持久化)
--mark-up <osdid>将 OSD 标记为 up(不持久化)
--mark-in <osdid>将 OSD 标记为 in(不持久化)
--clear-temp清除pg_tempprimary_temp变量
--clean-temps清理pg_temp

这些选项"不持久化"的含义是:仅在内存中的 OSDMap 对象上生效,用于后续的映射测试或 upmap 模拟,并不会写回文件。源码中--mark-up-in遍历get_max_osd()范围内的所有 OSD,逐一置位CEPH_OSD_UP状态并设置 in 权重;对 CRUSH 权重为 0 的 OSD 还会自动调用adjust_item_weightf(..., 1.0)补上默认权重(src/tools/osdmaptool.cc),保证新建的 OSD 能参与后续映射计算。测试 src/test/cli/osdmaptool/test-map-pgs.t 就是先用--mark-up-in把 500 个 OSD 全部标记为 up/in,再做--test-map-pgs验证size 3下 8000 个 PG 全部映射到 3 个不同 OSD。

--clear-temp调用osdmap.clear_temp()--clean-temps则构造 Incremental 并调用OSDMap::clean_temps()(src/tools/osdmaptool.cc)。

3.6 upmap 平衡类选项

选项说明
--upmap-cleanup <file>清理pg_upmap[_items]条目,将命令写入<file>(默认-表示 stdout)
--upmap <file>计算用于平衡 PG 布局的 pg upmap 条目,将命令写入<file>
--upmap-max <max-optimizations>设置最多计算的 upmap 条目数(默认 10)
--upmap-deviation <max-deviation>设置偏离目标的允许范围(默认 5)
--upmap-pool <poolname>将 upmap 平衡限制在单个 pool,可重复使用以限定多个 pool
--upmap-active模拟活跃平衡器,持续应用修改直到分布均衡
--upmap-seed <seed>指定随机种子(源码中通过--upmap-seed解析,便于复现结果)
--save将 upmap 或 CRUSH 调整的修改写入修改后的 OSD Map 文件
--vstart为 upmap 与 read 输出添加./bin/前缀(面向 vstart 开发环境)

--upmap的计算流程在 src/tools/osdmaptool.cc:先解析--upmap-pool指定的 pool 名并校验存在性;未指定时默认对 Map 中全部 pool 计算。每轮迭代会随机打乱 pool 顺序,逐 pool 调用osdmap.calc_pg_upmaps(cct, upmap_deviation, left, one_pool, &pending_inc, seed)计算最多left条调整,累计输出prepared X/Y changes。生成的命令通过print_inc_upmaps()输出,包含四类 Ceph 命令(src/tools/osdmaptool.cc):

  • ceph osd pg-upmap <pgid> <osd>.../ceph osd rm-pg-upmap <pgid>
  • ceph osd pg-upmap-items <pgid> <from> <to>.../ceph osd rm-pg-upmap-items <pgid>
  • ceph osd pg-upmap-primary <pgid> <osd>/ceph osd rm-pg-upmap-primary <pgid>

--upmap-active模式下,工具会反复应用增量并重新计算,直到某轮prepared 0/N changes(即输出 "Unable to find further optimization, or distribution is already perfect"),随后打印每个 OSD 的最终 PG 数量与总耗时/轮数。当--save--upmap-active生效时,计算出的增量会被apply_incremental()应用到内存 Map 并标记modified,最终写回文件(epoch 递增)。

测试 src/test/cli/osdmaptool/upmap.t 展示了完整链路:--create-from-conf建 Map →--mark-up-in --upmap-max 11 --upmap c --save生成 11 条ceph osd pg-upmap-items命令并持久化 →--print验证pg_upmap_items已写入 Map。这也是推荐的工作流:先用 osdmaptool 离线验证与生成命令,再在真实集群中执行

3.7 读平衡(primary 平衡)类选项

选项说明
--read <file>计算用于平衡 PG primary 的 upmap 条目,写入<file>
--read-pool <poolname>指定读平衡器要调整的 pool
--osd-size-aware读模式下考虑不同容量设备(需 pool 设置read_ratio

读平衡的目标是让每个 OSD 上的primary 数量(即承担读流量主副本的角色)尽量均衡。源码流程(src/tools/osdmaptool.cc):

  1. 校验 pool 存在且为副本(replicated)类型,纠删码池会直接报错退出;
  2. 调用get_pgs_by_osd()收集调整前每个 OSD 的 PG 与 primary 分布,并用calc_read_balance_score()计算read_balance_score(分数越低越均衡);
  3. 调用osdmap.balance_primaries()计算调整方案(--osd-size-aware时传入RB_OSDSIZEOPT,此时要求 pool 已设置合法的read_ratio,可通过ceph osd pool set <pool> read_ratio <value>配置);
  4. 再次统计并打印 BEFORE / AFTER 两段对比:每个 OSD 的primary affinitynumber of prims,以及前后read_balance_score,最后输出num changes与生成的命令。

--osd-size-aware模式下若read_ratio未设置或超出(0,100]范围,工具会给出明确的设置指引后退出。

四、实战示例与输出解读

4.1 创建 16 设备 OSD Map 并查看

osdmaptool --createsimple 16 osdmap --clobber osdmaptool --print osdmap

第一条命令创建包含 16 个 OSD 的通用 Map(若文件已存在则覆盖);第二条以纯文本打印全部内容,包括 epoch、fsid、pool 定义、max_osd以及内嵌 CRUSH Map 的文本视图。

4.2 查看 pool 1 的 PG 映射统计

osdmaptool osdmap --test-map-pgs-dump --pool 1

典型输出如下(完整复刻自原文档):

pool 1 pg_num 8 1.0 [0,2,1] 0 1.1 [2,0,1] 2 1.2 [0,1,2] 0 1.3 [2,0,1] 2 1.4 [0,2,1] 0 1.5 [0,2,1] 0 1.6 [0,1,2] 0 1.7 [1,0,2] 1 #osd count first primary c wt wt osd.0 8 5 5 1 1 osd.1 8 1 1 1 1 osd.2 8 2 2 1 1 in 3 avg 8 stddev 0 (0x) (expected 2.3094 0.288675x)) min osd.0 8 max osd.0 8 size 0 0 size 1 0 size 2 0 size 3 8

该输出包含四层信息:

  1. PG 表:pool 1 有 8 个 PG,每行是一个 PG,列为「PG id、acting 集合、primary OSD」。例如1.5 [0,2,1] 0表示 PG 1.5 的 acting 集合为[0,2,1],primary 是 OSD 0;
  2. OSD 表:每行是一个 OSD,列为「映射到该 OSD 的 PG 数(count)、该 OSD 出现在 acting 集合首位(first)的 PG 数、作为 primary 的 PG 数、CRUSH 权重(c wt)、OSD 权重(wt)」;
  3. 分布统计:对 3 个 OSD 上 PG 数量做统计,给出均值(avg)、标准差(stddev)、stddev/avg、以及"期望标准差"(基于二项分布模型的期望值)与其比值——本例 stddev 为 0,说明 8 个 PG 被完美均匀地分散到 3 个 OSD;
  4. size 分布:统计映射到 n 个不同 OSD 的 PG 数量。本例size 3 8表示全部 8 个 PG 都映射到了 3 个不同的 OSD(副本数恰好 3),没有 PG 出现降级(size < 3)。

4.3 失衡集群的统计对比

在一个分布不那么均衡的集群中,输出可能如下(来自原文档):

#osd count first primary c wt wt osd.0 33 9 9 0.0145874 1 osd.1 34 14 14 0.0145874 1 osd.2 31 7 7 0.0145874 1 osd.3 31 13 13 0.0145874 1 osd.4 30 14 14 0.0145874 1 osd.5 33 7 7 0.0145874 1 in 6 avg 32 stddev 1.41421 (0.0441942x) (expected 5.16398 0.161374x)) min osd.4 30 max osd.1 34 size 0 0 size 1 0 size 2 0 size 3 64

6 个 OSD 承载 64 个 PG,平均 32 个/PG,标准差 1.41421。注意此处c wt(CRUSH 权重 0.0145874)与wt(OSD 权重 1)不一致——CRUSH 权重低但 OSD 权重为 1 的情况,往往意味着设备存在容量差异或 CRUSH 权重被调整过,这正是需要 upmap 平衡器介入的场景。

4.4 模拟 upmap 活跃平衡器

osdmaptool --upmap upmaps.out --upmap-active --upmap-deviation 6 --upmap-max 11 osdmap

输出(来自原文档):

osdmaptool: osdmap file 'osdmap' writing upmap command output to: upmaps.out checking for upmap cleanups upmap, max-count 11, max deviation 6 pools movies photos metadata data prepared 11/11 changes Time elapsed 0.00310404 secs pools movies photos metadata data prepared 11/11 changes Time elapsed 0.00283402 secs pools data metadata movies photos prepared 11/11 changes Time elapsed 0.003122 secs pools photos metadata data movies prepared 11/11 changes Time elapsed 0.00324372 secs pools movies metadata data photos prepared 1/11 changes Time elapsed 0.00222609 secs pools data movies photos metadata prepared 0/11 changes Time elapsed 0.00209916 secs Unable to find further optimization, or distribution is already perfect osd.0 pgs 41 osd.1 pgs 42 osd.2 pgs 42 osd.3 pgs 41 osd.4 pgs 46 osd.5 pgs 39 osd.6 pgs 39 osd.7 pgs 43 osd.8 pgs 41 osd.9 pgs 46 osd.10 pgs 46 osd.11 pgs 46 osd.12 pgs 46 osd.13 pgs 41 osd.14 pgs 40 osd.15 pgs 40 osd.16 pgs 39 osd.17 pgs 46 osd.18 pgs 46 osd.19 pgs 39 osd.20 pgs 42 Total time elapsed 0.0167765 secs, 5 rounds

解读要点:

  • 每轮以pools <名称列表>开头,pool 顺序每轮随机打乱(源码中std::shuffle(pools.begin(), pools.end(), ...));
  • prepared X/11 changes表示本轮计算出的调整条目数;条目内容写入upmaps.out,形如ceph osd pg-upmap-items 1.7 142 147(参见 src/test/cli/osdmaptool/upmap.t);
  • 5 轮后某轮prepared 0/11,判定无法继续优化或分布已完美,随即打印每个 OSD 的最终 PG 数(20 个 OSD 均在 39~46 之间,最大差 7,已落在--upmap-deviation 6允许的偏离范围内);
  • 每个<file>输出可直接作为脚本在真实集群执行sh upmaps.out),这就是"先离线模拟、再线上执行"的平衡落地方式。

4.5 模拟读平衡(primary 平衡)

先确保容量已通过 upmap 模式平衡,再对副本池做读平衡:

osdmaptool osdmap --read read.out --read-pool <pool name>

输出(来自原文档):

./bin/osdmaptool: osdmap file 'om' writing upmap command output to: read.out ---------- BEFORE ------------ osd.0 | primary affinity: 1 | number of prims: 3 osd.1 | primary affinity: 1 | number of prims: 10 osd.2 | primary affinity: 1 | number of prims: 3 read_balance_score of 'cephfs.a.meta': 1.88 ---------- AFTER ------------ osd.0 | primary affinity: 1 | number of prims: 5 osd.1 | primary affinity: 1 | number of prims: 5 osd.2 | primary affinity: 1 | number of prims: 6 read_balance_score of 'cephfs.a.meta': 1.13 num changes: 5

BEFORE/AFTER 对比显示:primary 数从 3/10/3 调整为 5/5/6,read_balance_score从 1.88 降至 1.13,共 5 处调整,命令写入read.out。若输出 "Unable to find further optimization, or distribution is already perfect",则表示 primary 分布已无需优化。

五、与其他工具的分工与配合

  • ceph(8):在线管理集群的命令行入口,ceph osd pg-upmap等命令用于在运行中的集群上应用 upmap 调整;
  • crushtool(8):独立的 CRUSH Map 操作工具,可对osdmaptool --export-crush导出的文件做--decompile/--compile/--test等操作。两者常配合使用:先用--export-crush导出,再用 crushtool 离线验证 CRUSH 规则,或用crushtool --build构造新 CRUSH Map 后通过--import-crush导入(见 src/test/cli/osdmaptool/test-map-pgs.t 中crushtool --build --num_osds 500 node straw 10 rack straw 10 root straw 0构造 500 设备 CRUSH Map 再导入的用法)。

六、源码结构速览

  • 主程序:src/tools/osdmaptool.cc(985 行),涵盖参数解析、Map 构建、CRUSH 导入导出、PG 映射测试、upmap/read 平衡计算与输出;
  • OSD Map 核心类:src/osd/OSDMap.h 与 src/osd/OSDMap.cc,提供calc_pg_upmaps()balance_primaries()clean_pg_upmaps()calc_read_balance_score()等平衡算法实现;
  • CLI 回归测试:src/test/cli/osdmaptool 目录下的*.t文件,覆盖创建打印(create-print.t)、CRUSH 导入导出与权重调整(crush.t)、upmap 生成与持久化(upmap.t、upmap-out.t)、映射统计(test-map-pgs.t)、树形视图(tree.t)、pool 处理(pool.t)、覆盖保护(clobber.t)、参数缺失(missing-argument.t)等场景。

七、使用注意事项

  • --createsimple/--create-from-conf在目标文件已存在且未加--clobber时会拒绝覆盖;
  • --mark-up--mark-out--mark-in--adjust-crush-weight等修改默认不写回文件,只有显式--save(upmap/read 模式为--upmap-active--save)才会持久化并使 epoch 递增;
  • --upmap-deviation必须 ≥ 1;
  • --read仅支持副本池,--osd-size-aware仅对 read 模式生效且要求 pool 已配置read_ratio
  • 生成的 upmap/read 命令文件需要在真实集群中用ceph命令逐一执行,osdmaptool 本身不会连接集群;
  • 该工具用于离线分析、预演与脚本化测试,实际集群中的动态平衡由 mgr balancer 模块在线完成,两者共享同一套calc_pg_upmaps底层算法,因此离线模拟结果对线上有直接参考价值。
  • 存储
  • 分布式文件系统
  • 对象存储
  • 后端
  • 高可用

【免费下载链接】ceph

Ceph is a distributed object, block, and file storage platform

项目地址:https://gitcode.com/gh_mirrors/ce/ceph
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询