10.6 元数据管理与副本放置

一句话

元数据决定 “能不能找到数据”、副本放置决定 “坏了能不能恢复”:元数据要能水平扩展且低延迟,副本必须跨故障域——否则 “3 副本” 只是 “同一机架里的 3 份拷贝”。

元数据的两种架构

架构 代表 优点 缺点
集中式(单 Master) HDFS NameNode、GFS Master 简单、强一致、易实现 内存受限、单点(靠 HA 补)
分布式(分片 KV) 对象存储、Ceph MON+OSD map 可扩展、无单点 一致性与路由更复杂

集中式的天花板很清楚:每个对象/文件/块在内存里占一条记录(约 150 字节量级)。

实测:元数据内存账

对象数 元数据内存(150B/对象)
100 万 ≈ 0.14 GB
1000 万 ≈ 1.40 GB
1 亿 ≈ 13.97 GB

1 亿对象就要 14GB 堆——这还没算索引、缓存与副本。所以 “小文件/海量对象” 对集中式元数据是致命的;分布式元数据(分片 + 前缀树)才是解法。

副本放置:跨故障域才算副本

3 机架、3 副本,若随机放置:

放置方式 同一对象 3 副本全在 1 个机架的概率
随机(可重复) ≈ 11.1%
机架感知(每机架 ≤ 1 副本) 0%

11.1% 意味着 “约每 9 个对象就有 1 个,其全部副本在同一机架”——机架断电就永久丢数据。副本数不等于可靠性,故障域分布才是。

可靠性的三个层次:
  副本数(3)→ 故障域(跨机架/跨 AZ)→ 修复速度(重建带宽/限速)
少任何一层,另外两层都会被浪费

代码:机架感知放置的判据

# 放置策略:同一对象的副本必须落在不同机架(再要求不同 AZ)
def place(obj, racks, replicas):
    chosen = []
    for r in racks:                       # 机架优先
        if len(chosen) == replicas: break
        if r.az in {c.az for c in chosen} and len({c.az for c in chosen}) < len({x.az for x in racks}):
            continue                      # 先保证跨 AZ
        chosen.append(r)
    assert len({c.rack for c in chosen}) == replicas, "副本集中在同一机架"
    return chosen

反模式

反模式 后果
只数副本数、不看故障域 机架/ AZ 故障时全部副本一起丢
元数据放单机内存且不做 HA NameNode 挂 = 集群不可用
1 亿小对象用集中式元数据 内存爆、GC 停顿、启动慢
副本修复不限速 重建流量抢带宽,前台延迟飙升
只按 “磁盘利用率” 放置 热点节点先满,扩容也救不了
不做 “副本一致性校验” 静默损坏(bit rot)长期不被发现

三条铁律

🔑 副本要跨故障域;同机架的 3 份等于 1 份。

🔑 元数据规模决定架构:1 亿对象别用单 Master。

🔑 修复要限速 + 可观测;否则 “修数据” 变成 “拖垮业务”。

自检

Q1 为什么 “3 副本” 在随机放置下只有约 89% 的对象是安全的?

▸ 答案:因为随机放置允许 “3 个副本落在同一机架”(概率约 11.1%)。这些对象在 “该机架故障” 时会同时失去所有副本,等于单副本。副本数的意义依赖 “故障域独立性”。

Q2 元数据内存怎么估?

▸ 答案:按 “对象数 × 每对象字节数” 估:本机按 150B/对象算,1 亿对象 ≈ 14GB。再加上索引、缓存与副本,实际需求更高。估算时要留 2 倍余量,并考虑 GC 停顿对延迟的影响。

Q3 集中式元数据(NameNode)为什么难扩展?

▸ 答案:因为所有元数据要在内存里维护并保持一致:单机内存有限,且每次变更都要走同一个入口。HDFS 的解法是 “联邦(多 NameNode 分命名空间)” 与 “更大堆 + 调优”,但本质仍是 “按命名空间分片”。

Q4 机架感知放置的实现关键是什么?

▸ 答案:关键是拓扑信息:节点要上报 “机架/AZ”,放置器按拓扑选点,并校验 “副本的故障域互不相同”。没有拓扑信息,“机架感知” 只是口号;有了它,才能把 “3 副本” 变成 “3 个独立故障域”。

Q5 副本修复为什么要限速?

▸ 答案:因为重建是读放大:修 1 块要读 k 块(EC)或 1 份(副本),并写入新副本;如果不限速,重建流量会与前台业务抢带宽,造成 “修数据把业务拖慢”。常见做法是 “限速 + 低峰优先 + 监控重建队列”。

Q6 “bit rot”(静默损坏)怎么发现?

▸ 答案:靠校验和 + 定期扫描:每个块存校验和,后台定期读取校验;发现不匹配就用其他副本修复。没有校验和,损坏只会在 “读到时” 才暴露,且可能已经传染到备份。

Q7 对象存储的元数据为什么常用 “分片 KV”?

▸ 答案:因为对象数量可以到千亿级:单机内存放不下,且需要水平扩展与高并发。分片 KV(按 bucket + key hash)把元数据分散到多节点,配合一致性协议保证 “同一 key 的元数据只有一个主”,从而既扩展又不冲突。

关联