MapReduce
简介
- 处理海量数据的分布式计算框架
- 数据分布式存储
- 作业调度
- 机器间通信等复杂问题
- 为何使用HDFS存储
- 系统可靠(通过其它节点快速恢复)
- 可扩展性
- 并发处理
- 注重数据处理的吞吐量
- MapReduce分而治之思想
- 单点策略
- 一个人数所有钞票,数出各种面值有多少张
- 分治策略
- 每个人分的一堆钞票,数出各种面值有多少张
- 汇总,每个人负责统计一种面值
- 单点策略
MapReduce计算框架
-
谈谈对shuffle的理解?mr计算框架的流程?什么是shuffle?
- map:
- 数据经过切片(input split)
- 每个输入的切片都会使用一个map进行处理
- map输出的结果会有一个环形内存缓冲区(大小100M ,当阈值达到80%,在本地创建一个溢写文件,然后将缓冲区的数据写入该文件)
- 数据涉及(排序 【快速排序】、合并 【目的:尽力减少写入磁盘的数据量;减少数据传输到下一个阶段的数据量】)
- 通过jobtracker中维护的整个集群的宏观信息,找到对应map的输出位置即可
- hash理解:决定数据分到哪个reduce中
- reduce有3个:0,1,2
- 100%3=1; 50%3=2; 10%3=1
- reduce
- 本身也有环形内存缓冲区,阈值也是 80M,生成一个spil文件
- 有后台线程不断将小文件合并为有序的大文件(排序【归并排序】,和合并)
- 将合并的数据交给reduce,作为reduce文件的输入,并执行内部的业务逻辑代码进行处理
- 最终结果输出到hdfs/本地
- shuffle阶段
- map任务的输出到reduce任务的输入的过程
- 在shuffle阶段,最致命的问题:网络带宽!!!
- 本质:
- 尽可能减少网络带宽带来的不必要的消耗
- 优化内存使用,减少磁盘的IO操作
- map:
-
block是底层的文件夹,map是无法直接读取的。需要将block转换为内部可以识别的record
-
为什么hdfs中的块不能设置过大或者过小?
- 过大: 在数据读取计算的过程中,如果过大容易导致网络传输时间较长,程序出现卡顿或者无响应,导致最终的失败恢复成本过高
- 过小
- 存储海量小文件会占用大量的NN内存资源
- NN对外界提供服务的时候会频繁进行文件传输,严重占用网络/CPU资源
MapReduce编程模型
- 通过mr实现wordcount(wc)
- 源数据:was the title the
- 结果数据:
- the 1
业务场景
- 面试的点!!
1. 通过文件名称模糊匹配到文件位置:find / -name "hadoop-streaming*"
2. 通过文件中的字符串内容找到对应的文件:find / -name "*.sh" | xargs grep streaming
- 业务场景1:统计词语出现的次数
map的输出,即为reduce的输入
import sys
current_word = None
sum = 0
for line in sys.stdin:
word, val = line.strip().split('\t')
if current_word == None:
current_word = word
if current_word != word:
print "%s\t%s" % (current_word, sum)
current_word = word
sum = 0
sum += int(val)
print "%s\t%s" % (current_word, str(sum))
1. is 1 cur=is word(下一个单词)=is sum=0+1=1
2. is 1 cur=is word(下一个单词)=is sum =1+1=2
3. ···=> is, 2
4. today 1 cur=today(下一个单词)=good sum=0+1=1
5. => today,1
cat 1.data | python map.py | sort -k1 | python red.py
统计词语
- 业务场景2:统计白名单中的单词
1.cat The_Man_of_Property.txt | python map.py mapper_func white_list | sort -k1 | python red.py reducer_func | head
- 业务场景3:展示用户购买了哪些订单?
import sys
cur = None
cur_list = []
for line in sys.stdin:
ss = line.strip().split('\t')
key = ss[0]
val = ss[1]
if cur == None:
cur = key
elif cur!=key:
print '%s\t%s'%(cur,','.join(cur_list))
cur = key
cur_list = []
cur_list.append(val)
print '%s\t%s'%(cur,','.join(cur_list))
cat 1.data | python map.py | sort -k1 |python red.py
or
cat 1.data | sort -k1 |python red.py
-
user_id order_idsort1 1
sort2 3
sort2 88
sort2 54
sort1 2
sort6 22
sort6 58
sort6 888
2. 结果数据:
sort1 1,2
sort2 3,54,88
sort6 22,58,888 -
业务场景4:
# map_a.py
import sys
for line in sys.stdin:
ss = line.strip().split(' ')
key = ss[0]
val = ss[1]
print "%s\t1\t%s" % (key, val)
# map_b.py
import sys
for line in sys.stdin:
ss = line.strip().split(' ')
key = ss[0]
val = ss[1]
print "%s\t2\t%s" % (key, val)
# red_join.py
import sys
val_1 = ""
for line in sys.stdin:
key, flag, val = line.strip().split('\t')
if flag == '1':
val_1 = val
elif flag == '2' and val_1 != "":
val_2 = val
print "%s\t%s\t%s" % (key, val_1, val_2)
val_1 = ""
1. 源数据:
* aaa1 123
* aaa1 hadoop
2. 结果数据:
* uid order_id amt
* aaa1 123 hadoop
快捷操作
vim
- vim编辑器里如何快速注释多行:
- Esc
- ctrl+v 显示数据块
- 按住向下箭头,选取行
- 输入“shift+i”,“shift+#”,两次“ESC”
- vim编辑器里如何快速取消注释
- ESC
- ctrl+v 显示数据块
- 按住向下箭头,选取行
- 输入“x”
- esc状态下 g+d:高亮显示需找单词的光标
- sh -x run.sh:调试脚本将变量信息进行输出(sh run.sh也可)
Hdoop Streaming
简介
- MapReduce和HDFS采用
- Streaming框架允许让任何语言编写的map,reduce程序额能够在
优点
- 开发效率高
- 程序运行效率高
- 便于平台进行资源控制