MIT 6.824分布式系统和MapReduce Lecture 1 Introduction


  1. 分布式系统的定义:一组相互协作的计算机通过网络通信来共同完成某个任务。
  2. 课程重点:将关注大型网站存储、大数据计算(如MapReduce)以及点对点文件共享等案例研究。
  3. 分布式系统的重要性:许多关键基础设施建立在分布式系统之上,这些系统需要多台计算机来完成任务,或者需要物理上分散部署。
  4. 构建分布式系统的原因
    • 高性能:通过并行处理提升性能。
    • 容错:通过复制任务在多台计算机上执行,提高系统的容错能力。
    • 物理分布:某些问题天然需要在空间上分散处理,如跨银行转账。
    • 安全性:通过在多台计算机上分散计算,实现隔离,增强安全性。
  5. 分布式系统的挑战
    • 并发编程问题:多台计算机同时执行任务,带来并发编程的复杂性。
    • 意外的故障模式:分布式系统可能遇到部分故障,如网络问题或部分计算机失效。
    • 性能提升难题:虽然理论上增加计算机数量可以提升性能,但实际上要实现这种线性扩展非常困难。
  6. 课程结构:包括讲座、论文阅读、实验和期末考试。讲座将涵盖分布式系统的两大主题:性能和容错。实验将涉及构建实际的分布式系统,重点关注性能和容错。
  7. MapReduce案例研究:详细介绍了MapReduce框架,它允许用户通过编写简单的map和reduce函数来执行大规模分布式计算,而无需关心底层的分布式细节。
  8. MapReduce的工作原理
    • Map阶段:在输入文件上并行执行map函数,生成中间的键值对。
    • Shuffle阶段:根据键将所有map输出收集起来,为reduce阶段准备数据。
    • Reduce阶段:对每个键对应的所有值执行reduce函数,生成最终输出。
  9. MapReduce的挑战:网络通信是MapReduce性能的主要瓶颈,尤其是在数据传输(shuffle阶段)时。
  10. 现代分布式系统:现代数据中心网络速度更快,Google等公司已经停止使用MapReduce,转而使用更现代的系统,这些系统能够更有效地处理数据流和大规模并行计算。

MapReduce

1. MapReduce概要

MapReduce是一种编程模型及其实现,用于处理和生成大型数据集。其核心思想是通过两种用户定义的函数——MapReduce,实现数据的分布式处理:

  1. Map函数
    • 输入是一个键值对(key/value),输出是一组中间键值对。
    • Map函数负责将原始输入数据分解为中间数据。
  2. Reduce函数
    • 接收由Map阶段输出的中间数据,并将具有相同键的所有值聚合。
    • Reduce函数通常生成一个更小的结果集。

2. MapReduce案例

以下总结了多种MapReduce应用场景,涵盖从单词统计到倒排索引等典型案例。


1. 单词统计(Word Count)

功能

统计每个文档中单词的出现次数。

Map阶段

输入键值对(文档名称,文档内容),对每个单词输出<word, 1>

Reduce阶段

对相同单词的值列表求和,生成<word, count>

伪代码

def map(key, value):
    for word in value.split():
        emit(word, 1)

def reduce(key, values):
    emit(key, sum(values))

用途

分析文本数据,例如单词频率统计。


2. 分布式Grep(Distributed Grep)

功能

提取包含指定模式的行。

Map阶段

判断行是否包含指定模式,若匹配则输出该行。

Reduce阶段

直接输出中间结果(Identity Function)。

伪代码

def map(key, value):
    if "pattern" in value:
        emit(key, value)

def reduce(key, values):
    for value in values:
        emit(key, value)

用途

分布式日志搜索或数据过滤。


3. URL访问频率统计(Count of URL Access Frequency)

功能

统计每个URL的访问次数。

Map阶段

解析日志文件,每行输出<URL, 1>

Reduce阶段

对相同URL的值列表求和,生成<URL, total count>

伪代码

def map(key, value):
    url = extract_url(value)
    emit(url, 1)

def reduce(key, values):
    emit(key, sum(values))

用途

分析网站流量或用户行为。


4. 反向链接图(Reverse Web-Link Graph)

功能

构建目标页面与其所有引用页面的映射。

Map阶段

解析网页,输出<target, source>,表示source页面链接了target

Reduce阶段

汇总目标页面的所有来源页面。

伪代码

def map(key, value):
    for target in extract_links(value):
        emit(target, key)

def reduce(key, values):
    emit(key, list(values))

用途

构建搜索引擎中的反向索引。


5. 主机词向量统计(Term-Vector per Host)

功能

为每个主机生成关键词及其频率的向量。

Map阶段

解析文档内容,按主机输出<hostname, term vector>

Reduce阶段

合并同一主机的词向量,并移除低频词。

伪代码

def map(key, value):
    hostname = extract_hostname(key)
    term_vector = generate_term_vector(value)
    emit(hostname, term_vector)

def reduce(key, values):
    combined_vector = merge_term_vectors(values)
    emit(key, filter_infrequent_terms(combined_vector))

用途

文本聚类或主题分析。


6. 倒排索引(Inverted Index)

功能

记录每个单词在哪些文档中出现。

Map阶段

为每个单词生成键值对<word, document ID>

Reduce阶段

对相同单词的文档ID列表进行排序并去重。

伪代码

def map(key, value):
    for word in value.split():
        emit(word, key)

def reduce(key, values):
    emit(key, sorted(set(values)))

用途

实现全文搜索,用于快速定位文档。


7. 分布式排序(Distributed Sort)

功能

对记录按指定键进行全局排序。

Map阶段

提取排序键,生成<key, record>

Reduce阶段

直接输出分区后的排序结果。

伪代码

def map(key, value):
    sort_key = extract_key(value)
    emit(sort_key, value)

def reduce(key, values):
    for value in values:
        emit(key, value)

依赖

  • 分区函数(例如hash(key) mod R)。
  • 每个分区内保证键递增排序。

用途

大规模排序任务,如TeraSort。


这些案例展示了MapReduce的灵活性和广泛适用性,可用于文本处理、数据分析和索引构建等多种场景。

3. 实现

以下为Google设计的MapReduce实现所针对的计算环境特性。

1. 环境适配性

不同的MapReduce实现方式可以根据环境选择,适应从小型共享内存机器到大型分布式网络集群的需求。


2. Google的计算环境特点

Google针对其大规模集群设计了特定的MapReduce实现,该环境的主要特性包括:

(1) 硬件配置

  • 处理器:每台机器配备双处理器的x86架构,运行Linux系统。
  • 内存:每台机器内存为2-4 GB,属于普通商品硬件。

(2) 网络架构

  • 使用普通的网络硬件:
    • 每台机器的网络带宽为100 Mbps或1 Gbps。
    • 整体网络的双向带宽有限,表现为瓶颈区域带宽不足。

(3) 集群规模

  • 集群由数百至数千台机器组成。
  • 由于规模庞大,机器故障非常普遍。

(4) 存储系统

  • 使用廉价的IDE硬盘作为存储介质。
  • 依赖自研的分布式文件系统(GFS),通过数据副本提供高可用性和可靠性,克服硬件的不可靠性。

(5) 调度机制

  • 用户提交的作业通过调度系统处理。
  • 每个作业由多个任务组成,调度系统将任务分配到集群中的可用机器。

3.1 工作流程

  1. 数据分片:输入数据被分割为多个小片,每片通常大小在16MB到64MB之间。
  2. 任务分配:Master节点管理任务调度,将Map任务和Reduce任务分配给工作节点。
  3. Map阶段
    • 每个工作节点读取分片,执行用户定义的Map函数,生成中间键值对。
    • 中间结果被分区并存储在本地磁盘上。
  4. 数据传输和排序:Reduce节点通过网络获取中间数据,对其按键进行排序。
  5. Reduce阶段:Reduce节点处理中间数据,生成最终的输出结果。
  6. 结果输出:输出被写入到指定的分布式存储中。
  • 输入数据分片

    MapReduce 库会将输入文件拆分为 M 个小块(通常每块 16MB 到 64MB,可由用户参数控制)。然后在集群中的多个机器上启动多个程序实例。

  • 主节点与工作节点

    启动的程序实例中有一个是 主节点(master),其余是 工作节点(worker)。主节点负责将 M 个 Map 任务R 个 Reduce 任务 分配给空闲的工作节点。

  • Map 阶段

    • 被分配到 Map 任务的工作节点读取对应的输入分片,并将其解析为键值对(key/value pairs)。
    • 用户自定义的 Map 函数对这些键值对进行处理,生成中间键值对。
    • 中间键值对缓存在内存中,随后按照分区函数(如 hash(key) mod R)分为 R 个区域,并定期写入本地磁盘。写入的位置会被通知主节点。
  • Reduce 阶段的数据拉取

    • 主节点通知 Reduce 工作节点中间数据的位置。
    • Reduce 节点通过远程调用从 Map 节点的本地磁盘读取中间数据。
    • Reduce 节点对这些数据按照中间键进行排序(需要确保相同键的数据分组到一起)。如果数据量太大,会使用外部排序。
  • Reduce 阶段

    • Reduce 节点遍历排序后的中间数据,将每个唯一键及其对应的一组值传递给用户自定义的 Reduce 函数。
    • Reduce 函数的输出被追加到对应的最终输出文件(每个 Reduce 任务对应一个文件)。
  • 任务完成

    • 当所有 Map 和 Reduce 任务完成后,主节点唤醒用户程序,MapReduce 调用返回。最终输出为 R 个文件,用户可以直接使用这些文件作为下一个 MapReduce 调用的输入,或者在其他分布式应用中处理。

请添加图片描述

优势:

  • 自动化并行化:无需开发者操心并行、分布式及容错等细节。
  • 容错性:如果节点失败,任务会重新调度执行。
  • 扩展性:可以在由普通硬件组成的大型集群上运行,处理TB甚至PB级别的数据。

3.2 Master 的数据结构

  • 任务状态管理:

    Master 维护所有 Map 和 Reduce 任务的状态,包括:

    • 状态:空闲(idle)、执行中(in-progress)、已完成(completed)。
    • 执行的工作节点(worker)的标识。
  • 中间数据位置管理:

    Master 记录每个已完成的 Map 任务生成的 RR 个中间文件的位置和大小,并将这些信息推送给正在进行的 Reduce 任务。

  • 中间文件重分发:

    如果某个 Map 任务重新执行(例如因为节点失败),Master 会将新生成的中间文件位置通知 Reduce 任务,确保 Reduce 可以正常获取数据。


3.3 容错机制

由于 MapReduce 需要在数百甚至数千台机器上运行,必须具备良好的容错能力。以下是主要的容错机制:

1. Worker 节点失败

  • 检测失败:

    Master 定期对每个 Worker 发送 ping 信号。如果某 Worker 在指定时间内未响应,Master 会将其标记为失败。

  • 任务重置:

    • 该 Worker 已完成的 Map 任务 会被重置为初始状态(idle),以便在其他节点上重新调度执行,因为中间文件存储在失败节点的本地磁盘,无法访问。
    • Reduce 任务无需重新执行,因为 Reduce 的输出存储在全局文件系统中。
  • 重分发任务:

    如果 Map 任务先在 Worker A 上执行,后因 A 失败在 Worker B 上重新执行,Reduce 任务会从 Worker B 获取新的中间数据。

2. Master 节点失败

  • 检查点机制:

    Master 可以定期将其数据结构(任务状态、文件位置信息等)保存为检查点。如果 Master 失败,可从最近的检查点恢复。

  • 当前实现:

    Master 节点单点失败时,MapReduce 任务会中止。用户需要重新启动任务。不过,由于 Master 是单节点,失败的可能性较小。


故障条件下的语义

  • 确定性函数:

    如果用户定义的 Map 和 Reduce 操作是确定性函数(输入确定,输出也确定),分布式 MapReduce 保证其结果与顺序执行相同。

  • 非确定性函数:

    如果 Map 或 Reduce 包含非确定性操作(如随机数),分布式 MapReduce 的结果可能稍有差异:

    • 相同 Reduce 任务的输出与顺序执行一致。
    • 不同 Reduce 任务可能读取到 Map 任务的不同执行结果(例如某 Map 任务失败后重新执行)。

3.4 本地化 (Locality)

  • 节省网络带宽:

    网络带宽是集群中宝贵的资源。为了减少网络带宽消耗,MapReduce 优化了任务调度,使 Map 任务尽量在存储输入数据的机器上运行。

  • 数据存储机制:

    • 输入数据由 GFS(Google File System)管理,分为 64 MB 块,每个块存储 3 个副本,分布在不同机器上。
  • 任务调度优化:

    1. Master 优先将 Map 任务分配到拥有输入数据副本的机器上。
    2. 如果无法安排在存储副本的机器上,则优先选择同一网络交换机下的机器。
  • 结果:

    在大规模任务中,大部分输入数据可以被本地读取,减少了网络带宽的使用。


3.5 任务粒度 (Task Granularity)

  • 任务拆分:
    • Map 阶段分为 M 个子任务,Reduce 阶段分为 R 个子任务。
    • M 和 R 通常远大于 Worker 机器的数量。
  • 优势:
    1. 动态负载均衡: 每个 Worker 执行多个小任务,可以根据空闲状态动态调度任务。
    2. 故障恢复: 如果某个 Worker 失败,其完成的任务可以重新分配给多个其他 Worker。
  • 限制:
    • Master 需要进行 O(M+R) 次调度决策,并维护 (O(M×R) 的状态信息(每对 Map 和 Reduce 任务大约需要 1 字节存储空间)。
    • R 的大小通常受到用户的限制,因为每个 Reduce 任务生成一个独立的输出文件。
  • 实际选择:
    • M:通常选择每个 Map 任务处理 16 MB 到 64 MB 数据,以优化本地化性能。
    • R:通常是 Worker 数量的几倍。
    • 示例:使用 2000 个 Worker 时,常见配置为M=200000, R=5000。

3.6 备份任务 (Backup Tasks)

  • 问题:

    MapReduce 任务中的“尾部拖延”(Straggler)可能显著延长整个操作的完成时间,常见原因包括:

    • 硬件问题(如磁盘错误导致读写速度减慢)。
    • 集群调度引起的资源竞争(CPU、内存、磁盘、网络带宽)。
    • 软件问题(如禁用缓存导致计算性能显著下降)。
  • 解决方案:

    • 备份机制:
      当 MapReduce 接近完成时,Master 会为仍在执行中的任务安排备份执行(Backup Execution)。
    • 标记完成:
      无论是主任务还是备份任务完成,任务都会被标记为已完成。
  • 性能优化:

    • 备份机制只增加了少量计算资源(通常只多消耗 1% 至 3%)。
    • 对于大规模 MapReduce 操作,显著减少完成时间。例如,禁用备份机制时,排序程序的运行时间增加了 44%。

通过这些优化,MapReduce 能更高效地利用计算资源,最大化数据局部性,并显著减少尾部拖延对总运行时间的影响。

4. 完善

4.1 分区函数 (Partitioning Function)

  • 默认分区: 使用 hash(key) mod R 将中间键分布到 个 Reduce 任务中,通常能产生平衡的分区。

    RR

  • 用户自定义: 支持用户定义分区函数,例如 hash(Hostname(urlkey)) mod R,可确保相同主机的 URL 数据写入同一输出文件。


4.2 排序保证 (Ordering Guarantees)

  • 每个分区内的中间键值对按照键值递增顺序处理。
  • 用途: 输出文件支持按键高效随机访问或方便用户处理排序数据。

4.3 合并函数 (Combiner Function)

  • 功能: 允许在 Map 任务所在机器上对中间数据进行部分合并,减少传输到 Reduce 任务的数据量。
  • 适用场景: 用户定义的 Reduce 函数是交换律和结合律的,如单词计数。
  • 优点: 减少网络流量并显著加速某些操作。

4.4 输入和输出类型 (Input and Output Types)

  • 输入格式:
    • 支持多种格式(如文本行、键值对序列)。
    • 输入类型实现负责数据拆分,确保任务边界的有效性(如按行拆分)。
    • 可自定义输入类型(如从数据库或内存结构读取数据)。
  • 输出格式:
    • 提供不同数据格式的输出支持,用户也可添加新的输出类型。

4.5 副作用文件 (Side-effects)

  • 额外输出: Map 或 Reduce 操作可能需要生成辅助文件,需由应用程序保证操作的原子性和幂等性(如使用临时文件)。
  • 限制: 不支持多个文件的原子提交,但实践中未引发问题。

4.6 跳过错误记录 (Skipping Bad Records)

  • 问题: Bug(如第三方库问题)可能导致特定记录引发 Map 或 Reduce 函数崩溃,阻碍操作完成。
  • 解决方案:
    • MapReduce 可检测并跳过引发崩溃的记录,允许计算继续。
    • 通过信号处理机制记录出错的记录序号,若多次失败则跳过。

4.7 本地执行 (Local Execution)

  • 目的: 提供本地顺序执行的 MapReduce 实现,用于调试、性能分析或小规模测试。
  • 用户控制: 通过标志限制特定 Map 任务,方便使用调试工具(如 gdb)。

4.8 状态信息 (Status Information)

  • HTTP 服务:
    • Master 通过内置 HTTP 服务器展示任务状态(已完成任务数、处理速度、输入/输出字节数等)。
    • 包含错误日志链接和 Worker 失败信息,便于诊断用户代码问题。
  • 用户收益:
    • 预测计算时间,决定是否增加资源。
    • 分析计算是否异常缓慢。

4.9 计数器 (Counters)

  • 功能: 提供计数器机制记录事件次数(如处理的总词数、某类文档数)。
  • 实现:
    • 用户创建命名计数器,在 Map 或 Reduce 函数中递增。
    • Master 汇总各任务计数值并排除重复执行产生的影响。
    • 计数值实时显示在状态页面上。
  • 用途:
    • 数据校验(如确保输入与输出对数一致)。
    • 监控进度与操作逻辑。

这些扩展功能提高了 MapReduce 的灵活性、调试便利性以及操作效率,适配了多种场景和需求。

5 性能分析

在本节中,我们测量了 MapReduce 在一个大型集群上运行的两个计算任务的性能。这两个计算任务分别是:在约 1TB 的数据中搜索特定模式,以及对约 1TB 的数据进行排序。这两个程序代表了 MapReduce 用户编写的大量实际程序的子集:一类程序用于将数据从一种表示形式转换为另一种,另一类则从大规模数据集中提取少量有意义的数据。


5.1 集群配置

所有程序都在一个包含约 1800 台机器的集群上运行。每台机器的配置如下:

  • 处理器:两颗 2GHz 的 Intel Xeon 处理器,启用了超线程技术;
  • 内存:4GB,其中 1-1.5GB 被集群中的其他任务保留;
  • 磁盘:两块 160GB IDE 硬盘;
  • 网络:千兆以太网。

这些机器通过一个两级树状交换网络连接,根节点的总带宽为 100-200 Gbps。所有机器位于同一个机房中,机器之间的往返延迟小于 1 毫秒。

实验在周末下午进行,当时 CPU、磁盘和网络大多处于空闲状态。


5.2 Grep 程序性能

Grep 程序扫描 10¹⁰ 个 100 字节大小的记录,寻找一个相对稀少的三字符模式(该模式出现于 92,337 条记录中)。输入数据被分为约 64MB 的块(M=15000),所有输出最终存储为一个文件(R=1)。
请添加图片描述

运行过程

图 2 展示了计算随时间的进展:

  • Y 轴表示输入数据的扫描速率;
  • 速率随更多机器加入逐渐增加,在 1764 个工作节点全部参与时达到峰值超 30 GB/s
  • 随着 Map 任务完成,速率逐渐下降,约 80 秒后降为零;
  • 总运行时间约 150 秒,包括约 1 分钟的启动开销(如程序分发到工作节点、与 GFS 的交互延迟等)。

5.3 Sort 程序性能

Sort 程序对 10¹⁰ 个 100 字节的记录进行排序,总数据量约 1TB。该程序基于 TeraSort 基准测试模型编写,仅包含约 50 行用户代码:

  • 一个 3 行的 Map 函数提取 10 字节排序键并生成中间键值对;
  • Reduce 使用内置的 Identity 函数,直接输出中间键值对;
  • 排序结果写入 GFS,输出文件有两个副本,总大小为 2TB

运行过程

请添加图片描述

  • 输入数据分为 64MB 块(M=15000),最终输出被分为 4000 个文件(R=4000)。
  • 图 3(a) 显示正常运行时的数据传输速率:
    • 输入速率:峰值约 13 GB/s,因 Map 任务同时将中间数据写入本地磁盘,速率较 Grep 程序低;
    • Shuffle 阶段:约 600 秒时完成,速率峰值出现在 Reduce 任务初期;
    • 输出速率:由于写入双副本,总速率较低(约 2-4 GB/s),891 秒完成整个计算,接近当前 TeraSort 基准的最佳结果(1057 秒)。

5.4 备份任务的影响

图 3(b) 显示禁用备份任务的执行情况:

  • 大部分任务在 960 秒时完成,但最后 5 个 Reduce 任务完成耗时极长(约 300 秒);
  • 总运行时间 增加 44%,达到 1283 秒。

5.5 机器故障的影响

图 3© 显示故意杀掉 200 个工作进程的情况:

  • 几分钟后,集群调度器立即在原机器上重新启动了工作进程;
  • 重新执行的 Map 工作快速完成,输入速率短暂出现负值;
  • 总耗时 933 秒,仅比正常运行增加 5%。

由此可见,MapReduce 的容错机制非常有效,即使发生大规模故障也能快速恢复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值