前言
每天在互联网上产生的数据量是巨大的。比如,根据英特尔公司的首席执行官Brian Krzanich的说法,2020年,互联网当中的用户每天产生大约1.5GB的数据。放到全球,每年会产生的数据将从2018年的33ZB增长到175ZB(1ZB = 1万亿亿字节),相当于每天产生491EB(1EB = 100万PB)的数据。另外,Facebook每天就能产生4,194,304GB的数据。这也只是大概估算的数字,而具体每天互联网所产生的数据量可能因各种因素而异。
对于这些庞大的数据,如何去筛选辨别那一定不是人工可以做到的。所以这些数据一般会被作为一些大数据机器的输入。而因为其数据量十分庞大,单机器的瓶颈就非常的突出,所以一般用于处理的都是大集群。
图片来源:IDC 数据时代2025
什么是MapReduce
MapReduce是Google提出的一个关于实施大数据集处理以及大型数据生成的编程模型。该模型是基于Key-Value键值对的。 它将数据的处理划分成两个阶段,Map 阶段与 Reduce阶段。在Map阶段,Map函数会将Key-Value键值对处理成一个Key-List<Value>的集合,而在Reduce阶段,Reduce函数会将这些Key-List<V> 进行按照Key相同进行合并,并得到最终结果。
选取键值对的原因是,这种数据在互联网上是最常见的,很多现实中的问题都可以利用这种模式解决。以这种编程模型写的程序,可以轻松在一大群机器上并行、自动执行。
在谷歌提出的MapReduce论文中提到:他们已实现的MapReduce程序运行在一个大型商品级机器集群上,而且具有高度的可拓展性:一个典型的MapReduce计算可以在数千台机器上处理TB级别的数据。
程序员们发现系统很容易使用:已经有数以百计的MapReduce程序被实现,并且每天都有一千以上的MapReduce任务运行在谷歌的(计算机)集群中。
MapReduce的执行方式的提出,让没有任何并行计算、分布式系统的经验的程序员们都可以轻松利用大型分布式系统中的资源,简单来说,就是让这个处理方式变得更加简单,程序员可以更加关注资源的利用而不是在程序设计上。
MapReduce 的使用
URL的访问频率计数
- Map阶段,利用Map函数来处理来自许多网页的处理日志,并且输出<URL,1>的键值对。
- Reduce阶段,收集好了所有的<URL,1>键值对后,按照URL对进行合并,此时得到一个<URL,List<1,1,1,1...>>,最终得到一个结果:<URL,Len(List<1,1,1,1...>),就是访问频率。
分布式排序
- Map阶段,Map函数提取出每个记录中的Key值,并且返回一个<Key,Record>格式的键值对。
- Reduce阶段, Redu都e函数对所有的Key-Value都值对不做修改直接返回。
MapReduce 编程模式的实现

上图便是一个十分简洁明了的例子。我们在一个集群中,一般会有主从之分,这样更加方便任务的分发与调度。
系统角色定义
- Master:主程序,用户派发任务,调度Worker执行任务,以及监控Worker任务运行状态,如果Worker迟迟未回复任务完成,那么他将会把任务派发给另外的Worker执行确保容错。
- Worker:持续向Master寻求任务,拿到任务执行并返回结果。
说白了,就是一个老板Master,与一群打工仔Worker
任务的定义
在该编程模式中,存在两种任务,一种是Map任务,一种是Reduce任务。Reduce任务必须在Map任务全部执行完成之后才能被执行。
Master 与 Worker的通信
各个机器之间通过RPC(Remote Promote Call)进行调用。通常来说消耗小,并且效率高
Master中的数据结构定义
Master中维护了一些数据结构。对于每一个Map和Reduce任务,Master存储了对应的任务的状态 (闲置的,运行中,或者已完成),以及Worker机器的id (针对非空闲的任务)。 并且Master中也存储了有Map执行后所产生的中间态文件信息(大小、位置等),因此派发Reduce任务时,也会将中间态文件一并传输过去。
执行流程
当用户程序调用MapReduce函数时,会发生以下的一系列动作
- 在用户程序中的MapReduce库先将输入的文件拆成M份,具体大小可由用户自行去控制。然后这些文件将被划分成M份。随后,便在集群中的一组机器上启动多个程序的副本。
- 其中一个副本被定义为Master。剩下的都是Worker。Master将会分配任务给Worker。任务类型是Map或者是Reduce
- 一个被分配了Map任务的Worker,从输入的数据中解析出Key-Value键值对,并将每一个Key-Value键值对作为参数传递给用户自定义的Map函数。Map函数产生的中间态Key-Value键值对会被缓存在内存之中。
- 这些在内存中的Key-Value键值对会被划入R个磁盘区域,并且位置会传输回Master进行保存,后续将发送给执行Reduce任务的Worker。
- 当Worker收到了Reduce任务后,Master会将那些位置信息一并发送。Worker则可通过RPC从Worker机器的本地磁盘中读取被缓存的数据。 这些数据将被排序。
- 负责Reduce任务的Worker迭代所有被排好序的中间态数据,并将所遇到的每一个唯一的Key值和其对应的中间态Value值集合传递给用户自定义的Reduce函数。Reduce函数所产生的输出将会追加在一个该Reduce分区内的、最终的输出文件内。
- 当所有的Map任务和Reduce任务都完成后,Master将唤醒用户程序执行后续操作。
Fault Tolerance (容错)
容错机制在分布式集群下非常重要,这主要依靠心跳检测
Worker Failure
Master周期性的向每一个Worker进行ping操作。如果说在一定时间内没有收到ping的回复,那么Master会将该Worker标记为发生故障(Failed)。此时Master会将由该Worker执行的Map/Reduce从运行中重置为未执行。并且这些重置后的任务,将被继续分配给其他空闲的Worker。
Master Failure
Master会定期将其定义的存储数据进行持久化。如果一旦宕机,重启过后直接读取这个备份节点,从该节点开始继续执行任务,这样也不会对任务结果造成任何影响。
总结
整个MapReduce流程看下来,这就是简直是分而治之思想的实践。并且分布式也是在这种大规模数据量,单机器瓶颈的情况下产生的。大致了解了MapReduce后,建议去完成Mit 6.824 实验一 单词计数(Lab 1: MapReduce)。自己手写一个简易的MapReduce试试!
注:本文的内容来自于谷歌的MapReduce论文,以及自己学习后的思考。如果可以,建议你去阅读全篇论文。
学习资料: