Map 端 spill 详解
-
Upload
montague-santos -
Category
Documents
-
view
128 -
download
7
description
Transcript of Map 端 spill 详解
MapMap 端端 spillspill 详解详解
俞灵2011-09-19
一个简单的例子一个简单的例子Wordcount 的 map 函数
◦ public void map(LongWritable key, Text value, ◦ OutputCollector<Text, IntWritable> output, ◦ Reporter reporter) throws IOException {◦ String line = value.toString();◦ StringTokenizer itr = new StringTokenizer(line);◦ while (itr.hasMoreTokens()) {◦ word.set(itr.nextToken());◦ output.collect(word, one);◦ }◦ }
output.collect(word, one); 是如何实现的呢
Mapreduce-64Mapreduce-64 前前 collectcollect 原原理理原理
◦使用三个数组 kvoffsets 记录索引 Kvindices key value 索引 Kvbuffer 存储 record
◦ Kvoffsets 或 Kvbuffer 达到 limit 便开始 spill
◦按照 partition 对 record 排序并 spill
参数解释参数解释初始值
◦ sm = Io.sort.mb << 20◦ rp = io.sort.record.percent ◦ sp = io.sort.spill.percent
三个数组长度◦ kvoffsets = new int[ sm*rp /16]◦ Kvindices = new int[ 3*sm*rp /16]◦ Kvbuffer = new byte[sm - sm*rp ]
两个 limit◦ softBufferLimit = kvbuffer.length * sp◦ softRecordLimit = kvoffsets.length * sp
初始状态
….
….
kvoffsets
kvindices
kvbuffer
kvstart
kvendkvinde
x
bufstart
bufendbufind
exbufmar
k
加入一条记录◦ (key,val) 长度分别为 (3,4)
….
….
kvoffsets
kvindices
kvbuffer
kvstart
kvendkvinde
x
bufstart
bufend
bufindex=7
bufmark=7
partition03
参数设置参数设置设置参数
◦sp=0.8◦rp=0.05◦sm=32000◦recordNum=sm*rp/16=1000◦kvlimit=recordNum*sp=800◦bufLen=sm*(1-rp)=30400◦buflimit=bufLen*sp=24320
Spill 开始前
….
kvoffsets
kvindices
kvbuffer
kvstart
kvendkvinde
x
bufstart
bufend
bufindex=9022
bufmark=9022
partition03
partition
…
57
…..
03
800
bvlimit=800
buflimit=24320
buflvoid= 30400
Spill 结束后
kvoffsets
kvindices
kvbuffer
kvstart
kvendkvinde
x
bufstart
bufend
bufindex=9925
bufmark=9924
partition03
partition
…
57
…..
03
800
bvlimit=800
buflimit=24320
buflvoid= 30400
900
9924
Collect 流程collect(key,
value)
spilllock
计算kvfull,kvsoftlimit
开始 spill
是否达到 limit且在 spill
是否 full
等待 spill 结束
是否 full
unlock
写 key
Key 是否被分割
移动 key, 重置kvoid
写 value
写索引 , 更新kvindex
yes
yes
yes no
yes
nono
no
write 流程 Write
Spilling?
是否有记录
yes
达到 limit或写不下
写得下
no
复制数据更新bufindex
计算buffull,warp
计算 buflimit
Start spill
MapBufferTooSmall
写得下
Wait spill
写得下
yes
yes
yes
yes
yes
no
no
no
no
no
流程解释流程解释三个触发 spill 的地方
◦ kv 达到 limit(kvstart == kvend && kvsoftlimit)◦ buf 达到 limit
kvstart == kvend, kvend != kvindex 有 record bufsoftlimit || (buffull && !wrap))
◦ 单条记录过长 kvend == kvindex 无 record buffull && !wrap
Wrap◦ True: 可以存下单条记录 , 需要调头◦ 处理一条记录垮首尾的情况
流程解释流程解释Block 的地方
◦ Kvfull◦ buffull && !wrap ( 无法写入下一条记录 )
单条记录超过剩余容量◦ MapBufferTooSmallException◦ spillSingleRecord
Bufvoid 的作用◦ 可用 buf 大小◦ 防止 key 调头 ( 利于 spill 时计算 )
问题◦ 内存未充分利用◦ Block 地方两个 , 程序慢
Mapreduce-64Mapreduce-64原理
◦把三个数组合并成一个数组◦总内存超过限制才 spill
问题◦单个数组如何存储 int 和 byte
Creates a view of byte buffer as an int buffer
kvmeta = ByteBuffer.wrap(kvbuffer).asIntBuffer();
◦如何存储索引和 record 双向存储
Mapreduce-64 原理图
Mapreduce-64 原理图
Collect 流程collect(key,
value)
计算bufremain
lock
Bufremain 是否小于
0
是否可回收内存 l
计算 used, buflimit
是否在spill
是否要spill
回收内存
开始 spill, 重置参数
写 key
Key 是否被分割
移动 key, 重置kvoid
写 value
写索引 , 更新kvindex
no
unlock
no
no
no
no
yes
yes
yes
yes
yes
Write 流程Write()
复制数据更新bufindex
BufferTooSmall
计算bufremainBufremain 是否小
于 0
lock
计算可用空间
计算blockwrite
是否在spill
是否blockwri
te
是否可回收内存 l
回收内存
是否有记录
Startspill 重置bufmark
是否blockwrit
e
等待 spill
是否blockwrit
e
noyes
yes
no
no
no
no
nono
yes
yes
yes
yes
yes
流程解释流程解释Spill 条件
◦ bufsoftlimit && kvindex != kvend( 有记录 )◦ 下一条记录过长
Block 的情况 : blockwrite◦ distkvi <= distkve? distkvi <= len + 2 * METASIZE: distkve
<= len || distanceTo(bufend, kvbidx) < 2 * METASIZE;
Bufremain 的计算◦ min( distanceTo(bufindex, 4*kvindex) - 2 * METASIZE,softLimit -
bUsed) - METASIZE;
◦ min( distanceTo(bufend, newPos), min(distanceTo(newPos, 4*kvend), softLimit) ) - 2 * METASIZE
预留两个 metasize ?
sortAndSpillsortAndSpill 流程流程修改前后流程不变
◦ 获取文件名及输出流◦ 获取需要 spill 的 kv 首尾位置◦ 根据 partition 对 kv 排序◦ 根据是否需要 combine 进行输出
由 partitnion 从小到大输出 相同 partition 合并成一条记录输出
◦ Spill 计数器加一 , 关闭输出流