草庐IT

分布式计算MapReduce究竟是怎么一回事?

JAVA旭阳 2023-03-28 原文

​前言

如果要对文件中的内容进行统计,大家觉得怎么做呢?一般的思路都是将不同地方的文件数据读取到内存中,最后集中进行统计。如果数据量少还好,但是面对海量数据、大数据的场景这样真的合适吗?不合适的话,那有什么比较好的方式进行计算呢?不急,看完本文给你答案。

分布式计算思想

我们打开思路,既然文件数据遍布在各个节点上,那么我们就不把文件从各个节点加载过来,而是把算法分到各个节点进行计算,最后统一进行合并处理。这就是所谓的分布式计算。

 分布式计算将该应用分解成许多小的部分,分配给多台计算机进行处理。这样可以节约整体计算时间,大大提高计算效率。

整个思想的核心就是“先分再合,分而治之”。所谓“分而治之”就是把一个复杂的问题,按照一定的“分解”方法分为等价的规模较小的若干部分,然后逐个解决,分别找出各部分的结果,然后把各部分的结果组成整个问题的最终结果。 

那么Hadoop也借鉴了这样的思想,设计出了MapReduce计算框架。那么MapReduce框架具体设计上有什么亮点呢?

MapReduce设计思想

Hadoop在设计MapReduce的时候,吸取了分布式计算中分而治之的思想,同时需要考虑更多细节的问题。

(1)如何对付大数据处理场景

对相互间不具有计算依赖关系的大数据计算任务,实现并行最自然的办法就是采取MapReduce分而治之的策略。

首先Map阶段进行拆分,把大数据拆分成若干份小数据,多个程序同时并行计算产生中间结果;然后是Reduce聚

合阶段,通过程序对并行的结果进行最终的汇总计算,得出最终的结果。 

不可拆分的计算任务或相互间有依赖关系的数据无法进行并行计算。

(2)构建抽象编程模型

MapReduce借鉴了函数式语言中的思想,用Map和Reduce两个函数提供了高层的并行编程抽象模型。

map: 对一组数据元素进行某种重复式的处理;

reduce: 对Map的中间结果进行某种进一步的结果整理。

MapReduce中定义了如下的Map和Reduce两个抽象的编程接口,由用户去编程实现:

map: (k1; v1)(k2; v2)
reduce: (k2; [v2])(k3; v3)
通过以上两个编程接口,大家可以看出MapReduce​处理的数据类型是<key,value>键值对。

(3)统一架构、隐藏底层细节

如何提供统一的计算框架,如果没有统一封装底层细节,那么程序员则需要考虑诸如数据存储、划分、分发、结果

收集、错误恢复等诸多细节;为此,MapReduce设计并提供了统一的计算框架,为程序员隐藏了绝大多数系统层

面的处理细节。

MapReduce最大的亮点在于通过抽象模型和计算框架把需要做什么(what need to do)​与具体怎么做(how to do)分开了,为程序员提供一个抽象和高层的编程接口和框架。

程序员仅需要关心其应用层的具体计算问题,仅需编写少量的处理应用本身计算问题的业务程序代码。 

至于如何具体完成这个并行计算任务所相关的诸多系统层细节被隐藏起来,交给计算框架去处理: 从分布代码的执行,到大到数千小到单个节点集群的自动调度使用。

MapReduce介绍

Hadoop MapReduce是一个分布式计算框架,用于轻松编写分布式应用程序,这些应用程序以可靠,容错的方式并行处理大型硬件集群(数千个节点)上的大量数据(多TB数据集)。

MapReduce是一种面向海量数据处理的一种指导思想,也是一种用于对大规模数据进行分布式计算的编程模型。

MapReduce特点

易于编程

Mapreduce框架提供了用于二次开发的接口;简单地实现一些接口,就可以完成一个分布式程序。任务计算交给计算框架去处理,将分布式程序部署到hadoop集群上运行,集群节点可以扩展到成百上千个等。

良好的扩展性

当计算机资源不能得到满足的时候,可以通过增加机器来扩展它的计算能力。基于MapReduce的分布式计算得特点可以随节点数目增长保持近似于线性的增长,这个特点是MapReduce处理海量数据的关键,通过将计算节点增至几百或者几千可以很容易地处理数百TB甚至PB级别的离线数据。

高容错性

Hadoop集群是分布式搭建和部署得,任何单一机器节点宕机了,它可以把上面的计算任务转移到另一个节点上运行,不影响整个作业任务得完成,过程完全是由Hadoop内部完成的。

适合海量数据的离线处理

可以处理GB、TB和PB级别得数据量。

MapReduce局限性

MapReduce虽然有很多的优势,也有相对得局限性,局限性不代表不能做,而是在有些场景下实现的效果比较差,并不适合用MapReduce来处理,主要表现在以下结果方面:

实时计算性能差

MapReduce主要应用于离线作业,无法作到秒级或者是亚秒级得数据响应。

不能进行流式计算

流式计算特点是数据是源源不断得计算,并且数据是动态的;而MapReduce作为一个离线计算框架,主要是针对静态数据集得,数据是不能动态变化得。

MapReduce实战

WordCount算是大数据计算领域经典的入门案例,相当于Hello World。主要是统计指定文件中,每个单词出现的总次数。 

虽然WordCount业务极其简单,但是希望能够通过案例感受背后MapReduce的执行流程和默认的行为机制,这才是关键。

Map阶段代码实现

实现了map接口,把输入的数据经过切割,全部标记1,因此输出就是<单词,1>。

Reduce阶段代码实现

实现了reduce接口,对所有的1进行累加求和,就是单词的总次数

启动代码

可以参考官方例子:https://github.com/apache/hadoop/blob/branch-3.3.0/hadoop-mapreduce-project/hadoop-mapreduce-examples/src/main/java/org/apache/hadoop/examples/WordCount.java

运行

hadoop jar hadoop-mapreduce-examples-3.3.0.jar wordcount
/input /output
  • 第一个参数:wordcount表示执行单词统计任务;
  • 第二个参数:指定输入文件的路径;
  • 第三个参数:指定输出结果的路径(该路径不能已存在)
查看运行结果

最终可以在/output目录下看到输出的结果

MapReduce执行流程

从资源运行层面,一个完整的MapReduce程序在分布式运行时有三类程序,如下所示:

  • MRAppMaster:负责整个MR程序的过程调度及状态协调
  • MapTask:负责map阶段的整个数据处理流程
  • ReduceTask:负责reduce阶段的整个数据处理流程

MapReduce任务优先会提交到Yarn组件上,这个主要是用来管理资源的,因为计算需要CPU、内存等资源。首先会运行1个MRAppMaster​程序,主要负责整个MR程序的过程调度及状态协调。然后运行多个MapTask​,最后运行ReduceTask。

从业务逻辑层面上,以上面的wordCount为例,它的运行流程如下图所示:

Map阶段执行流程

  • 第一阶段:把输入目录下文件按照一定的标准逐个进行逻辑切片,形成切片规划。默认Split size = Block size(128M)​,每一个切片由一个MapTask处理。
  • 第二阶段:对切片中的数据按照一定的规则读取解析返回<key,value>对。默认是按行读取数据。key是每一行的起始位置偏移量,value是本行的文本内容。
  • 第三阶段:调用Mapper类中的map方法处理数据。每读取解析出来的一个<key,value>,调用一次map方法。
  • 第四阶段:按照一定的规则对Map输出的键值对进行分区partition。默认不分区,因为只有一个reducetask。分区的数量就是reducetask运行的数量。
  • 第五阶段:Map输出数据写入内存缓冲区,达到比例溢出到磁盘上。溢出spill的时候根据key进行排序sort。默认根据key字典序排序。
  • 第六阶段:对所有溢出文件进行最终的merge合并,成为一个文件。

Reduce阶段执行过程

  • 第一阶段:ReduceTask会主动从MapTask复制拉取属于需要自己处理的数据。
  • 第二阶段:把拉取来数据,全部进行合并merge,即把分散的数据合并成一个大的数据。再对合并后的数据排序。 
  • 第三阶段是对排序后的键值对调用reduce方法。键相等的键值对调用一次reduce方法。最后把这些输出的键值对写入到HDFS文件中。

shuffle阶段

  • Shuffle的本意是洗牌、混洗的意思,把一组有规则的数据尽量打乱成无规则的数据。
  • 而在MapReduce中,Shuffle更像是洗牌的逆过程,指的是将map端的无规则输出按指定的规则“打乱”成具有一定规则的数据,以便reduce端接收处理。 
  • 一般把从Map产生输出开始到Reduce取得数据作为输入之前的过程称作shuffle。

以上就是整个MapReduce执行的整个流程。

总结

MapReduce是Hadoop提供的一个分布式计算框架,对于大数据开发人员来说,只要关注于自己的业务,实现他们提供的Map和Reduce接口,接下来底层都交给Hadoop来处理。但是MapReduce已经日薄西山,企业用的也越来越少了,慢慢被Spark、Flink等计算引擎代替,主要原因还是太慢,比如shuffle阶段中频繁涉及到数据在内存、磁盘之间的多次往复,但是这种计算思想还是很值得一学的。

有关分布式计算MapReduce究竟是怎么一回事?的更多相关文章

  1. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  2. Ruby——嵌套类和子类是一回事吗? - 2

    下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby​​解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc

  3. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  4. ruby - 怎么来的(a_method || :other) returns :other only when assigning to a var called a_method? - 2

    给定以下方法:defsome_method:valueend以下语句按我的预期工作:some_method||:other#=>:valuex=some_method||:other#=>:value但是下面语句的行为让我感到困惑:some_method=some_method||:other#=>:other它按预期创建了一个名为some_method的局部变量,随后对some_method的调用返回该局部变量的值。但为什么它分配:other而不是:value呢?我知道这可能不是一件明智的事情,并且可以看出它可能有多么模棱两可,但我认为应该在考虑作业之前评估作业的右侧...我已经在R

  5. ruby-on-rails - 我该怎么办 :remote location validation with CarrierWave? - 2

    我在我的Rails3示例应用程序上使用CarrierWave。我想验证远程位置上传,因此当用户提交无效URL(空白或非图像)时,我不会收到标准错误异常:CarrierWave::DownloadErrorinImageController#createtryingtodownloadafilewhichisnotservedoverHTTP这是我的模型:classPaintingtrue,:length=>{:minimum=>5,:maximum=>100}validates:image,:presence=>trueend这是我的Controller:classPaintingsC

  6. ruby - 分布式事务和队列,ruby,erlang,scala - 2

    我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和

  7. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  8. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - 使用 Ruby,计算 n x m 数组的每一列中有多少个 true 的简单方法是什么? - 2

    给定一个nxmbool数组:[[true,true,false],[false,true,true],[false,true,true]]有什么简单的方法可以返回“该列中有多少个true?”结果应该是[1,3,2] 最佳答案 使用转置得到一个数组,其中每个子数组代表一列,然后将每一列映射到其中的true数:arr.transpose.map{|subarr|subarr.count(true)}这是一个带有inject的版本,应该在1.8.6上运行,没有任何依赖:arr.transpose.map{|subarr|subarr.in

随机推荐