GFS读写过程

适合学习和回忆的 GFS 中 Client 向 Master 请求元数据、再与 ChunkServer 通信的全过程

读流程写流程,写流程比读复杂,涉及 primary / secondary / lease / 数据流水线


GFS 中三类角色

Client:
发起读写请求的客户端

Master:
只管理元数据,不直接传输文件数据
管理:
- 文件名空间
- 文件 -> chunk 映射
- chunk 副本位置
- chunk lease(谁是 primary)

ChunkServer:
真正存储 chunk 数据

一、先记住最核心原则

GFS 的关键设计思想

Master 不在数据通路上,只在控制通路上。

也就是:

  • Master 负责告诉 Client 去哪里读/写
  • 真正的数据传输发生在 Client 和 ChunkServer 之间

这个是 GFS 最重要的一句。


二、GFS 读数据全过程

假设用户要读取:

/foo.txt 的某个 offset 开始的一段数据

1)读流程总图

sequenceDiagram participant Client participant Master participant CS1 as ChunkServer A participant CS2 as ChunkServer B participant CS3 as ChunkServer C Client->>Master: 1. 询问文件 offset 对应的 chunk 句柄 + 副本位置 Master-->>Client: 2. 返回 chunk handle + replicas(CS1,CS2,CS3) Client->>CS2: 3. 直接向某个最近的 ChunkServer 发起读请求 CS2-->>Client: 4. 返回 chunk 数据 Note over Client,Master: Client 会缓存 chunk 元数据,后续同一 chunk 读请求通常不必再问 Master

2)逐步解释

第一步:Client 先根据文件名和 offset 定位 chunk

GFS 文件被切成很多固定大小的 chunk(经典论文里通常是 64MB)。

所以 Client 读取时,先要算出:

chunk index = offset / chunk_size

比如:

读取 /foo.txt 的 offset = 130MB
chunk_size = 64MB

那么它要找的就是:

第 2 号 chunk

第二步:Client 向 Master 请求元数据

Client 不会直接问 “把数据给我”。

它问的是:

给我 /foo.txt 第 i 个 chunk 的:
- chunk handle
- 这个 chunk 的副本位置

Master 返回:

chunk handle = 12345
replicas = [ChunkServer A, B, C]

这里:

  • chunk handle 是 chunk 的全局唯一标识
  • replicas 是这个 chunk 的多个副本所在的 ChunkServer

第三步:Client 直接选一个 ChunkServer 读

Client 拿到副本列表后,会自己选一个 ChunkServer,通常选:

  • 距离更近的
  • 网络更快的
  • 当前看起来更合适的

然后直接发请求:

请把 chunk handle=12345 从某个内部 offset 开始的数据发给我

注意这里已经 不经过 Master 了。


第四步:ChunkServer 返回数据

ChunkServer 找到本地 chunk 数据,返回给 Client。

如果这个请求只覆盖一个 chunk,流程结束。

如果读跨越多个 chunk,Client 会:

  • 对下一个 chunk 再发请求
  • 如果缓存里没有元数据,再去问 Master

3)读流程一句话总结

Client 先向 Master 要“位置”,再直接向 ChunkServer 要“数据”。


三、GFS 读流程的细节补充

1. Client 会缓存元数据

Master 负担不能太重,所以 Client 会缓存:

  • 文件到 chunk 的映射
  • chunk handle
  • chunk 副本位置

所以后续连续读常常是:

第一次问 Master
后面直接找 ChunkServer

2. Master 不返回数据本身

Master 只返回:

  • chunk handle
  • 副本位置

它不转发真实数据。


3. 如果 ChunkServer 失败怎么办

如果 Client 发现某个 ChunkServer 不可用:

  • 换另一个副本重试
  • 如果元数据过期,再重新问 Master

四、GFS 写数据全过程

写流程比读复杂很多,因为要保证多个副本的一致性。

核心角色:

  • Master:告诉 Client 哪些副本参与写,以及谁是 primary
  • Primary ChunkServer:负责给这次写操作确定顺序
  • Secondary ChunkServer:按 primary 指定的顺序执行写入

五、GFS 写流程总图

sequenceDiagram participant Client participant Master participant P as Primary ChunkServer participant S1 as Secondary ChunkServer participant S2 as Secondary ChunkServer Client->>Master: 1. 请求某 chunk 的写入信息 Master-->>Client: 2. 返回 primary + secondaries + lease Note over Client,P: 3. Client 先把数据推送到所有副本(数据流) Client->>S1: push data Client->>S2: push data Client->>P: push data Note over Client,P: 4. Client 向 primary 发送写命令(控制流) Client->>P: write(handle, data_id, offset) P->>P: 5. 为写操作分配全局顺序 P->>S1: 6. 按顺序转发写命令 P->>S2: 7. 按顺序转发写命令 S1-->>P: 8. ack S2-->>P: 9. ack P->>P: 10. 本地提交完成 P-->>Client: 11. 返回成功

六、为什么写流程要分成“推数据”和“发写命令”两步

这是 GFS 很经典的设计。

第一步:数据先推送到所有副本

Client 会先把数据送到所有参与写入的 ChunkServer,但此时它们只是:

  • 把数据暂存在内部缓冲区
  • 还没有真正写到正式位置

第二步:再由 primary 发号施令

真正写的时候,Client 只向 primary 发送控制命令:

请把刚才那份数据写到 chunk 的某个位置

这样做的好处是:

  • 数据传输和控制解耦
  • primary 只负责排序,不必承载全部数据转发压力
  • 写入顺序统一,便于副本一致

七、写流程详细展开


第 1 步:Client 向 Master 请求写元数据

Client 告诉 Master:

我要写 /foo.txt 的某个 chunk

Master 返回:

  • 该 chunk 的各个副本位置
  • 哪个副本当前是 primary
  • 对应 lease 信息

例如:

chunk handle = 12345
primary = ChunkServer A
secondaries = [B, C]

第 2 步:Client 把数据推送给所有副本

Client 不会只把数据发给 primary。

而是会把数据发送到全部副本。实际实现里常是 链式流水线

例如:

Client -> A -> B -> C

或者按网络拓扑优化路径推送。

重点是:

  • 每个 ChunkServer 都先收到同一份数据
  • 数据先缓存起来
  • 此时还没正式提交

第 3 步:Client 向 primary 发送写请求

当所有副本都拿到数据后,Client 向 primary 发控制请求:

write(chunk_handle, data_id, offset)

这里 data_id 表示刚才那份已经推送到各副本缓存区的数据。


第 4 步:Primary 决定全局顺序

这一步是 GFS 写一致性的关键。

多个 Client 可能同时往同一个 chunk 写,primary 要决定:

这次写是第几号操作
先执行谁,后执行谁

也就是:

primary 给这个 chunk 上的并发修改建立一个串行顺序。


第 5 步:Primary 把写命令转发给 secondaries

Primary 告诉 secondary:

按这个顺序执行这次写

Secondaries 接到后,在本地正式写入对应位置。


第 6 步:Secondaries 回 ACK 给 Primary

每个 secondary 写完之后返回确认。


第 7 步:Primary 汇总结果并回复 Client

如果所有副本都成功,primary 回复 Client 成功。

如果某些副本失败,Client 会收到错误,然后重试或重新询问 Master。


八、GFS 写流程的本质

数据先分发到所有副本,命令由 primary 排序后统一执行。


九、Append 流程和普通 Write 的区别

GFS 里还有一个非常有代表性的操作:Record Append

它和普通写的区别是:

  • 普通写:Client 指定 offset
  • Record Append:Client 只说“把这条记录追加到文件末尾”

这时由 primary 决定最终追加位置。


Record Append 流程概念图

sequenceDiagram participant Client participant Master participant P as Primary participant S1 as Secondary participant S2 as Secondary Client->>Master: 请求 append 所需元数据 Master-->>Client: 返回 primary + replicas Client->>P: 发送 append 请求 P->>P: 选择实际追加偏移 P->>S1: 按选定 offset 执行 append P->>S2: 按选定 offset 执行 append S1-->>P: ack S2-->>P: ack P-->>Client: 返回成功 + 实际偏移

为什么 GFS 很强调 Append

因为 GFS 面向的典型场景是:

  • 大量日志写入
  • 追加式数据生成
  • 批处理数据生产

所以 “追加” 比 “随机覆盖写” 更常见。


十、读写全过程总览图

flowchart TD A[Client 发起请求] --> B{读还是写?} B -->|读| C[根据文件名+offset定位 chunk] C --> D[向 Master 请求 chunk handle 和副本位置] D --> E[Master 返回 replicas] E --> F[Client 直接选择一个 ChunkServer] F --> G[ChunkServer 返回数据] B -->|写| H[向 Master 请求 chunk 副本位置和 primary] H --> I[Master 返回 primary + secondaries + lease] I --> J[Client 先把数据推送到所有副本] J --> K[Client 向 primary 发送写命令] K --> L[primary 决定写顺序] L --> M[primary 命令 secondaries 执行写入] M --> N[secondaries ack 给 primary] N --> O[primary 回复 Client]

十一、GFS 中 Master 到底干了什么

可以把 Master 记成:

Master 负责控制面

  • 文件名空间管理
  • 文件到 chunk 的映射
  • chunk 副本位置管理
  • 分配新的 chunk handle
  • 选 primary,授予 lease
  • 垃圾回收、重复制、负载均衡

Master 不负责数据面

  • 不转发文件内容
  • 不参与正常读写数据流

十二、“全过程简版”

读流程

1. Client 根据文件名和 offset 确定要访问哪个 chunk
2. Client 向 Master 请求 chunk handle 和副本位置
3. Master 返回 chunk 元数据
4. Client 直接联系某个 ChunkServer 读取数据
5. ChunkServer 返回数据给 Client

写流程

1. Client 向 Master 请求 chunk 的副本位置和 primary
2. Master 返回 primary 和 secondaries
3. Client 先把数据推送到所有副本
4. Client 向 primary 发送写命令
5. primary 确定并发写入顺序
6. primary 通知 secondaries 按相同顺序写入
7. secondaries 返回确认
8. primary 汇总后回复 Client

十三、一句总总结

你可以把 GFS 整个通信过程记成这两句:

先问 Master 位置,再找 ChunkServer 拿数据。

先问 Master 谁是 primary,再把数据发给副本,由 primary 统一排序提交。


十四、“学习脑图版”

mindmap root((GFS Client请求全过程)) 读 Client 计算 chunk index 请求 Master 获取 chunk handle 获取 replicas 直接联系 ChunkServer 返回数据 Client 缓存元数据 写 请求 Master 获取 primary 获取 secondaries 获取 lease 数据先推送全部副本 Client 向 primary 发命令 primary 排序 secondaries 执行 ack 返回 primary 回复 Client Master 管理元数据 不走数据流 ChunkServer 存储 chunk 提供读写 关键机制 replication lease primary-secondary pipeline append
posted @ 2026-04-17 19:24  BuerH  阅读(12)  评论(0)    收藏  举报