6.824 分布式系统 MapReduce
2023-10-03 18:15:00
# Papers
总览
MapReduce
是一个编程模型, 也是一个处理和生成超大数据集的算法模型的相关实现
用户需要做的事情:
- 用户指定
Map
函数处理一个键值对的集合, 输出基于键值对的中间数据 - 用户指定
Reduce
函数把中间数据中具有相同Key
的Value
值整合起来
MapReduce
需要做的事情: 封装并行计算, 容错, 负载均衡, 数据分布的复杂细节
实现
- 用户程序在主机群中
fork
出一个Master
程序, 以及多个Worker
程序
把原始数据划分成M
个数据片段, 决定R
个不同分区用来存储中间数据 Master
分配任务,M
个Map
任务和N
个Reduce
任务- 被分配了
Map
任务的Worker
程序读入相应的数据片段, 调用Map
函数解析为键值对 - 按照用户提供的分区函数 (比如
hash(key) % R
) 把键值对放到对应的分区中
把存储位置传回Master
, 让Master
过后传递给Reduce
任务的Worker
中 - 被分配了
Reduce
任务的Worker
程序使用RPC
从之前执行Map
任务的Worker
主机中
对应分区读取数据并排序(可能用到外部排序) - 遍历键值对, 对于相同
Key
的键值对, 调用Reduce
函数合并数据, 输出到对应分区的输出文件中 - 所有任务完成之后,
Master
唤醒用户程序, 调用结束
在最后, 用户可能会把所有 R
个输出文件合并
数据结构
Master
- 存储每个任务的状态(待完成, 完成中, 已完成)
- 对于每个已完成的
Map
任务, 存储R
个中间文件的大小和位置
容错
Worker
错误
Master
周期性地ping
每个Worker
如果在规定的时间内没有收到返回信息,Master
标记失效的Worker
这个Worker
的任务被重新设置为空闲状态- 对于该
Worker
已完成的Map
任务, 需要全部重新完成, 因为Map
任务的结果存储在这台主机中.
并且重新执行的动作会被通知给所有的执行Reduce
任务的Worker
, 从新主机中读取数据 - 对于该
Worker
已完成的Reduce
任务输出存储在全局文件系统上, 所以不需要重新执行
- 对于该
Master
错误
一般有两种办法
- 每隔一段时间把之前
Master
存储的所有东西写入硬盘作为一个检查点, 故障时从最近一个检查点恢复 - 重新执行所有任务
故障时语义
当用户定义的 Map
和 Reduce
函数是输入确定性函数(相同输入产生相同输出)时, 那么不会产生语义问题
- 每个
Map
任务创建R
个临时文件, 完成时把这R
个临时文件的信息传给Master
如果Master
发现这个任务之前被别的Worker
完成了, 那么他忽略这条消息, 否则就记录在数据结构里 - 每个
Reduce
任务创建一个临时文件(存放在全局文件系统中), 完成时把它重命名(原子的)
如果多个机器都在执行一个Reduce
任务, 他们的重命名请求只在第一次的时候生效
对于非输入确定性的函数 MapReduce
只有较弱的失效处理
存储位置
Master
调度 Map
任务的时候会知道输入文件的位置, 所以尽量在输入文件存储的机器或者附近的机器执行
这样可以减少网络带宽的消耗从而提高整体的效率
任务粒度
Master
执行 $O(M+R)$ 次调度, 内存存储 $O(M \times R)$ 个状态
选择合适的 M
值从而让输入文件被分成 16M ~ 64M 的块被处理(配合存储系统)
选择合适的 R
值, 一般是想使用的 Worker
机器的倍数
任务备份
落伍者指的是对于一台主机, 可能有其他的故障或者任务让它执行 Map
或 Reduce
任务的效率极低, 这会拖延整个任务完成的时间
针对可能出现落伍者的问题, Master
在所有的任务快执行完的时候, 调度备用的 Worker
来处理剩下来的任务
这种策略比正常操作多几个百分点的计算资源, 却能显著减少超大 MapReduce
任务的运行时间
拓展功能
- 分区函数: 用户指定特殊的分区函数来满足特殊要求, 比如把来自同一个主机的 URLs 放在同一个输出文件中
- 有序输出: 在给定的分区中按照
Key
值增量排序处理数据 - 合并函数: 用户指定合并函数,
Map
结束之后先合并一次再传递给Reduce
任务, 可以显著提高一些MapReduce
操作的效率 - 输入输出: 用户可以指定输入输出格式
- 跳过故障记录: 如果每次执行一个任务的时候都会出现错误, 在到达一定次数的时候就会忽略这次任务
- 本地运行: 提供本地化运行的
MapReduce
, 方便调试 - 使用 HTTP 显示状态信息, 使用计数器统计不同事件发生次数