Ceph的Crush算法思想

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])。

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_num
    • pg_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 选择不同的故障域(如 hostrackrow)。

4. CRUSH Map 的层级结构

CRUSH Map 定义了 OSD 的物理拓扑,通常采用树状结构:

  • 叶子节点 :OSD(如 osd.1osd.2)。
  • Bucket 节点 :逻辑分组(如 hostrackdatacenter)。
  • 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:

  1. 计算每个 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)×weight
    • r 是副本序号(用于多副本场景)。
    • weight 是 OSD 的权重(如 1.0 代表 1TB 磁盘)。
  2. 选择 straw 值最大的 OSD
    • 权重越高的 OSD 被选中的概率越大。

7. CRUSH 算法的优势

  • 去中心化:无需全局元数据,客户端可独立计算数据位置。
  • 动态扩展:新增 OSD 时,数据自动均衡,迁移量最小化。
  • 故障域隔离:副本可分布在不同的机架、主机,提高容灾能力。
  • 权重感知:大容量 OSD 存储更多数据,实现负载均衡。

8. 总结

CRUSH 算法通过 伪随机计算 + 层级化拓扑结构 + 规则引擎,实现高效、灵活的数据分布。其核心流程为:

  1. 对象 → PG(哈希取模)。
  2. PG → OSD(CRUSH 计算,考虑权重、故障域)。
  3. 副本策略(按 Rule 选择多个 OSD)。

默认 CRUSH Map 适用于大多数场景,但 大规模或异构集群可能需要手动优化(如调整权重、自定义 Rule)。