存储池&&PG及配置管理

11522 字
58 分钟
存储池&&PG及配置管理
存储池&&PG及配置管理

存储池 && PG及配置管理#

[TOC]


命令拆解#

Ceph 命令是”层级式”命名的,拆开看每个词就不需要死记:

Terminal window
ceph osd pool rm xixi xixi --yes-i-really-really-mean-it
│ │ │ │ │ │
│ │ │ │ │ └── "我真要这么干"池删除的最高级双重确认'两次 really'
│ │ │ │ └── 池名(要输两遍,防止手滑)
│ │ │ └── Remove 删除
│ │ └── 存储池(逻辑分区)
│ └── OSD 守护进程层
└── Ceph CLI 总入口
词含义记忆方法
cephCeph 集群 CLI 总入口所有命令都从这个开始
osdObject Storage Daemon存储相关操作(池、PG、CRUSH 都归这层管)
pool存储池,逻辑分区数据的”命名空间”,不同业务用不同池
pgPlacement Group 归置组数据分布的最小单位,一个 PG 里可放成千上万个对象
rmRemove 删除
create创建
get查单个属性精确==查询==某个参数值
set修改属性==修改==某个参数值
dump导出全部导出所有配置/规则,==常配合 grep 过滤==
show查看最终生效配置合并 Config DB + ceph.conf + 默认值
给出进程==实际==跑的配置
lsList 列出列出所有池 / 规则
config集中化配置数据库替代传统 ceph.conf,Monitor 集中存储
crushCRUSH 算法 / 拓扑表集群的”地图”——数据该往哪放
application池用途声明告诉集群这池是给 RBD / CephFS / RGW 用的
replicated副本池类型数据完整复制多份——==“一式三份”==
erasure纠删码池类型切块 + 校验块——“拼图 + 备用块”
pg_numPG 总数池里有多少个”调度组”
pgp_num参与数据放置的 PG 数多少个调度组实际在干活,≤ pg_num
size==副本数==数据一共存几份
min_size==最小副本数==I/O 服务需要的最少可用副本数
nodelete池级删除锁给某个池打上 true → 该池不可删除
mon_allow_pool_delete集群级删除开关Monitor 总闸,控制整个集群是否允许删池
pg_autoscale_modePG 自动伸缩Ceph 根据 OSD 数量和用量自动调整 PG 数
global==全局配置层==影响所有守护进程(mon/osd/mgr/mds/client)
mon / osd / mgr类型级配置 target只影响某一类守护进程
osd.0 / mon.Ceph-201==实例级==配置 target精确到某一个具体进程
--yes-i-really-really-mean-it“我真要这么干”(双重确认)删池的最高级确认,两个 really
--force跳过普通确认常规操作的安全确认

命令层级——越靠左越宏观,越靠右越具体:

Terminal window
ceph --> 集群层(管一切)
ceph osd --> OSD 层(管池、管 PG、管 CRUSH)
ceph osd pool --> 池层(管大小、管副本、管类型)
ceph config --> 配置层(管参数、管开关)
层面命令入口管的视角
OSD 数据层ceph osd ...CRUSH 地图、OSD 状态、池属性、PG 状态CRUSH 全局视角——“数据该往哪放”
配置管理层ceph config ...集中化配置数据库、参数读写Monitor 视角——“集群怎么跑”
Dashboard 层ceph dashboard ...Web 管理界面、用户权限图形化视角——“不想敲命令时用它”

存储池概述#

池(Pool)是个啥?#

🧱 池是 Ceph 里存储数据的逻辑分区,你可以把它理解成一个”命名空间”

  • 不同的业务(RBD 块存储、CephFS 文件系统、RGW 对象存储)各自用各自的池,井水不犯河水
池的核心作用大白话解释
逻辑分区给不同应用划地盘,互不干扰
数据保护指定==副本数==或==纠删码==,决定数据能坏几块盘还不丢
CRUSH 规则绑一条 CRUSH 规则控制数据分布
比如限定故障域或 OSD 的 class 标签(ssd/hdd/nvme)
访问控制权限按==池==粒度划分
Monitor 发证,OSD 验票,限定谁能读写这个池
快照管理对整个池做快照,出事了能回滚

数据存储流程对比#

我们最熟悉的是副本池的流程(参考之前的笔记📚),先用它过一遍,再对照看纠删码池

🔹 副本池流程(复习)—— 以 3 副本为例:

Terminal window
┌──────────────────────────────────────────┐
│ Step 1:文件 → 切成固定 4MB 对象 │
│ │
│ 100MB 照片 │
│ │ │
│ ▼ │
│ ┌──────┐┌──────┐┌──────┐ ┌──────┐ │
│ │ 4MB ││ 4MB ││ 4MB │ ... │ 4MB │ │
│ │ obj1 ││ obj2 ││ obj3 │ ×25 │ obj25│ │
│ └──────┘└──────┘└──────┘ └──────┘ │
│ '每个对象固定 4MB,不够就补齐' │
└──────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ Step 2:对象→Pool→命中某个 PG │
│ │
│ "对象名" + CRUSH Map ──→ PG.7 │
│ 'CRUSH①:决定对象归哪个 PG' │
└──────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ Step 3:PG → CRUSH 再算 → 副本落盘 │
│ │
│ PG.7(size=3,要放 3 份) │
│ │ │
│ ▼ 'CRUSH②:决定副本落哪几块盘' │
│ │ │
│ ├─→ 副本① → osd.1(host A) │
│ ├─→ 副本② → osd.4(host B) │
│ └─→ 副本③ → osd.7(host C) │
│ ⚠️ (故障域 = host) │
│ obj1 的 3 个副本,落在 3 台不同主机上 │
│ '读的时候随便找一个副本就能拿到完整数据' │
└───────────────────────────────────────────┘

📌 副本池的本质:一份数据原样 copy 好几份,写的时候多写几遍,读的时候读最近的那份就行


🔹 纠删码池流程 —— 以 6+3 为例:

Terminal window
'前面两步一模一样,差异在第三步'
│
▼
┌──────────────────────────────────────────────┐
│ Step 3:PG → 编码切块 → 分散落盘 │
│ │
│ PG.7 收到 obj1(4MB 对象) │
│ │ │
│ ▼ '不是直接 copy,而是先编码' │
│ │ │
│ 把 4MB 对象切成 6 个数据块 │
│ │ │
│ ├─→ 数据块① │
│ ├─→ 数据块② │
│ ├─→ 数据块③ k = 6 个数据块 │
│ ├─→ 数据块④ │
│ ├─→ 数据块⑤ │
│ └─→ 数据块⑥ │
│ │ │
│ ▼ '根据 6 个数据块算出 3 个校验块' │
│ │ │
│ ├─→ 校验块⑦ │
│ ├─→ 校验块⑧ m = 3 个校验块 │
│ └─→ 校验块⑨ │
│ │ │
│ ▼ 'CRUSH②:9 个块分散到 9 块盘上' │
│ │ │
│ ├─→ 块① → osd.1 ├─→ 块⑥ → osd.6 │
│ ├─→ 块② → osd.2 ├─→ 块⑦ → osd.7 │
│ ├─→ 块③ → osd.3 ├─→ 块⑧ → osd.8 │
│ ├─→ 块④ → osd.4 ├─→ 块⑨ → osd.9 │
│ └─→ 块⑤ → osd.5 │
│ 总共 k+m = 9 个块,散落在 9 块不同的盘上 │
│ ⚠️ 如果故障域是 host → 需要 9 台主机! │
│ 如果故障域是 osd → 9 块盘可以都在同一台主机上 │
│ '只要任意 6 块还在,数据就能算回来' │
└──────────────────────────────────────────────┘

📌 纠删码池的本质:数据不存整份,而是切成块 + 算出校验块,散开到更多盘上

  • 用 CPU + I/O 换空间
    • 具体差多少?往下看对比表格

🔹 读写路径对比 —— 关键差异一目了然:

Terminal window
🌰写路径:
副本池(3副本) 纠删码池(6+3)
obj1 ──→ copy 3 份 obj1 ──→ 切成6块+算3块
│ │
▼ ▼
直接写 3 块盘 编码后写 9 块盘
'写 3 次,简单粗暴' 'CPU 编码开销 + 写 9 次 I/O'
│ │
写放大:3x 写放大:1.5x
'4MB 对象占 12MB 磁盘' '4MB 对象只占 6MB 磁盘'
=====================================================
🌰读路径:
副本池(3副本) 纠删码池(6+3)
需要数据 ──→ 读最近的 1 个副本 需要数据 ──→ 读任意 6 块
│ │
▼ ▼
拿到完整数据 CPU 解码拼回数据
'读 1 次,秒返回' '读 6 次 I/O + CPU 解码'
│ │
延迟:低 延迟:高

存储池的两种类型#

类型英文名称原理类比
==副本池==replicated数据==完整复制==多份,每个副本放在不同 OSD 上RAID1(多副本)
==纠删码池==erasure数据切成 k 个==数据块== + 算出 m 个==校验块==
共 k+m 个块,散落在不同盘上
RAID5(校验码)

通俗解释:

  • 副本池就是”一式三份”——同一份数据 copy 到三块盘上,简单粗暴,坏两块盘都不怕
    • 缺点是废空间,3 副本 = 实际可用只有 1/3 的容量
  • 纠删码池像*“拼图+备用块”*——把数据切成 6 个数据块,再算 3 个校验块,总共 9 个块散落在 9 块盘上
    • 只要任意 6 块还在就能恢复完整数据,比副本省空间多了
对比维度副本池纠删码池
存储利用率低(3 副本 = 1/3)高(6+3 = 2/3)
CPU 开销低高(需要编码&解码运算)
I/O 延迟低较高(要读多个块才能拼回数据)
典型场景RBD 块设备、高性能场景RGW 对象存储、冷数据归档
最多能坏几块盘size-1 块(3副本最多坏2块)任意 m 块(6+3 最多坏 3 块)
6是数据块(k), 3是校验块(m)
Tip

📌 生产环境推荐用副本池,除非你对容量极度敏感且能接受性能损耗


PG 概述#

什么是PG#

Ceph 存数据的过程:对象 → Pool → PG → OSD

💡 OSD 是什么? OSD 本质上是一个进程 + 一块盘

说 osd.0 就是指 /dev/sda 上的那个守护进程,说”数据写到 osd.3”就是写到 osd.3 背后的那块物理盘上

后面讲的 peering、backfill、磁盘 I/O,都是在说 OSD 进程在操作它背后的那块盘

Terminal window
Object(对象) --CRUSH①--> Pool 下的某个 PG --CRUSH②--> OSD 集合

📌 CRUSH 在数据落地过程中用了两次:

  • 第一次负责逻辑分组(对象归哪个 PG)
  • 第二次负责数据落盘(PG 的副本落哪几块盘)

PG 数量#

📌 ==官方公式==:

Terminal window
OSD 数量 × X
PG = ---------------
pool 的 size(副本数)
X = 每块 OSD 期望承载的 PG 数量,官方推荐 100 左右

🧱 这个公式到底在算什么?

核心逻辑:先定每块 OSD 背多少个 PG 合理,再反推池里该建多少个 PG

Terminal window
# PG 均匀散落在 OSD 上:
PG 总数 × size
每块 OSD 背的 PG 数 = ---------------
OSD 数量
# 反过来,已知每 OSD 期望背 X 个 PG,求 PG 总数:
OSD 数量 × X
PG 总数 = ---------------
size

PG 总数太多还是太少?

PG 总数后果
太少数据分布不均,个别 OSD 成为”热点”,忙的忙死闲的闲死
太多PG 元数据膨胀,peering(互相同步状态) / scrub (校验数据一致性)开销暴增,CPU 和内存吃紧
  • 公式里塞 X=100 就是为了让 PG 总数落在适中区间

    • X 是 100,范围是 100~250 之间

    • 100 偏低偏安全,想多分一些 PG 可以把 X 调大到 200,但不能超过 250(会被 Monitor 拦住)

  • Ceph 的 mon_max_pg_per_osd 默认上限是 250

回到公式——代入算一下:

Terminal window
示例①:9 块 OSD,3 副本
9 × 100
PG = --------- = 300 → 取最近的 2 次方 → 256
3
'验证:256 × 3 / 9 = 每 OSD 约 85 个 PG'
示例②:200 块 OSD,3 副本
200 × 100
PG = ----------- ≈ 6666 → 取最近的 2 次方
3
2^12 = 4096 ← 差 2570
2^13 = 8192 ← 差 1526(更近)
∴ 集群 PG 总量取 2^13 = 8192 比较合理
'验证:8192 × 3 / 200 = 每 OSD 约 123 个 PG,仍在合理范围'

💡 结果取最近的 2 的幂(方便数据均匀分布)

算完后顺手验一下(X的值):PG总数 × size ÷ OSD数 是否在 100~250 之间


size VS min_size#

这两个参数是副本池容错的核心

参数含义生产推荐值
size
==副本数==
数据一共存几份(包含原始那份)≥ 3
min_size
==与最小副本数==
I/O 服务需要的最少可用副本数size - 1(如 3 副本时设为 2)

工作机制:

  • 集群正常时,所有 size 个 OSD 上的数据一致
  • 坏一块盘,剩余副本 ≥ min_size → I/O 照常跑
  • 剩余副本 < min_size → 池暂停 I/O 或只读,优先保数据一致性,宁可停服也不丢数据

💡 这就是 Ceph 的”宁死不屈”机制——数据安全比服务可用性更重要

Terminal window
🌰实战:把 3 副本改成 5 副本,同时提高 min_size
1)查看PG状态
root@Ceph-201 ~# ceph pg stat
1 pgs: 1 active+clean; 449 KiB data, 284 MiB used, 5.3 TiB / 5.3 TiB avail
root@Ceph-201 ~# ceph pg dump
'所有 PG 详细状态'
version 1287
stamp 2026-05-26T03:38:21.766113+0000
last_pg_scan 0
................
2)查看默认池现有规则
root@Ceph-201 ~# ceph osd pool ls detail
pool 1 '.mgr' replicated size 3 min_size 2
'可以查看指定的参数' # get 池子 key
root@Ceph-201 ~# ceph osd pool get .mgr size
size: 3
root@Ceph-201 ~# ceph osd pool get .mgr min_size
min_size: 2
3)修改规则
root@Ceph-201 ~# ceph osd pool get .mgr pg_autoscale_mode
pg_autoscale_mode: on
'如果开着 autoscale_mode,系统可能在你手动改完 pg_num 后立刻又给调回去'
# 我们在后面存储池管理中详细介绍这个选项
root@Ceph-201 ~# ceph osd pool set .mgr size 5
set pool 1 size to 5
root@Ceph-201 ~# ceph osd pool set .mgr min_size 3
set pool 1 min_size to 3
root@Ceph-201 ~# ceph osd pool ls detail
pool 1 '.mgr' replicated size 5 min_size 3 crush_rule 0
# 改成 5 副本后可以容忍任意 2 块盘故障(5-3=2),但代价是容量利用率更低

Peering 与 Backfill 详解#

Peering —— PG 状态协商#

🧱 前置概念:acting set 与 up set

在理解 peering 之前,先搞清楚 PG 里的 OSD 是怎么组织的

CRUSH 算法为每个 PG 算出一个 OSD 列表,指明该 PG 的副本应该落在哪几块盘上——这个列表就是 acting set

🌰 比如 PG.7 的 acting set = [OSD.0, OSD.1, OSD.2],意思是这个 PG 的 3 个副本(size=3)应分别存放在 OSD.0、OSD.1、OSD.2 三块盘上

🧱 主 OSD(Primary)

acting set 中的第一个 OSD 被指定为 主 OSD(Primary),其余为副本 OSD

角色谁干什么
主 OSDacting set 的第一个接收客户端读写请求、将写操作同步到副本、驱动 peering / recovery / backfill
副本 OSDacting set 的其余位置被动响应主 OSD 指令,同步数据、响应 log 查询

🌰 PG.7 的 acting set = [OSD.0, OSD.1, OSD.2] → OSD.0 是主,OSD.1 / OSD.2 是副本

正常情况下,还有一个 up set(当前实际在干活的 OSD 列表),两者保持一致:up set = acting set


🧱 Peering 是什么?

PG 的 acting set 里的 OSD 之间互相沟通、协商状态,达成共识——谁有最新数据、谁落后了、日志进度对齐到哪了

Tip

⚠️ 注意:PG 本身是逻辑实体,不干活

peering 的实际执行者是 acting set 里的 OSD 进程,==由主 OSD 牵头==、副本 OSD 响应——本质上就是这几个 OSD 在替这个 PG “对账”

📌 通俗理解:peering 就像三个副本”开会”

  • “你到哪了?我写到 log 第 100 条了""我才到 95,等我补一下”
  • 先把状态对齐,再决定下一步动作

什么时候会触发 peering?

触发场景说明
OSD 挂了又恢复它上面的 PG 落后了,需要和同伴对账
PG 数量变化pg_num / pgp_num 变了,PG 哈希边界重划,全部 PG 重新 peering
OSD 增删CRUSH 重新分配 PG 到不同 OSD
集群重启所有 PG 从零开始协商状态

Peering 的过程(简化版)

💡 一句话:说”PG.7 在 peering”和”主 OSD 在替 PG.7 peering”是同一件事

PG 是逻辑实体不干活,peering 由 acting set 里的 OSD 进程实际执行

Terminal window
PG.7 的 acting set = [OSD.0, OSD.1, OSD.2]
OSD.0 = 主 OSD(Primary)
其余 OSD 为副本 OSD,只被动响应主 OSD 的指令
═══════════════════════════════════════
Step 1: '主 OSD' 发起 peering 请求
┌─────────────────────────────────────┐
│ OSD.0 (Primary) │
│ │ │
│ │ PG.7 peering 报一下你们的 │
│ │ PG Log 最后一条序号 │
│ │ │
│ ├──────→ OSD.1 ──→ 回复: log #100 │
│ └──────→ OSD.2 ──→ 回复: log #98 │
└─────────────────────────────────────┘
Step 2: 确定权威日志(Authoritative Log)
┌─────────────────────────────────────┐
│ Primary 对比三份 log: │
│ OSD.0: #100 (自己就是最新的) │
│ OSD.1: #100 ✅ 一致 │
│ OSD.2: #98 ❌ 落后 2 条 │
│ │
│ 权威日志 = OSD.0 的 log │
│ 原则:挑最完整的一份 │
│ │
│ ⚠️ 前提:被选中的 log 必须连续、 │
│ 且属于当前 PG epoch——防止网络分区后 │
│ # PG epoch 每届政府的任期号,只增不减 │
│ 旧主带着"过期最长 log"回来造成脑裂 │
└─────────────────────────────────────┘
Step 3: 状态判定——该走哪条恢复路径?
┌─────────────────────────────────────┐
│ OSD.2 只差 2 条 log │
│ → 走 recovery(增量恢复) │
│ → OSD.2 回放缺失的 log 条目即可 │
│ │
│ 如果 OSD.2 整个 PG 目录都丢了 │
│ → 走 backfill(全量回填) │
└─────────────────────────────────────┘

📌 peering 本身不搬数据,只是协商状态 + 决定恢复策略

数据搬运是 recovery 或 backfill 的事

🧱 PG Log vs 实际数据

peering 过程中反复提到的”PG Log”到底是什么?跟用户存的数据是一回事吗?

Terminal window
PG Log(操作日志) 实际数据(对象内容)
───────────────────────── ─────────────────────
记录"发生过什么修改操作"(写/删/改/克隆等) 用户存的东西本身
比如: 比如:
#98 write obj15 obj15 = 4MB(照片的第 3 个分片)
#99 delete obj8 obj1 = 4MB(文档的第 1 个分片)
#100 modify obj3 obj3 = 4MB(视频的第 5 个分片)
像一个"记账本" 像一个"仓库"
peering 对账本 → 轻量,秒级完成 scrubbing 翻仓库逐件盘点 → 重,费 I/O

📌 这就是为什么 peering 能几百个 PG 同时做(只对日志条目,几乎不碰磁盘)

而 backfill / recovery 要限流(搬实际数据),scrubbing 也要限速(逐字节读副本比对,同样是重 I/O)

为什么 peering 多了会”风暴”?

每个 PG peering 时,acting set 里的 OSD 要来回发消息

关键前提:一块 OSD 上托管着很多 PG(按官方推荐 ~100 个),每个 PG 的 acting set 都可能包含这块 OSD

Terminal window
1 个 PG peering:
只有这 1 个 PG 的 acting set 里那几块 OSD 在通信 → 轻量,秒级完成
100 个 PG 同时 peering:
每块 OSD 上托管着 ~100 个 PG,这 100 个 PG 的 peering 砸过来,
一块 OSD 可能同时卷入几十个 PG 的协商:
→ OSD 进程的消息队列堆成山
→ Monitor 心跳超时
→ PG 被标记为 down / stale(误伤!)

这就是前面说的 peering 风暴——不是 peering 本身开销大,而是几百个 PG 同时 peering 时,OSD 的消息处理能力被打穿


Backfill —— 全量数据回填#

🧱 Backfill 是什么?

当某个 OSD 上整个 PG 的数据需要从头同步时,Ceph 不走逐条 log 回放(recovery:增量恢复),而是直接扫描并全量拷贝 PG 的所有对象——这就是 backfill

  • recovery(增量恢复) = 差几条 log,逐条追

  • backfill = 整个 PG 都要搬,全量拷

什么时候走 backfill 而不是 recovery?

场景走哪条路原因
OSD 短暂挂了又回来,只差几条 logrecovery增量补就行
新 OSD 加入集群,上面啥数据都没有backfill全量搬
PG 扩容,PG 被分配到之前未托管过它的 OSDbackfill该 OSD 上没有这个 PG 的存量数据,只能全量搬
OSD 永久替换(盘坏了换了块新的)backfill从零开始

Backfill 的过程

和 peering 一样,backfill 也是由主 OSD 驱动的——主 OSD 扫描 ==该PG== 落在自己盘上的所有对象,全量推送给目标 OSD

Terminal window
场景:OSD.3 是新加入的盘,PG.7 被 CRUSH 分配到了它上面
PG.7 acting set = [0, 1, 2] → OSD.3 加入后 → [0, 1, 3]
┌──────────────────────────────────────────────┐
│ 主 OSD (OSD.0) │
│ PG.7 目录: │
│ ├── obj1 (4MB) │
│ ├── obj8 (4MB) │
│ ├── obj15 (4MB) │
│ └── ... (共 10000 个对象,约 40GB) │
└──────────┬───────────────────────────────────┘
│
│ Backfill:全量顺序扫描 & 推送
│
▼
┌──────────────────────────────────────────────┐
│ OSD.3 (新盘,PG 目录为空) │
│ │
│ backfill 进度: │
│ ████████████░░░░░░░░ 67% (6.7K / 10K obj) │
│ │
│ 磁盘写 I/O 持续拉满 │
└──────────────────────────────────────────────┘
同时,OSD.2 上的旧副本被标记为"待清理"(PG 成员变了)

为什么 backfill 不能太多并发?

先理解一个前提:backfill 的每一步——从源 OSD 读对象、写到目标 OSD——本质上都是磁盘顺序 I/O

  • 这里的磁盘,就是指 OSD 背后的那块物理盘
Terminal window
🌰 单个 PG backfill 时(比如 PG.7):
源 OSD 上 PG.7 的对象在磁盘上是连续存放的
→ 磁头从 A 位置一路扫到 B 位置,一口气读完
→ 这是"顺序读"——磁头几乎不用跳,速度极快

一块盘上托管着几十上百个 PG,它们的对象各自占据不同的物理区域

当多个 PG 同时 backfill 时:

Terminal window
❌ 50 个 PG 同时 backfill 在同一块盘上:
磁盘被要求同时服务 PG.1、PG.7、PG.3... 的数据
原本每个 PG 都是"一口气读完"的顺序 I/O,
现在被搅在一起,磁头在不同 PG 的区域之间反复横跳
→ 顺序 I/O 退化成随机 I/O
→ 大量时间浪费在"寻道"上,实际读数据的时间占比暴跌
→ 吞吐量断崖式下跌,业务读写也被挤占

📌 核心:一块盘同一时间只做一件事(读或写某个 PG 的数据)效率最高,让它同时干好几件,磁头来回跳,总产出反而骤降


Peering → Recovery → Backfill 关系图#

Terminal window
OSD 挂掉 / PG 变化 / 集群事件
│
▼
┌─────────┐
│ Peering │ ← 先协商,搞清楚"谁有、谁缺、缺多少"
└────┬────┘
│
▼
PG Log 差得少?──── 是 ──→ Recovery(增量回放 log)
│ │
否 ▼
│ 恢复完成 → active+clean
▼
Backfill(全量扫描 & 拷贝对象)
│ '扫描 = 主 OSD 读自己的盘'
│ '拷贝 = 写到目标 OSD 的盘'
▼
恢复完成 → active+clean

📌 一句话:peering 是”对账”,recovery 是”打补丁”,backfill 是”重装系统”。


PGP 是什么#

PGP = Placement Group for Placement,即”用于数据放置的 PG 数量”

🧱 pg_num 和 pgp_num 的区别:

参数干什么的通俗理解
pg_num池里创建多少个 PG池里有多少个”调度组”
pgp_num多少个 PG 参与数据分布有多少个调度组实际在干活

📌 pgp_num ≤ pg_num,通常两者保持相等


🧱 为什么需要 pgp_num?——安全扩容的”调速阀门”

  • 如果把 pg_num 和 pgp_num 同时拉满,集群瞬间要对所有已有数据重新分布
    • 全部 PG 同时 peering,==新PG== 集中 backfill,I/O 直接被打穿

pgp_num 就是调速阀门:pg_num 决定有多少个 PG 存在,pgp_num 决定其中多少个真正在干活

安全扩容三步走:

Terminal window
1) 扩大 pg_num → 只创建新 PG 的数据结构,不实际迁移数据
2) 逐步调大 pgp_num → 每次只搬迁一部分 PG,集群平稳过渡
3) pgp_num 对齐 pg_num → 全部 PG 正常参与数据分布

📌 pgp_num 分步的本质是”限流”——让 PG 分批 peering + backfill,而非全部 PG 同时搅动

最终搬的数据总量差不多,但每批只扰动一部分 PG,集群始终保持可服务状态


🧱 为什么分步调能奏效?——回头看 peering 和 backfill

维度peering 风暴backfill 并发
瓶颈在哪OSD 消息队列 / CPU磁盘 I/O 带宽
什么感觉PG 假死(被误标 down/stale)业务 I/O 卡顿、延迟飙升
怎么控pgp_num 分步,减少同时 peering 的 PG 数pgp_num 分步 + osd_max_backfills 限速

💡 Ceph 默认 osd_max_backfills = 1(一次只回填 1 个 PG),就是怕 backfill 把磁盘打穿


⚠️ 生产环境:pg_num 和 pgp_num 最终必须等齐,否则新 PG 不参与数据放置

但不要一次同步拉满——先调 pg_num,再逐步放大 pgp_num,每步确认集群 active+clean 后再继续

Terminal window
root@Ceph-201 ~# ceph osd pool get .mgr pg_num
pg_num: 1
root@Ceph-201 ~# ceph osd pool get .mgr pgp_num
pgp_num: 1
'两者通常保持相等'
✅️ 使用 set 进行调整

临时PG#

主 OSD 挂了怎么办❓️

CRUSH 会重新算 acting set,但 ==新主OSD== 上还没数据——此时需要一个==过渡机制==,这就是临时 PG

概念谁定的什么时候变一句话
acting setCRUSH 计算PG 数变化、OSD 增删“应该在哪”
up setMonitor 根据 OSD 存活状态实时调整OSD 挂掉/恢复“实际在哪”

📌 正常情况 acting set = up set

当主 OSD 挂了,acting set 里换了新人但新人还没数据,up set 就让有数据的老人先顶班

acting set 和 up set 暂时不一致,这就是临时 PG

Terminal window
正常状态:
PG.7 的 acting set = [0, 1, 2]
up set = [0, 1, 2] ← 与 acting set 一致
OSD.0 = 主 OSD
────────────────────────────────────────
Step 1:OSD.0 故障
────────────────────────────────────────
CRUSH 重新计算 → acting set = [3, 1, 2]
OSD.3 被推举为新主 OSD,但盘上空空,还不能接读请求
────────────────────────────────────────
Step 2:申请临时 PG
────────────────────────────────────────
PG 向 Monitor 申请过渡方案
OSD.1(原副本,有最新数据)升任"临时主 OSD"
→ up set = [1, 3, 2] ← '临时干活阵容'
→ acting set = [3, 1, 2] ← CRUSH 的目标阵容(不变)
⚠️ acting set ≠ up set(过渡期不一致)
────────────────────────────────────────
Step 3:backfill 回填数据
────────────────────────────────────────
临时主 OSD.1 将 PG.7 数据全量推给 OSD.3
────────────────────────────────────────
Step 4:恢复正常
────────────────────────────────────────
OSD.3 数据同步完毕 → 临时 PG 取消
up set 恢复 = acting set = [3, 1, 2]
OSD.3 正式就任新主 OSD

PG 状态#

PG 状态是判断集群数据分布是否健康的关键指标

日常只需重点关注 active + clean,其余都是过渡状态。

状态含义归类
active能正常处理读写✅ 理想
clean所有副本齐全且内容一致
—> 没有缺失和待修复的副本
✅ 理想
Tip

上面两个同时出现(active+clean)= 一切正常

状态含义归类
peeringOSD 之间对 PG Log,协商谁最新谁落后 → 决定恢复策略
—> 对的是操作日志,不是数据本身
==对账==
recovering逐条回放 PG Log,差多少补多少 → “打补丁”==增量恢复==
backfill全量扫描该 PG 对象,从头拷贝到新 OSD → “重装系统”==全量恢复==
wait-backfill排队等 backfill(受 osd_max_backfills 限制)
—> 默认一次只回填 1 个 PG
限流
backfill-toofull目标 OSD 使用率超阈值,backfill 挂起⚠️ 阻塞

peering → 决定走 recovering 还是 backfill → ✅️ 完成 → active+clean

状态含义归类
remappedacting set ❌️≠❌️ up set,PG 正由临时阵容代管 → ==临时 PG==🔄过渡
creatingPG 正在创建一次性
splittingPG 数量扩容,正在分裂一次性
replayOSD 崩溃后,PG 在等待客户端重放未确认操作🔄过渡
状态含义归类
scrubbing逐字节比对副本的==实际数据==,发现静默损坏(bit rot)
—> peering 是对 PG Log,scrub 是对数据本身
后台巡检
repairscrubbing 发现不一致 → 用正确副本覆盖损坏副本后台修复

异常 / 降级状态:

状态含义
degraded部分副本挂掉或落后,但剩余副本 ≥ min_size,还能接 I/O
undersized当前可用副本数少于 size,但 ≥ min_size
down该 PG 必要的数据副本全部不可达,PG 下线
incompletePG 缺少关键信息(如日志断层),无法判断数据是否安全
inconsistentscrubbing 检测到副本间实际数据不一致 → 触发 repair
stalePG 所在 OSD 长时间没向 Monitor 报心跳,Monitor 不知道它什么状态
inactivePG 不能处理读写,等待持有最新数据的 OSD 回来
unclean有对象副本数不达标(与 clean 相反),通常正在恢复中
peeredpeering 已完成(状态协商好了),但副本还没补够,暂不接客
Important

遇到 PG 异常的常规思路:

  1. 重启相关 OSD 服务
  2. 调整属性参数
  3. 重置 PG

PG管理#

Terminal window
1)查看pg整体状态
root@Ceph01 ~# ceph pg stat
# 简洁状态(PG数量、状态、数据量、IO)
649 pgs: 649 active+clean; 92 MiB data, 685 MiB used, 179 GiB / 180 GiB avail; 341 B/s rd, 0 op/s
2)查看特定池子的 PG 列表
# 列出指定池子的所有PG
root@Ceph01 ~# ceph pg ls-by-pool kpyun
root@Ceph01 ~# ceph pg ls-by-pool kpyun | awk '{print $1,$2,$16}'
# 只显示PG ID、对象数、ACTING OSD
PG OBJECTS ACTING
2.0 4 [3,6,9]p3
'2.0 中的 2 是 池子的 ID(pool ID),0 是 该池子内的 PG 序号(shard index),从 0 开始编号'
2.1 5 [9,8,5]p9
2.2 6 [5,9,8]p5
...
3)查看特定 OSD 上的 PG
root@Ceph01 ~# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.17574 root default
-3 0.05858 host Ceph01
1 hdd 0.00980 osd.1 up 1.00000 1.00000
2 hdd 0.01949 osd.2 up 1.00000 1.00000
.......
root@Ceph01 ~# ceph pg ls-by-osd osd.1
# 列出某个OSD上的所有PG
root@Ceph01 ~# ceph pg ls-by-primary osd.1
# 列出以某OSD为主副本的PG
4)查看单个 PG 的详细信息(含状态、OSD映射、副本分布等)
`2.0 是 PG ID`
root@Ceph01 ~# ceph pg map 2.0
# 查看PG到OSD的映射
osdmap e501 pg 2.0 (2.0) -> up [3,6,9] acting [3,6,9]
root@Ceph01 ~# ceph pg 2.0 query
# 查询PG的详细统计信息(含副本状态、日志等)
{
"snap_trimq": "[]",
"snap_trimq_len": 0,
"state": "active+clean",
"epoch": 501,
"up": [
3,
6,
9
],
"acting": [
3,
6,
9
],
"acting_recovery_backfill": [
"3",
"6",
"9"
] .......

存储池管理#

Terminal window
1)创建副本存储池(默认类型)
root@Ceph-201 ~# ceph osd pool create xixi replicated
pool 'xixi' created
⚠️ '默认不指定池子类型 --> 就是副本池' --> replicated
2)创建纠删码存储池
root@Ceph-201 ~# ceph osd pool create haha erasure
pool 'haha' created
3)查看存储池列表
root@Ceph-201 ~# ceph osd pool ls
.mgr
xixi <-- ✅️ 副本池
haha <-- ✅️ 纠删池
👆 '这两个是我们刚创建的'
# 我们再加一个选项 detail
root@Ceph-201 ~# ceph osd pool ls detail
'查看存储池详细信息🔍'
pool 1 '.mgr' replicated size 3 min_size 2 crush_rule 0 📌 'crush规则0'
pool 2 'xixi' replicated size 3 min_size 2 crush_rule 0 📌 'crush规则0'
pool 3 'haha' erasure profile default size 4 min_size 3 crush_rule 1 📌 '规则1'
==========================================================
root@Ceph-201 ~# ceph osd crush rule ls
"有哪些规则" --> 📌 只列出名字
replicated_rule
erasure-code
'很明显一个是副本池默认的crush规则, 另一个是纠删码池的默认crush规则'
# 创建crush规则参考之前的笔记📚
🌰 副本规则 `create-replicated`
🌰 纠删码规则 `create-erasure`
✅️ ceph osd crush rule dump <规则名>
"这条规则内部长什么样" --> 📌 完整 JSON
# 查看故障域详细的规则规则
✅️ ceph osd pool set <存储池名称> <参数名> <参数值>
# 关联存储池到新规则
4)查看创建池子的pg和pgp数
✅️ '查看单个池的指定属性'
'默认相同' --> 32 = 2的5次方
# Ceph 会根据集群 OSD 数量和池的用量,自动计算并动态调整 PG 数量
📌 我们创建池子的时候,并没有指定pg数 ❌️ --> 生产环境一定要指定
root@Ceph-201 ~# ceph osd pool get xixi pg_num
pg_num: 32
root@Ceph-201 ~# ceph osd pool get xixi pgp_num
pgp_num: 32
root@Ceph-201 ~# ceph osd pool get haha pg_num
pg_num: 32
root@Ceph-201 ~# ceph osd pool get haha pgp_num
pgp_num: 32
命令查看维度一句话
rados df池“每个池用了多少、剩多少,按池算账”
ceph osd dfOSD 设备“每块盘用了多少、剩多少,按盘摸底”
Terminal window
5)查看存储池利用率
root@Ceph-201 ~# rados df
POOL_NAME USED OBJECTS CLONES COPIES ....
.mgr 1.3 MiB 2 0 6 ....
haha 0 B 0 0 0 ....
kpyun 0 B 0 0 0 ....
xixi 0 B 0 0 0 ....
'📌 重点在下面的统计'
total_objects 2
total_used 285 MiB
total_avail 5.3 TiB
total_space 5.3 TiB
root@Ceph-201 ~# ceph osd df
ID CLASS WEIGHT REWEIGHT SIZE AVAIL %USE PGS STATUS
0 hdd 0.293 1.000 300 GiB 300 GiB 0.01 44 up
1 hdd 0.488 1.000 500 GiB 500 GiB 0.01 58 up
...........
6)重命名存储池
root@Ceph-201 ~# ceph osd pool rename haha hehe
pool 'haha' renamed to 'hehe'
root@Ceph-201 ~# ceph osd pool ls | grep hehe | wc -l
1
7)查看 Ceph RADOS 存储池里的对象列表
root@Ceph01 ~# rados -p kpyun ls
# 列出池中所有对象
rbd_data.170e2ce99ffd4.00000000000003ff
rbd_data.* # RBD 镜像的数据对象(实际存储数据块)
rbd_id.server 🔥
rbd_id.* # 镜像的唯一标识符(就是镜像名称)
......
8)查看存储池的镜像名称
root@Ceph01 ~# rados -p kpyun ls | grep rbd_id
rbd_id.server02
rbd_id.server
root@Ceph01 ~# rbd -p kpyun ls
server 🔥
server02
root@Ceph01 ~# rbd info kpyun/server
rbd image 'server':
size 5 GiB in 1280 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 170e2ce99ffd4
block_name_prefix: rbd_data.170e2ce99ffd4 🔥 对应 rbd_data 的前缀
# 先查 ID,再列出所有相关数据对象
root@Ceph01 ~# rados -p kpyun get rbd_id.server - ;echo
170e2ce99ffd4 `和上面的输出一模一样`
root@Ceph01 ~# rados -p kpyun ls | grep rbd_data.170e2ce99ffd4
rbd_data.170e2ce99ffd4.00000000000003ff
rbd_data.170e2ce99ffd4.0000000000000300
rbd_data.170e2ce99ffd4.0000000000000100
9)对象映射的数据
root@Ceph01 ~# ceph osd map kpyun rbd_data.170e2ce99ffd4.00000000000003ff
osdmap e503 pool 'kpyun' (2) object 'rbd_data.170e2ce99ffd4.00000000000003ff' -> pg 2.4ab8ea10 (2.0) -> up ([3,6,9], p3) acting ([3,6,9], p3)
对象名称
↓ CRUSH 哈希算法
PG 2.0(4ab8ea10 是哈希后的 PG 编号)
↓ CRUSH 规则
OSD [3, 6, 9](3副本,p3 表示主副本在 OSD 3)
Terminal window
7)创建时指定 PG 数量和关闭自动伸缩
root@Ceph-201 ~# ceph osd pool get .mgr pg_autoscale_mode
pg_autoscale_mode: on
'系统池这个选项是开着的 --> 系统可能在你手动改完 pg_num 后立刻又给调回去'
root@Ceph-201 ~# ceph osd pool create kpyun 128 128 --autoscale_mode off
✅️ 128 128 = pg_num 128, pgp_num 128

📌 自动伸缩(pg_autoscale_mode)是什么?

Ceph 会根据集群 OSD 数量和池的用量,自动计算并动态调整 PG 数量

如果开着 autoscale,系统可能在你手动改完 pg_num 后立刻又给调回去


为什么创建时关掉它? 既然你手动指定了 128 个 PG,就说明你算好了PG数量了

  • --autoscale_mode off 告诉 Ceph “PG 数量我来定,你别插手”

同理,后续用 set 修改 pg_num 前也需要先关 autoscale

Terminal window
'我在创建这个池子的时候,默认不指定池的类型 --> 副本池'
root@Ceph-201 ~# ceph osd pool ls detail | grep kpyun
pool 4 'kpyun' replicated size 3 min_size 2 crush_rule 0
root@Ceph-201 ~# ceph osd pool get kpyun pg_num
pg_num: 128
root@Ceph-201 ~# ceph osd pool get kpyun pgp_num
pgp_num: 128
'这次都是128 --> 而不是32'

📌 Ceph 的逻辑:⚠️ 创建一个池之后务必声明它的用途

否则 Monitor 不知道这个池是存 RBD 镜像还是当 CephFS 元数据池,持续报 HEALTH_WARN ❌️

类型业务一句话
rbd==块存储==“这池子给虚拟机/云盘用的”
cephfs==文件系统==“这池子给共享文件存储用的”
rgw==对象存储==“这池子给 S3 / Swift 对象网关用的”
Terminal window
root@Ceph-201 ~# ceph -s | grep -A2 health
health: HEALTH_WARN ❌️
Degraded data redundancy: 6 pgs undersized
3 pool(s) do not have an application enabled
📌 集群里有 3 个池子还没声明"我是干啥用的"
1)声明用途
✅️ ceph osd pool application enable <池名> <类型>
root@Ceph-201 ~# ceph osd pool application enable kpyun rbd
2)查看已声明的用途
✅️ ceph osd pool application get <池名>
root@Ceph-201 ~# ceph osd pool application get kpyun
{
"rbd": {}
}

删除存储池的两道锁#

Ceph 为了保护数据不被人手滑删掉,设计了两道锁:

Terminal window
机制一:nodelete 标记(池级锁)
给'某个存储池'打上 nodelete=true → 该池不可删除 ❌️
'默认值':false(可删除)✅️
机制二:mon_allow_pool_delete 全局开关(集群级锁)
Monitor 级别的总闸,📌'控制整个集群是否允许删池'
'默认值':false(不允许删除)❌️
⚠️ 两道锁都有一票否决权 --> 任一不通过都不能删池
锁允许删除的条件默认值默认能删吗
nodelete(池级)falsefalse✅ 能
mon_allow_pool_delete(集群级)truefalse❌ 不能

📌 实际删池时,nodelete 默认就是 false(没上锁),真正卡住你的是全局开关 mon_allow_pool_delete

  • 所以实验里只需要翻这一道开关就够了
    • 不是只开了一个就能删,而是另一个本来就没关
  • 📌 生产环境建议:nodelete=true + mon_allow_pool_delete=false
    • 双重保险,防止手滑

ceph config 方式删除(推荐)#

Terminal window
'删除池的完整流程 —— ceph config 版'
1)强制删除试试
# 由于这是一个高风险操作,Ceph要求您提供更强的确认
1.需要输入两次存储池名称(xixi xixi)
2.使用 --yes-i-really-really-mean-it 参数
# 两次really强确认
root@Ceph-201 ~# ceph osd pool rm xixi xixi --yes-i-really-really-mean-it
Error EPERM: pool deletion is disabled; --> '删除失败' ❌️
"在删除存储池之前,您必须先将mon_allow_pool_delete配置选项设置为true"
2)检查 nodelete 标记
root@Ceph-201 ~# ceph osd pool get xixi nodelete
nodelete: false
'池级锁默认false --> 可以删除'
3)在 monitor 和 global 级别都开启允许删除
'global = 所有守护进程(mon/osd/mgr/mds/client),mon = 仅 Monitor'
# 实际上:设了 global,就完全不需要再设 mon
✅️ 老运维只认 mon, 后来 global 出现了,有些人就"两条都写上,求个心安"
root@Ceph-201 ~# ceph config set mon mon_allow_pool_delete true
root@Ceph-201 ~# ceph config set global mon_allow_pool_delete true
4)确认开关已生效
root@Ceph-201 ~# ceph config get mon mon_allow_pool_delete
true
root@Ceph-201 ~# ceph config get global mon_allow_pool_delete
Error EINVAL: unrecognized entity 'global'
'这是为什么??'
# global 不能用 get 查(不是具体守护进程类型),用 dump 来看
root@Ceph-201 ~# ceph config dump | grep mon_allow_pool_delete
ceph config dump # 导出所有配置项
global mon_allow_pool_delete true
mon mon_allow_pool_delete true
'global 和 mon 都 true,确认生效'
5)执行删除
root@Ceph-201 ~# ceph osd pool rm xixi xixi --yes-i-really-really-mean-it
pool 'xixi' removed
root@Ceph-201 ~# ceph osd pool ls | grep xixi | wc -l
0
6)安全收尾——关掉开关
root@Ceph-201 ~# ceph config set mon mon_allow_pool_delete false
root@Ceph-201 ~# ceph config set global mon_allow_pool_delete false

ceph config 配置管理#

Ceph 从 Squid 版本开始,引入了集中化配置数据库(Configuration Database),ceph config 命令是统一入口

传统 ceph.conf vs 配置数据库#

Terminal window
传统方式:'分散管理,一致性难保证'
1.N 个节点各存一份 `ceph.conf`
2.改配置 = 挨个 SSH 改文件,漏一台就不一致
---------------------------------------------
现代方式(Config DB):📌'Monitor 集中存储'
1.Monitor 内存着一份"配置总账"(存在 RocksDB 里)
2.你敲一条 `ceph config set` 写入总账,所有节点的守护进程自动拉取
3.一份数据,全集群读

💡 RocksDB 又是什么?

它是 Facebook 开源的一款嵌入式键值(Key-Value)数据库

非常轻量 —> 不需要单独部署服务,直接嵌在 Monitor 进程里跑,负责把==配置数据==持久化到磁盘上

Monitor 用它存两类东西:

  • ① 配置数据库(Config DB)

  • ② 集群 Map(OSD Map / PG Map / CRUSH Map 等)

说白了就是 Ceph 自己的”小账本”

优先级(由高到低):

① Config DB(ceph config set)→ ② ceph.conf 文件 → ③ 代码内置默认值

📌 最佳实践:日常运维优先用 ceph config 在线改,ceph.conf 仅作为静态补充或离线批量配置

常用命令#

命令说明
ceph config dump导出所有配置项
常配合grep过滤
ceph config get <target> <option>查配置——<target>
可以是类型级或实例级
ceph config set <target> <option> <val>设配置——<target>
可以是类型级或实例级
ceph config rm <target> <option>删除配置(同上)
ceph config show <target> <option>查看某个进程实际生效的配置
合并全部来源,给出最终生效值
ceph config assimilate-conf -i ceph.conf把老 ceph.conf 导入配置数据库
粒度例子
类型级 —> 影响==一类守护进程==mon / osd / mgr
实例级 —> 精确到一个具体进程osd.0 / mon.Ceph-201
Tip

💡 get / set / rm 的 <target> 可以是类型级(mon)也可以是实例级(mon.Ceph-201)

  • show 通常跟实例级,看某个==具体进程==实际跑的是什么配置
Terminal window
💡 守护进程命名规则:`type.id`
osd.0 → type.id
│ └── OSD 编号(Ceph 内部'守护进程编号',不是 Linux PID(重启会变))
└── 守护进程类型(mon / osd / mgr / mds / client)
`osd.0` = `osd` 类型的 `0` 号实例
📌 Monitor 用主机名当 ID(`mon.Ceph-201`),MDS 和 Manager 同理
Important

📌 global 是==虚拟赋值层==

  • 可以往里写(set),但往里读(get)就报 unrecognized entity❌️

  • 验证 global 是否生效用 ceph config dump | grep

取值层级影响范围setget
global==全局====所有守护进程==✅❌,用 dump 查
mon类型所有 Monitor✅✅
osd类型所有 OSD✅✅
mgr类型所有 Manager✅✅
mds类型所有 MDS✅✅
client类型所有客户端✅✅
osd.0==实例==仅 osd.0 这一个进程✅✅
mon.Ceph-201==实例==仅 Ceph-201 上的 Monitor✅✅
Terminal window
'实操示例'
1)查看 monitor 级别是否允许删池
root@Ceph-201 ~# ceph config get mon mon_allow_pool_delete
false
2)设置 monitor 级别配置
root@Ceph-201 ~# ceph config set mon mon_allow_pool_delete true
3)查看mon.Ceph-201的所有配置
'这里已经具体到某台主机了'
root@Ceph-201 ~# ceph config show mon.Ceph-201
NAME ALUE
debug_mon 20/20
keyring $mon_data/keyring
log_to_file false
public_network 10.0.0.0/24
................
✅️ '后面也可以跟某个具体配置'
root@Ceph-201 ~# ceph config show mon.Ceph-201 public_network
10.0.0.0/24
4)global全局配置
root@Ceph-201 ~# ceph config get gobal public_network
Error EINVAL: unrecognized entity 'gobal' ❌️
'需要配置 👇'
root@Ceph-201 ~# ceph config dump | grep public_network
global advanced public_network 10.0.0.0/24

Dashboard 速览#

Dashboard 是 Ceph 自带的 Web 图形化管理界面(端口 8443),不想敲命令的时候用它

Tentacle(v20)换了新 UI —— 首页改叫 Overview,界面更现代

🔹 Tentacle 新版主要功能:

功能一句话
多集群管理一个页面管好几个 Ceph 集群,不用来回切
统一看健康状态、容量、告警
NVMe 高速存储网页上配 NVMe 盘、分命名空间
对象存储(RGW)多活同步、冷热分层、过期删除、权限策略,全在页面上点
文件共享(SMB)Linux 上的 CephFS 当作 Windows 共享文件夹用
性能监控看磁盘读写速度、延迟、带宽趋势
统一登录(OAuth2)对接公司已有的账号系统,不用单独记密码
配置管理改副本数、改 PG 数、换 CRUSH 规则,不用敲命令
角色权限(RBAC)管理员、只读、块存储管理员、对象存储管理员…各看各的
Tip

📌 Tentacle 附带的监控组件:Prometheus 3.6 + Grafana 12 + Alertmanager 0.28

💡 生产环境别忘了把 Dashboard 的自签名证书换成正规 CA 签发的证书

内置角色:

角色能干啥一句话
administrator==全部权限==“超级管理员,什么都能动”
read-only只能看“参观者,点不坏任何东西”
block-managerRBD 块设备“管虚拟机云盘的”
rgw-manager对象网关“管 S3 存储桶的”
cephfs-manager文件系统“管共享目录的”
ceph dashboard 命令干什么
ac-user-create <用户名> -i <密码文件> <角色>创建用户
ac-user-show <用户名>查看用户信息
ac-user-set-password <用户名> -i <密码文件>修改密码
ac-user-set-roles <用户名> <角色>修改角色
ac-user-delete <用户名>删除用户
Terminal window
📌 复杂的操作上 Web 界面点,命令行记住👆上面 5 条够用了
'实例'
1)创建管理员用户 jiu,密码从文件读入
root@Ceph-201 ~# echo 'Redhat123.com' > /root/passwd.txt
⚠️ 防止 Password is too weak❌️ --> ✅️ '密码设置复杂一点'
root@Ceph-201 ~# ceph dashboard ac-user-create jiu -i /root/passwd.txt administrator
✅️ 刚创建的同时,把用户信息也打印出来了
{"username": "jiu", "password": "$2b$12$xn ...xxx", "roles": ["administrator"]

Terminal window
2)查看 admin 用户信息
root@Ceph-201 ~# ceph dashboard ac-user-show admin
✅️ 是admin用户呀!
{"username": "admin", "password": "$2b$12$Vq..xxx"
3)修改 jiu 的密码
root@Ceph-201 ~# echo 'Oldboy123.com' > /root/passwd.txt
root@Ceph-201 ~# ceph dashboard ac-user-set-password jiu -i /root/passwd.txt
✅️ 选项 --> ac-user-set-password
✅️ 后面没有角色, 只有一个密码文件📃
4)把 jiu 降级为只读
root@Ceph-201 ~# ceph dashboard ac-user-set-roles jiu read-only
✅️ 选项 & 更换的角色
{"username": "jiu", ...xxx "roles": ["read-only"],

Terminal window
5)删除 jiu
root@Ceph-201 ~# ceph dashboard ac-user-delete jiu
User 'jiu' deleted

Manager 的 Active / Standby 机制#

Dashboard 本质上是 Manager 进程提供的 HTTP 服务

Terminal window
URL: https://Ceph-201:8443/
root@Ceph-201 ~# curl -k https://Ceph-201:8443/
# -k 跳过证书
This resource can be found at <a href="https://10.0.0.202:8443/">
✅️ -L 可以实现自动跳转
🔹 为什么访问 Ceph-201 却跳到 Ceph-202❓️
1)显示集群中 active / standby
root@Ceph-201 ~# ceph -s | grep mgr
mgr: Ceph-202.xdeumk(active, since 88m), standbys: Ceph-201.cxdvrq
'Ceph 集群通常有多台 Manager(冗余),但同一时刻只有一个是 active'
✅️ 此时 active --> Ceph-202
✅️ 谁当 active mgr,Dashboard 就跑在谁上面
2)试试Ceph-202
root@Ceph-201 ~# curl -kI https://Ceph-202:8443/
HTTP/1.1 200 OK
'这个是可以通的'
https://Ceph-201:8443/
│
└→ standby mgr(Ceph-201): "我不当家,去Ceph-202找active"
│
└→ 重定向 → https://10.0.0.202:8443/
✅️ 访问 standby mgr 的 Dashboard 端口,会被重定向到 active mgr

🔹 选举规则

Manager 选举是先到先得——两边的 mgr 容器同时启动,谁先向 Monitor 注册成功谁就是 active,晚了半拍就成 standby

  • 这不是故障,是正常的 HA 设计:active 挂了,standby 秒级接替
Terminal window
3)查看mgr的状态
root@Ceph-201 ~# ceph mgr stat
✅️ JSON 格式更详细
{
"epoch": 72,
"available": true,
"active_name": "Ceph-202.xdeumk",
"num_standby": 1
}
4)看 Dashboard 实际跑在哪个 IP
root@Ceph-201 ~# ceph mgr services
✅️ 这个命令是真的实用
{
"dashboard": "https://10.0.0.202:8443/"
}
5)手动踢掉 active mgr,触发 standby 接替
✅️ 被踢的原 active 重启
# 用于主动切换(维护前可能会用)
root@Ceph-201 ~# ceph mgr fail
root@Ceph-201 ~# ceph mgr services
{
"dashboard": "https://10.0.0.201:8443/"
}
root@Ceph-201 ~# curl -kI https://Ceph-201:8443/
HTTP/1.1 200 OK ✅️

🔹 把 Dashboard 固定在某台机器上

如果不想让它跟着 active mgr 跑,可以显式指定 IP:

Terminal window
root@Ceph-201 ~# ceph config set mgr mgr/dashboard/server_addr 10.0.0.201
root@Ceph-201 ~# ceph config get mgr mgr/dashboard/server_addr
10.0.0.201
'终于用上 rm 选项了'
root@Ceph-201 ~# ceph config rm mgr mgr/dashboard/server_addr
root@Ceph-201 ~# ceph mgr fail
✅️ ceph mgr fail 一踢,mgr 重启 --> 重新加载配置,内存里的旧值清了
# mgr 不会热加载,得重启才生效

常用操作速查#

Terminal window
# ===================================
# 集群状态
# ===================================
ceph -s # 集群整体健康状态
ceph -w # 实时监控集群变化
ceph osd tree # OSD 树(含 class / 权重 / 状态)
ceph osd df # OSD 磁盘使用率
rados df # 存储池使用率(按池算账)
ceph mgr stat # Manager active/standby 状态(JSON)
ceph mgr services # Dashboard 实际跑在哪个 IP
# ===================================
# 存储池管理
# ===================================
ceph osd pool ls # 列出所有存储池
ceph osd pool ls detail # 存储池详细信息(类型/副本数/规则)
ceph osd pool create <name> <pg> <pgp> replicated # 创建副本池
ceph osd pool create <name> <pg> <pgp> erasure # 创建纠删码池
ceph osd pool create <name> <pg> <pgp> --autoscale_mode off # 创建时关闭自动伸缩
ceph osd pool rename <old> <new> # 重命名存储池
ceph osd pool rm <name> <name> --yes-i-really-really-mean-it # 删除存储池(双重确认)
ceph osd pool application enable <name> <rbd|cephfs|rgw> # 声明池用途
# ===================================
# 池属性管理
# ===================================
ceph osd pool get <name> <param> # 查单个属性(size / min_size / pg_num ...)
ceph osd pool set <name> <param> <val> # 修改属性
ceph osd pool get <name> pg_autoscale_mode # 查看自动伸缩是否开启
ceph osd pool get <name> nodelete # 查看池级删除锁状态
# ===================================
# CRUSH 规则
# ===================================
ceph osd crush rule ls # 列出所有 CRUSH 规则(只列名字)
ceph osd crush rule dump <rule> # 查看规则完整 JSON(故障域/副本数/设备类型)
# ===================================
# PG 管理
# ===================================
ceph pg stat # PG 状态概览
ceph pg dump # 所有 PG 详细状态(常配合 grep)
# ===================================
# 配置管理 (ceph config)
# ===================================
ceph config dump # 导出所有配置项(常配合 grep 过滤)
ceph config dump | grep <keyword> # 按关键字查配置
ceph config get <target> <option> # 查配置(类型级/实例级)
ceph config set <target> <option> <val> # 设配置(global/mon/osd/mgr 等)
ceph config rm <target> <option> # 删除配置
ceph config show <target> # 查看进程实际生效的全部配置
# ===================================
# Dashboard 用户管理
# ===================================
ceph dashboard ac-user-create <user> -i <passwd_file> <role> # 创建用户
ceph dashboard ac-user-show <user> # 查看用户信息
ceph dashboard ac-user-set-password <user> -i <passwd_file> # 修改密码
ceph dashboard ac-user-set-roles <user> <role> # 修改角色
ceph dashboard ac-user-delete <user> # 删除用户

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

相关文章智能推荐
1
K8s故障排查 & 控制器与Service实战
Kubernetes故障排查三板斧describe/logs/exec与command&args,容器三种状态与pause基础架构容器,env环境变量部署WordPress,Deployment副本控制与滚动更新回滚,Service四类型ClusterIP/NodePort/LoadBalancer/ExternalName,kube-proxy+iptables底层实现,名称空间,CoreDNS服务发现与跨ns解析,deploy+svc部署WordPress及跨名称空间连库实战
2
K8s开篇 & kubeadm集群部署实战
KubernetesK8s核心概念与架构详解,基于kubeadm从零部署高可用集群,Flannel网络配置,Pod基础使用与YAML声明式管理
3
Prometheus 告警 && etcd 集群实战
Prometheus监控Alertmanager 告警路由/模板/静默/抑制 + 钉钉插件,etcd 3.7 TLS 高可用集群部署/备份恢复/Prometheus 监控,复用既有 kpyun CA 体系
4
Prometheus存储实战 && HTTPS认证 && 黑盒监控
Prometheus监控VictoriaMetrics单机部署+remote_write远端存储,Prometheus启用HTTPS+Basic Auth认证,node-exporter黑白名单,标签管理(relabel/metric_relabel),blackbox-exporter HTTP/ICMP/TCP黑盒探测,Grafana存储迁移到MySQL
5
Prometheus自定义监控 && 服务发现 && 联邦模式
Prometheus监控部署 pushgateway 实现短期任务/自定义指标的推送式监控(API 推送删除、honor_labels、TCP 12 状态、丢包率脚本),用 Go + client_golang 开发自定义 exporter(静态编译零依赖),落地 file_sd 与 consul 服务发现(consul 2.0.3 集群 + consul_exporter),最后用 3 台 Prometheus server 搭建联邦模式实现分布式采集汇总
Profile Image of the Author
久棹
不是先学好了再干,而是先干起来再学习,干中学!
分类
站点统计
文章
115
分类
15
标签
272
总字数
306,562
运行时长
0 天
最后活动
0 天前
文章目录