浅谈Hadoop中的shuffle机制

一、官方文件:

org.apache.hadoop.mapred (Apache Hadoop MapReduce Shuffle 3.3.1 API)

二、Shuffle在Map、Reduce两个阶段的主要作用

1.Mapper
每个MapperTask有一个环形内存缓冲区(环形缓冲区实质上是一个环形队列,环形队列是在实际编程极为有用的数据结构,它是一个首尾相连的FIFO的数据结构,采用数组的线性空间,数据组织简单,能很快知道队列是否满为空,能以很快速度的来存取数据。在MapOutputBuffer.init中创建。 ),用于存储map任务的输出。默认大小100MB(io.sort.mb属性),一旦达到阀值0.8(io.sort.spil.percent) ,一个后台线程把内容写到(spill)磁盘的指定自录(mapred.local.dir)下的新建的一个溢出写文件。
写磁盘前,要partition,sort,combiner。如果有后续的数据,将会继续写入环形缓冲区中,最终写入下一个溢出文件中。
等最后记录写完,合并全部溢出写文件为一个分区且排序的文件.
如果在最终合并时,被合并的文件大于等于3个,则合并完会再执行一次Combiner,否则不会。
2.Reducer
Reduce阶段启动 Fetcher 线程到已经完成 Map阶段 的节点上复制一份属于自己的数据,这些数据默认会保存在内存的缓冲区中,当内存的缓冲区达到一定的阀值的时候,就会将数据写到磁盘之上。在 Reduce 阶段远程复制数据的同时,会在后台开启两个线程对内存到本地的数据文件进行合并操作。在对数据进行合并的同时,会进行排序操作,由于 Map 阶段已经对数据进行了局部的排序,Reduce阶段只需保证 Copy 的数据的最终整体有效性即可。
在这里插入图片描述
在这里插入图片描述
map输出–>缓存区(buffer,默认100M)–>partition(在buffer标记) -->sort(将kv对的元数据进行排序,依然是在buffer内进行)–>spill(条件为buffer中的数据达到80%,即0.8时,开始溢写)到本地磁盘,产生溢写文件,将同一分区的数据聚集(此时数据是排序状态) -->n个溢写文件merge成一个文件–>fetch(reduce端的线程通过Http协议复制当前reduceTask要处理的分区数据,先复制到缓存,再根据缓存大小来决定是否产生文件)–>merge(reduce端会合并多个文件,最后一次合并不产生文件,直接在内存中输入reduce)

三、解析各个类以及其方法的具体作用

一、FadvisedChunkedFile

作用:发出在给定文件描述符上读取头条的请求。

二、FadvisedFileRegion

作用:传输数据。它将数据从磁盘传输到内存中的本地缓冲区,然后将数据从缓冲区传输到给定的字节通道。

三、ShuffleHandler

1.ShuffleMetrics

作用:统计失败的和成功的shuffle输出的数量

2.ReduceMapFileCount

方法:operationComplete(ChannelFuture future)
作用:统计正在等待的map数量并对其进行不同的操作,调用了sendMap(ReduceContext reduceContext)方法

3.ReduceContext

作用:维护每个 messageReceived() Netty 上下文的参数。允许来自 operationComplete() 的 sendMapOutput 调用

4.TimeoutHandler

作用:超时处理程序,如果超时则关闭连接

5.HttpPipelineFactory

  • 方法1:HttpPipelineFactory(Configuration conf, Timer timer)
    作用:创建一个sslFactory并添加相关配置和初始化,设置闲置状态处理程序

  • 方法2:getPipeline()
    作用:添加SSL引擎,Http请求解码器,Http块聚合器,Http响应编码器,块写入处理程序,shuffle,空闲状态处理程序,超时处理程序到pipeline

6.Shuffle

  • 方法1:Shuffle(Configuration conf)
    作用:shuffle的配置信息
  • 方法2:setPort(int port)
    作用:创建接口
  • 方法3:splitMaps(List mapq)
    作用:对map进行切割
  • 方法4:channelOpen(ChannelHandlerContext ctx, ChannelStateEvent evt)
    作用:将此时通道状态事件的通道添加到channel集群中
  • 方法5:messageReceived(ChannelHandlerContext ctx, MessageEvent evt)
    作用:验证http请求,填充标题,将http响应写入事件通道中,并调用sendMap(reduceContext)方法
  • 方法6:sendMap(ReduceContext reduceContext)
    作用:获取map输出的分区或者分块
  • 方法7:getErrorMessage(Throwable t)
    作用:获取错误信息
  • 方法8:getBaseLocation(String jobId, String user)
    作用:获取用户程序的基本位置,其中包含用户缓存,应用程序缓存以及应用程序的id
  • 方法9:getMapOutputInfo(String mapId, int reduce, String jobId, String user)
    作用:获取map输出的信息
  • 方法10:populateHeaders(List mapIds, String jobId,String user, int reduce, HttpRequest request, HttpResponse response,boolean keepAliveParam, Map<String, MapOutputInfo> mapOutputInfoMap)
    作用:将map输出信息放入mapOutputInfoMap,将数据缓冲区该对象写入header

7.AttemptPathInfo

作用:将存储路径更改为仅存储本地目录索引,而不是整个路径,效率更高。

8.AttemptPathIdentifier

  • 方法1:hashCode()
    作用:哈希码的转换
  • 方法2:toString()
    作用:字符串的转换
  • 方法3:equals(Object o)

9.MapOutputInfo

作用:获取map端输出的文件名以及索引记录

  • 方法1:serializeMetaData(int port)
    作用:将 shuffle 端口序列化为 ByteBuffer 以备后用。返回端口的序列化形式。

  • 方法2:deserializeMetaData(ByteBuffer meta)
    作用:用于反序列化 ShuffleHandler 返回的元数据的辅助函数。返回Shuffle Handler 监听的端口以提供 shuffle 数据。

  • 方法3:serializeServiceData(Token jobToken)
    作用:一个辅助函数,用于序列化 JobTokenIdentifier 作为 ServiceData 发送到 ShuffleHandler。返回jobToken 的序列化版本。

  • 方法4:deserializeServiceData(ByteBuffer secret)
    作用:用于反序列化

  • 方法5:initializeApplication(ApplicationInitializationContext context)
    作用:初始化应用程序,获取新的jobid并将其记录

  • 方法6:stopApplication(ApplicationTerminationContext context)
    作用:终止应用程序

  • 方法7:serviceInit(Configuration conf)
    作用:服务初始化

  • 方法8:serviceStart()
    方法:将shuffle端口添加至channel集群,并在HttpPipelineFactory建立shuffle端口

  • 方法9:serviceStop()
    作用:服务终止,取消注册源

  • 方法10:getMetaData()
    作用:获取元数据

  • 方法11:recoverState(Configuration conf)
    作用:恢复状态,并调用startStore(Path recoveryRoot)方法

  • 方法12:startStore(Path recoveryRoot)
    作用:打开数据库文件检查其版本,若本地数据库不存在则创建新的数据库

  • 方法13:loadVersion()
    作用:获取当前版本,如果先前未存储版本,则将其视为当前版本信息。

  • 方法14:storeSchemaVersion(Version version)
    作用:将状态架构数据库的版本KEY值以及版本信息存入状态数据库中

  • 方法15:checkVersion()
    作用:检查加载版本与当前版本是否兼容,若兼容则调用storeVersion()方法存储该版本信息

  • 方法16:addJobToken(JobID jobId, String user,Token jobToken)
    作用:添加一个用户和jobId至用户资源,并为该jobId添加一个jobToken(jobToken 用于身份验证 Shuffle 数据请求的工作令牌。)

  • 方法17:recoverJobShuffleInfo(String jobIdStr, byte[] data)
    作用:对获取的jobId进行判断,若可用则添加至用户资源中

  • 方法18:recordJobShuffleInfo(JobID jobId, String user,Token jobToken)
    作用:记录jobId的信息,并将其添加至状态数据库,并调用addJobToken(jobId, user, jobToken)

  • 方法19:removeJobShuffleInfo(JobID jobId)
    作用:在用户资源中删除该jobId,并在状态数据库中删除jobId

  • 方法20:setResponseHeaders(HttpResponse response,boolean keepAliveParam, long contentLength)
    作用:设置响应头

  • 方法21:sendMapOutput(ChannelHandlerContext ctx, Channel ch, String user, String mapId, int reduce, MapOutputInfo mapOutputInfo)
    作用:对map输出文件进行读操作,若当前channel为空则调用FadvisedFileRegion类,否则调用FadvisedChunkedFile类

  • 方法22:exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
    作用:异常捕获

四、大致思路

  1. initializeApplication()初始化应用程序通过appid获取新的jobid后调用recordJobShuffleInfo()记录jobid的信息,在recordJobShuffleInfo()中调用addJobToken()添加一个user和jobId至用户资源,并为该jobId添加一个jobToken

  2. serviceStart()先调用recoverState(conf)先获取恢复路径,若不为空则调用startStore(recoveryRoot)若本地数据库不存在则先创建数据库再打开并调用storeVersion()储存其版本信息,若存在则打开数据库文件再调用checkVersion()检查加载版本与当前版本是否兼容,若兼容则调用storeVersion()方法存储该版本信息。再对jobid的key值在数据库中进行迭代,若有与之匹配的key则调用recoverJobShuffleInfo()对新获取的jobid进行判断,若可用则添加至用户资源中。将shuffle端口添加至channel集群,并在HttpPipelineFactory建立shuffle端口

  3. Reduce端发来http请求之后,在messageReceived()中先调用verifyRequest()对http进行验证,再调用populateHeaders()填充标题,在populateHeaders()中调用setResponseHeaders()设置响应头。再调用sendMap(),在sendMap()中调用sendMapOutput()获取map输出的分区或者分块,即对map的输出文件进行读操作,并判断channel是否为空,若为空则对map输出文件进行传输,若不为空则对通道中的文件发起读取头条的请求。

五、优化策略

  1. 如果能估算map输出大小,就可以合理设置该值来尽可能减少溢出写的次数
  2. 如果map输出的数据量非常大,写入磁盘时压缩数据,因为这样会让写磁盘的速度更快,节约磁盘空间,并且减少传给reducer的数据量。
  3. 减少不必要的排序:并不是所有类型的Reduce需要的数据都是需要排序的,排序这个nb的过程如果不需要最好还是不要的好
  4. 调用reduce之前,map必须完成的最少比例
  5. reducer在copy阶段同时从mapper上拉取的文件数
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易霭珞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值