Ceph 的 CRUSH(Controlled Replication Under Scalable Hashing)算法 是一种去中心化的数据分布算法,用于确定对象在 OSD(Object Storage Device)上的存储位置。它通过伪随机计算实现数据的均匀分布,同时支持故障域隔离、动态扩展和负载均衡。以下是 CRUSH 算法的核心工作原理:
1. CRUSH 算法的核心目标
CRUSH 算法的主要目标包括:
- 去中心化:无需元数据服务器,客户端可直接计算数据位置。
- 负载均衡:数据均匀分布在 OSD 上,避免热点问题。
- 故障域感知:确保数据副本分布在不同的故障域(如不同主机、机架、机房)。
- 动态扩展:新增或移除 OSD 时,最小化数据迁移量。
2. CRUSH 算法的输入与输出
- 输入 :
- 对象 ID(如文件名或哈希值)。
- PG ID(Placement Group,归置组)。
- CRUSH Map(描述集群拓扑结构,包括 OSD、Bucket 层级)。
- Placement Rule(数据分布规则,如副本数、故障域策略)。
- 输出 :
- 一组 OSD (存储对象的设备列表,如
[osd.1, osd.5, osd.9]
)。
- 一组 OSD (存储对象的设备列表,如
3. CRUSH 算法的关键步骤
CRUSH 算法的工作流程可以分为两个主要阶段:
(1) 对象 → PG 映射
- 每个对象通过哈希计算映射到某个 PG:
PG_ID=Hash(Object_ID) % pg_num \text{PG\_ID} = \text{Hash(Object\_ID)} \ \% \ \text{pg\_num} PG_ID=Hash(Object_ID) % pg_numpg_num
是存储池的 PG 数量。- 相同 Object_ID 始终映射到同一个 PG。
(2) PG → OSD 映射
- CRUSH 算法计算 PG 应该存储在哪些 OSD 上 :
CRUSH(PG_ID,CRUSH Map,Rule)→[OSD1,OSD2,OSD3] \text{CRUSH}(PG\_ID, \text{CRUSH Map}, \text{Rule}) \rightarrow [OSD_1, OSD_2, OSD_3] CRUSH(PG_ID,CRUSH Map,Rule)→[OSD1,OSD2,OSD3]- 采用 伪随机选择,确保相同 PG 始终映射到相同 OSD 集合。
- 考虑 OSD 权重(容量越大,被选中的概率越高)。
- 按照 Placement Rule 选择不同的故障域(如
host
、rack
、row
)。
4. CRUSH Map 的层级结构
CRUSH Map 定义了 OSD 的物理拓扑,通常采用树状结构:
- 叶子节点 :OSD(如
osd.1
、osd.2
)。 - Bucket 节点 :逻辑分组(如
host
、rack
、datacenter
)。 - Root 节点:整个集群的入口点。
示例 CRUSH Map 结构:
root default
├── host node1
│ ├── osd.1 (weight 1.0)
│ └── osd.2 (weight 1.0)
├── host node2
│ ├── osd.3 (weight 1.0)
│ └── osd.4 (weight 1.0)
└── rack rack1
├── host node3
│ ├── osd.5 (weight 1.0)
│ └── osd.6 (weight 1.0)
└── host node4
├── osd.7 (weight 1.0)
└── osd.8 (weight 1.0)
5. Placement Rule(放置规则)
CRUSH Rule 定义了数据如何选择 OSD,典型规则如下:
plaintext
rule replicated_rule {
ruleset 0
type replicated
min_size 1
max_size 10
step take default # 从 root bucket 开始
step chooseleaf firstn 0 type host # 选择不同 host 的 OSD
step emit
}
step take
:从哪个 Bucket 开始选择(如root
)。step chooseleaf
:选择 OSD 的策略(如firstn
选择多个副本)。step emit
:结束选择并返回 OSD 列表。
6. CRUSH 的伪随机选择机制
CRUSH 使用 Straw2 算法 选择 OSD:
- 计算每个 OSD 的"签长" :
straw=(CRUSH_HASH(PG_ID,OSD_ID,r) & 0xFFFF)×weight \text{straw} = (\text{CRUSH\_HASH}(PG\_ID, OSD\_ID, r) \ \& \ 0xFFFF) \times \text{weight} straw=(CRUSH_HASH(PG_ID,OSD_ID,r) & 0xFFFF)×weightr
是副本序号(用于多副本场景)。weight
是 OSD 的权重(如 1.0 代表 1TB 磁盘)。
- 选择
straw
值最大的 OSD :- 权重越高的 OSD 被选中的概率越大。
7. CRUSH 算法的优势
- 去中心化:无需全局元数据,客户端可独立计算数据位置。
- 动态扩展:新增 OSD 时,数据自动均衡,迁移量最小化。
- 故障域隔离:副本可分布在不同的机架、主机,提高容灾能力。
- 权重感知:大容量 OSD 存储更多数据,实现负载均衡。
8. 总结
CRUSH 算法通过 伪随机计算 + 层级化拓扑结构 + 规则引擎,实现高效、灵活的数据分布。其核心流程为:
- 对象 → PG(哈希取模)。
- PG → OSD(CRUSH 计算,考虑权重、故障域)。
- 副本策略(按 Rule 选择多个 OSD)。
默认 CRUSH Map 适用于大多数场景,但 大规模或异构集群可能需要手动优化(如调整权重、自定义 Rule)。