写在前面
结合自身的经验记录,mapreduce中的一些知识点以及一个wordcount小实践
MR知识点整理
核心思想:分而治之
- file:文件要存储在HDFS上,每个文件切分城多个一定大小(128MB)的block块(默认3个备份)存储在对个节点(DataNode,一下简称DN)上
- InputFormat:分位两部分:数据分割和记录读取器
- 数据分割(split):每个split分片包含着后一个block块中的开头部分(解决了跨block的问题)
- 记录读取器(Record Reader):每读取一条数据,调用一次map函数记录一次
- Map程序:需要根据自己的需求开发
- shuffle
- Partition分区:决定数据由哪个reduce处理,从而进行分区。比如采用hash,有N个reducer,那么数据{‘are’,‘1’} 的key ‘are’ 对n进行取模得到m,最后结果是{m, key, value},然后根据m进行分区
- MemoryBuffer:
内存缓冲区,每个map的结果和partition处理的key value结果都保存在缓存中
默认大小:100MB
溢写阈值:80%
缓存区的数据存储是{partition, key:value}的三元组形式组成,例如:
{‘1’, ‘the’:1}
{‘2’, ‘we’:1}
{‘1’, ‘do’:1} - sort:缓存区中按照key进行排序
- spill
1、内存缓冲区达到阈值后,溢写spill线程锁住这80M的缓冲区,开始将数据写出到本地磁盘中,写完之后释放80M内存
2、每次溢写都会生成一个数据文件
3、溢出的数据到磁盘之前会对数据进行key排序,以及合并combiner - Combiner:数据合并,将相同key的value值合并,减少输出的传输量,提升性能,通过Reducer类来定义
配置化
- 缓冲区大小设置:
core-site.xml设置为100M io.file.buffer.size=100000000 以字节为单位
- HDFS块大小设置
hdfs-site.xmldfs.blocksize=128000000
- 保留储存空间
hdfs-site.xmldfs.datanode.du.reserved=128000000
- 回收站保留时间
core-site.xmlfs.trash.interval=5 单位为分钟 默认值为0,表示回收站无效
- reduce的慢启动设置
mapreduce.job.reduce.slowstart.completedmaps=0.80 可以提高吞吐率
小实践
时间语言这边用的是python
数据源:随便找一篇英文文章,单词之间空格分割
map.py:
import sys
for line in sys.stdin:
list = line.strip().split(" ")
for word in list:
print("%s\t%s" % (word, '1'))
reduce.py
import sys
curr_word = None
sum = 0
for line in sys.stdin:
list = line.strip().split(" ")
if len(list) != 2:
continue
word, count = ss
if not curr_word:
curr_word = word
if curr_word != word:
print("%s\t%s" % (curr_word, str(sum)))
curr_word = word
sum = 0
sum += int(count)
print("%s\t%s" % (curr_word, str(sum)))
run.sh
HADOOP_CMD=/usr/local/src/hadoop-2.6.1/bin/hadoop
STREAM_JAR=/usr/local/src/hadoop-2.6.1/share/hadoop/tools/lib/hadoop-streaming-2.6.1.jar
INPUT_PATH="{your data}"
OUTPUT_PATH="/output_wc"
$HADOOP_CMD fs -rmr -skipTrash $OUTPUT_PATH
$HADOOP_CMD jar $STREAM_JAR \
-input $INPUT_PATH \
-output $OUTPUT_PATH \
-mapper "python map.py" \
-reducer "python red.py" \
-file ./map.py \
-file ./red.py \
-D "mapred.job.name=wordcount"