MapOutputBuffer理解(上)

本文深入剖析了MapReduce编程框架中的MapOutputBuffer类及其在shuffle过程中的作用。详细介绍了其环形缓存区的设计原理,包括k-v数据与索引数据的存储方式,以及触发spill进程的条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本框架

MapReduce编程框架大致上可分为map和reduce两个阶段,连接两个阶段的就是shuffle的过程。MapOutputBuffer就是shuffle中非常重要的一个类,它主要用来处理数据的缓存和排序。数据缓存,不用多说,看类名就可以看出来,这个buffer类一定会有累积数据加速写入的功能。至于排序,是因为reduce在后续copy数据时希望数据是有序排列的,这样可以避免再次遍历数据进行排序。

所以,在MapReduce编程框架设计之初,设计者就将map的输出涉及未有序的,即按照partition进行排列,每个partition的内部key再次排序,以减少后续reduce阶段的开销。


运行机制

运行机制我在之前的shuffle分析中有讲过,这里再简单回顾下。

MapOutputBuffer类里维护了一个环形缓存区,缓存区中存储了两种不同类型的数据,即k-v数据和索引数据(kvmeta),两者相邻但互不重叠,以一个临时的分界点equator进行区分。其中k-v数据是map处理之后的kv对数据,kvmeta数据是kv对在环形缓存区中的索引,每个meta信息由4个int组成,包括:value的起始位置、key的起始位置、partition值、value的长度。随着数据不断写入缓存区,但占用的内存达到一定的阈值时,便会触发spill进程将内存缓冲区的数据溢写到本地硬盘中。在spill之前,在缓存区数据还有个SortAndSpill操作,sort先把Kvbuffer中的数据按照partition值和key两个关键字升序排序,移动的只是索引数据,排序结果是Kvmeta中数据按照partition为单位聚集在一起,最终结果是同一partition内的按照key有序排列。具体流程如下:

  • equator初始位置为0。在写入数据时,k-v数据[raw data]是向上增长存储的(顺时针),kvmeta数据[meta data]是向下增长的(逆时针)。bufstart(溢写时raw数据的起始位置),bufend(溢写时raw数据的结束位置)和bufindex(raw数据的结束位置)都位于0处。kvstart(溢写时meta数据的起始位置), kvend(溢写时meta数据的结束位置)和kvindex(下次要插入的meta信息的起始位置)沿逆时针方向推进4个int的大小。此外,kvbuffer剩余空间(bufferRemaining)为sortmb(kvbuffer占用的内存总量)*spillper(溢写阈值)。
  • 当第一组raw数据写入后,先放入key再放入value,并在bufindex上累加key和value的字节,更新bufindex。再放meta data,从kvindex的基础上,加一个int放value的start的下标,依次放入key start、partition和value length。这样,meta就可以准确定位到刚才放入的raw data。kvindex跳到下一个存放meta data的位置(即kvindex+4),此时,kvstart, kvend, bufstart, bufend的位置不更新。bufferRemaining需减去刚才存放raw data和meta data占用的内存空间。
  • 依次存放后续的raw data和meta data。随着数据的不断写入,kvindex不断减少,bufindex不断增加,bufferRemaining也在不断减小。当bufferRemaining空间不足时便会触发spill的线程了。spill的触发可发生在写入meta数据或者raw数据时。
  • spill开始前,会先更新kvend和bufend的位置。因为kvindex标示的是下次要插入meta data的位置,所以kvend等于kvindex+4int,kvstart不变,标志第一个meta data写入的位置。bufend是最后raw data中value结束的位置,bufstart标志第一个key开始的位置。kvstart与kvend之间是全部meta data,bufstart与bufend之间是raw data。
  • 溢写过程是守护线程完成的,在溢写过程中仍然可以正常写入raw data和meta data。写入需要重新确定equator的位置,该位置位于kvend逆时针到bufend之间,也就是在空余空间的某个位置。由于写入的过程应尽量避免spill的影响,也就是写入的时候要利用当前的空余空间,而不应该侵入已经有数据的空间。kvbuffer中剩余空间的中间位置设为新的分界点,将bufindex指针移动到这个分界点,kvindex指针还是在下一个要插入meta的起始位置(分界点+4),然后两者继续按照既定的轨迹放置数据。注意剩下的可写入空间不应该是所有的空余空间,而是equator到kvend,bufend之间空间比较小的那个。任何一个用完,都代表不能继续写入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值