Google GFS:分布式文件系统的开山之作,HDFS 就是照着它做的
Google 的数据量到了 PB 级,单机文件系统撑不住了——硬盘不够大、数据没备份、节点会坏。
GFS 就是 Google 为这个场景设计的分布式文件系统。它不追求 POSIX 兼容,不追求低延迟,追求的是:海量数据、高吞吐、容错性强、能跑在普通硬件上。
后来 Hadoop 的 HDFS 就是 GFS 的开源实现——架构一样、概念一样、连组件名字都是对应的。
GFS 的三个角色:各管一摊
GFS 是典型的主从架构,三个角色分工明确:
graph TD
A[客户端 Client
应用程序接口] -->|1. 获取元数据| B[主控服务器 Master
元数据管理]
A -->|2. 直接读写数据| C[数据块服务器 ChunkServer1] & D[ChunkServer2] & E[ChunkServer3]
B -->|3. 心跳/元数据同步| C & D & E
C & D & E -->|存储数据| F[本地磁盘
Chunk 副本]
note[核心思想 Master 管元数据,ChunkServer 存数据,Client 直接访问数据节点]
| 角色 | 管什么 | 存什么 |
|---|---|---|
| Master | 管”账本”:文件名、目录、Chunk 位置 | 元数据(全在内存里) |
| ChunkServer | 管”货”:实际数据块 | Chunk 数据(本地磁盘) |
| Client | 应用程序接口 | 缓存元数据,不存数据 |
关键设计:Master 不参与数据读写。 Client 只找 Master 要”数据在哪”,拿到地址后直接跟 ChunkServer 传数据。Master 不经过数据流,压力小,集群规模可以做得很大。
Chunk:64MB 的大数据块
GFS 把文件切成固定大小的 Chunk(数据块),默认 64MB。
为什么是 64MB?不是 4KB?
| 设计考量 | 说明 |
|---|---|
| 减少元数据量 | 一个文件需要的 Chunk 数量少,Master 内存能装下更多元数据 |
| 减少网络请求 | Client 一次性拿到的 Chunk 位置信息覆盖范围大 |
| 适合大数据场景 | 连续读写 64MB,比频繁寻道效率高得多 |
| 简化副本管理 | 大块复制比小块复制更高效 |
注意:64MB 是 GFS 的默认值,HDFS 后来改成了 128MB。 磁盘越来越快,块大小也跟着涨。
副本机制:默认 3 份,节点挂了自动补
每个 Chunk 默认存 3 份副本,分布在不同的 ChunkServer 上。
- 一个节点坏了 → 其他节点还有副本
- 一个机架断电了 → 其他机架还有副本
Master 的职责:
- 监控副本数量,发现少了就自动复制补足
- 把新副本分配到负载低的节点
- 定期扫描,回收被删除文件的 Chunk
租约机制:写一致性怎么保证?
GFS 最常见的写操作是追加(Append)——不是覆盖,是在文件末尾加数据。
并发追加的问题是:多个 Client 同时写同一个 Chunk,谁先谁后?怎么保证所有副本写的内容一致?
GFS 的解法是”租约”:
- Master 给每个 Chunk 指定一个 主 ChunkServer(Primary),授予租约(默认 60 秒有效)
- 所有写操作由 Primary 协调:
- Client 把数据发给所有副本(Primary + Secondary)
- Client 问 Primary “可以写了吗?”
- Primary 确定写入顺序,通知所有 Secondary 按这个顺序执行
- 全部写成功,Primary 回复 Client
- 租约快到期时,Primary 找 Master 续期
这样做的效果:
- Master 不用参与每次写操作,压力小
- Primary 统一协调顺序,所有副本写入顺序一致 → 数据一致
- 并发追加时,Primary 负责合并顺序,每个追加操作原子性
读写流程
读操作(简单):
sequenceDiagram
Client->>Master: 请求文件元数据(Chunk 列表及位置)
Master->>Client: 返回 Chunk 列表及每个 Chunk 的 ChunkServer 地址
Client->>ChunkServer: 直接请求读取目标 Chunk 数据
ChunkServer->>Client: 返回 Chunk 数据
写操作(追加):
sequenceDiagram
Client->>Master: 请求 Chunk 租约信息(获取 Primary 和 Secondary)
Master->>Client: 返回 Primary 和 Secondary 地址
Client->>Primary & Secondary: 推送数据到所有副本的缓存
Client->>Primary: 发送写请求(请求执行追加)
Primary->>Secondary: 通知写顺序,要求执行写操作
Secondary->>Primary: 返回写成功响应
Primary->>Client: 返回追加成功响应(包含实际写入位置)
关键点:数据先”推”到所有副本,再”通知”写。 这样数据已经在本地了,写操作只是顺序追加,速度快。
Master 的元数据怎么存的?全在内存里
Master 存三样东西:
- 文件命名空间:目录树、文件名
- 文件 → Chunk 映射:每个文件由哪些 Chunk 组成
- Chunk → ChunkServer 映射:每个 Chunk 在哪些节点上
前两样持久化到磁盘(操作日志 + 检查点),第三样不持久化——ChunkServer 启动时会把自己手里的 Chunk 列表上报给 Master。
为什么第三样不持久化? ChunkServer 会上下线、会故障,位置信息是动态的,靠心跳汇报更可靠。
GFS 与 HDFS 的对照
HDFS 就是 GFS 的开源实现,几乎照搬了设计:
| GFS | HDFS |
|---|---|
| Master | NameNode |
| ChunkServer | DataNode |
| Chunk(64MB) | Block(128MB) |
| 租约机制 | 无(写操作由 NameNode 协调,更简单但性能略低) |
| 追加写为主 | 追加写为主,支持有限的随机写 |