背景

Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

Mapreduce1 vs YARN

Mapreduce1

我们首先来看一下整体架构

  • JobTracker 是 Map-reduce 框架的中心,他需要与集群中的机器定时通信 (heartbeat), 需要管理哪些程序应该跑在哪些机器上,需要管理所有 job 失败、重启等操作
  • TaskTracker 是 Map-reduce 集群中每台机器都有的一个部分,他做的事情主要是监视自己所在机器的资源情况。TaskTracker 同时监视当前机器的 tasks 运行状况。TaskTracker 需要把这些信息通过 heartbeat 发送给 JobTracker,JobTracker 会搜集这些信息以给新提交的 job 分配运行在哪些机器上。上图虚线箭头就是表示消息的发送 - 接收的过程

我们接下来解释一下一个任务提交的整体流程

  1. 在客户端启动一个作业。
  2. 向JobTracker请求一个Job ID。
  3. 将运行作业所需要的资源文件复制到HDFS上,包括MapReduce程序打包的JAR文件、配置文件和客户端计算所得的输入划分信息。这些文件都存放在JobTracker专门为该作业创建的文件夹中。文件夹名为该作业的Job ID。JAR文件默认会有10个副本(mapred.submit.replication属性控制);输入划分信息告诉了JobTracker应该为这个作业启动多少个map任务等信息。
  4. JobTracker接收到作业后,将其放在一个作业队列里,等待作业调度器对其进行调度(这里是不是很像微机中的进程调度呢,呵呵),当作业调度器根据自己的调度算法调度到该作业时,会根据输入划分信息为每个划分创建一个map任务,并将map任务分配给TaskTracker执行。对于map和reduce任务,TaskTracker根据主机核的数量和内存的大小有固定数量的map槽和reduce槽。这里需要强调的是:map任务不是随随便便地分配给某个TaskTracker的,这里有个概念叫:数据本地化(Data-Local)。意思是:将map任务分配给含有该map处理的数据块的TaskTracker上,同时将程序JAR包复制到该TaskTracker上来运行,这叫“运算移动,数据不移动”。而分配reduce任务时并不考虑数据本地化。
  5. TaskTracker每隔一段时间会给JobTracker发送一个心跳,告诉JobTracker它依然在运行,同时心跳中还携带着很多的信息,比如当前map任务完成的进度等信息。当JobTracker收到作业的最后一个任务完成信息时,便把该作业设置成“成功”。当JobClient查询状态时,它将得知任务已完成,便显示一条消息给用户

可以看出第一代的mapreduce简洁明了,在刚推出的时候受到了广泛的欢迎,有许多成功的案例。但是随着集群规模越来越大,第一代模型渐渐暴露出了许多问题

  • JobTracker 是 Map-reduce 的集中处理点,存在单点故障
  • JobTracker 完成了太多的任务,造成了过多的资源消耗,当 map-reduce job 非常多的时候,会造成很大的内存开销,潜在来说,也增加了 JobTracker fail 的风险,这也是业界普遍总结出老 Hadoop 的 Map-Reduce 只能支持 4000 节点主机的上限
  • 在 TaskTracker 端,以 map/reduce task 的数目作为资源的表示过于简单,没有考虑到 cpu/ 内存的占用情况,如果两个大内存消耗的 task 被调度到了一块,很容易出现 OOM
  • 在 TaskTracker 端,把资源强制划分为 map task slot 和 reduce task slot, 如果当系统中只有 map task 或者只有 reduce task 的时候,会造成资源的浪费,也就是前面提过的集群资源利用的问题

于是有了第二代的mapreduce框架YARN

YARN

从上图可以看出有如下几种角色:

  • ResourceManager: 负责Job的调度、管理,资源的分配、管理的模块。它所管理的单位是Job(更为通用的叫法是Application),不再是具体的Task,因此能比传统的MapReduce支持更大规模的集群;
  • NodeManager:负责执行具体Task的模块。它不再有Slots的概念,取而代之的Container,Task都是通过在NodeManager上启动Container的方式来执行的;
  • ApplicationMaster:由YARN框架提供的一个Libary,每个用户Application(Job)会对应一个ApplicationMaster,在用户提交Application后,ResourceManager会启动该Application对应的ApplicationMaster, 并把ApplicationMaster的地址反馈给客户端,后续客户端直接跟ApplicationMaster进行交互。ApplicatoinMaster负责向* ResourceManager申请执行用户Task所需要的资源,以及管理用户Application中每一个Task的运行情况;
  • Container:抽象出来的资源集合的概念,它代表由ResouceManage授予给Application的资源,包括CPU、内存等。最终用户Task都是通过Container来执行的;
  • Client:负责向ResourceManager提交Application(Job)请求,并从ApplicationMaster获取执行结果。

我们接下来解释一下一个任务提交的整体流程

  1. 用户通过Client向ResourceManager提交Application,ResourceManager根据用户的请求,分配一个合适的Container,然后在指定的NodeManager上启动该Container运行ApplicationMaster;
  2. ApplicationMaster在NodeManager上启动后,向ResourceManager注册自己;
  3. ApplicationMaster跟ResourceManager协商、申请用户Task所需要的Container, 申请到后ApplicationMaster把Container描述发给指定的NodeManager,NodeManager启动Container,运行用户Task;
  4. 用户Task在Container中执行的过程中,会定期向ApplicationMaster汇报执行的进度、状态等信息;
  5. 在执行过程中,Client可以直接跟ApplicationMaster通信,获取整个Application执行的进度、状态等信息;
  6. 所有的Task执行结束后,整个Application执行结束,ApplicationMaster会向ResourceManager注销自己,释放资源,并退出运行。

hello world

我们每次学习一门新技术,接触的第一个例子往往都是hello world。在hadoop中的hello world是统计单词计数

mapper.py

import sys

for line in sys.stdin:
words = line.strip().split('\t')
for word in words:
print word

reducer.py

import sys

pred_word = None
pred_cnt = 0 for word in sys.stdin:
if pred_word == word:
pred_cnt += 1
else:
if pred_word:
print "\t".join([pred_word, pred_cnt])
pred_word = word
pred_cnt = 1
print "\t".join([pred_word, pred_cnt])

shell

bin/hadoop jar hadoop_streaming.jar \
-files mapper.py,reducer.py \
-D stream.num.map.output.key.fields=1 \
-input /xxx/ooo/setences.txt \
-output /xxx/ooo/wordcnt.txt \
-mapper "python mapper.py" \
-reducer "python reducer.py"

Map、Reduce任务中Shuffle和排序的过程

Map阶段分为Read-Map-Collect-Spill-Merge。Read读取数据,拆分为split,对每个Split执行Map函数,然后Map的输出进入Collect阶段。map的输出是(key, value), collect调用partitioner(线程首先根据reduce任务的数目将数据划分为相同数目的分区,也就是一个reduce任务对应一个分区的数据),获得输出(partition, key, value),存入环形缓冲区(该缓冲区的大小默认为100M,由io.sort.mb属性控制),并按照partition + key进行快速排序,如果有combiner,按照key进行聚合。缓冲区存储达到阈值时(默认为缓冲区大小的80%,由io.sort.spill.percent属性控制),发生spill,写入磁盘。一次spill吐出一个临时文件,信息还包含每个分区在spill文件中的偏移量,便于快速获取需要的分区。merge阶段,将多个spill临时文件进行归并排序,生成一个大文件,因此每个mapper最后输出一个文件。

Reducer阶段分为Copy-Sort-Reduce。Reducer会定期查看哪些mapper已经完成,并将其output位置放在scheduledCoppies列表里,然后启动多个MapOutputCopier线程,去ScheduledCopies列表里指定的远程位置去拷贝数据。Reducer只拷贝map输出文件里属于自己处理的partition,拷贝的数据存在内存中,放不下则生成文件。Sort阶段,对多个mapper拷贝来的结果进行归并排序,保证全局有序。然后将排序后的结果喂给reduce函数处理,保存处理结果至HDFS。

Shuffle过程就是Collect+Spill+Merge+Copy+Sort,由Hadoop框架实现。这样用户只需要关注业务逻辑相关的map逻辑和reduce逻辑。

控制map和reduce的个数

reduce的个数:

-D mapred.reduce.tasks

map的个数:

我们知道,文件在上传到Hdfs文件系统的时候,被切分成不同的Block块(默认大小为64MB)。但是每个Map处理的分块有时候并不是系统的物理Block块大小。实际处理的输入分块的大小是根据inputSplit来设定的,那么inputSplit是怎么得到的呢

InputSplit = Math.max(minSize, Math.min(maxSize, blockSize)

mapSize = totalSize/InputSplit

  • minSize=mapred.min.split.size
  • maxSize=mapred.max.split.size
  • totalSize 文件总大小

二级排序

二级排序是指Collect过程会在map输出结果的key前加入partition,reduce阶段首先根据自己负责的partition抓取map端的数据,然后再按照key进行排序。也即按照partition和key一起排序

实现join语句

SELECT u.name
, o.orderid
FROM order_info o
JOIN user_info u
ON o.uid = u.uid

可以参考美团点评博客

mapper.py

import os
import sys def read_input(file):
for line in file:
yield line.rstrip().split() def map(separator='\t'):
file_path = os.environ["mapreduce_map_input_file"]
file_source = os.path.basename(os.path.dirname(file_path))
data = read_input(sys.stdin)
for flds in data:
uid = flds[0]
if file_source == 'user_info':
name = flds[1]
print '\t'.join((uid, '1', name))
elif file_source == "order_info":
order_id = flds[1]
print '\t'.join((uid, '2', order_id)) if __name__ == "__main__":
map()

reducer.py

from operator import itemgetter
from itertools import groupby
import sys def read_mapper_output(file, separator='\t'):
for line in file:
yield line.rstrip().split(separator) def reduce(separator='\t'):
data = read_mapper_output(sys.stdin, separator=separator)
for sno, group in groupby(data, itemgetter(0)):
name =None
if group[1] == '1':
name = group[2]
elif group[1] == '2':
order_id = group[2]
if name:
print separator.join((sno, name, order_id)) if __name__ == "__main__":
reduce()

参考文献

Hadoop总结的更多相关文章

  1. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  2. 初识Hadoop、Hive

    2016.10.13 20:28 很久没有写随笔了,自打小宝出生后就没有写过新的文章.数次来到博客园,想开始新的学习历程,总是被各种琐事中断.一方面确实是最近的项目工作比较忙,各个集群频繁地上线加多版 ...

  3. hadoop 2.7.3本地环境运行官方wordcount-基于HDFS

    接上篇<hadoop 2.7.3本地环境运行官方wordcount>.继续在本地模式下测试,本次使用hdfs. 2 本地模式使用fs计数wodcount 上面是直接使用的是linux的文件 ...

  4. hadoop 2.7.3本地环境运行官方wordcount

    hadoop 2.7.3本地环境运行官方wordcount 基本环境: 系统:win7 虚机环境:virtualBox 虚机:centos 7 hadoop版本:2.7.3 本次先以独立模式(本地模式 ...

  5. 【Big Data】HADOOP集群的配置(一)

    Hadoop集群的配置(一) 摘要: hadoop集群配置系列文档,是笔者在实验室真机环境实验后整理而得.以便随后工作所需,做以知识整理,另则与博客园朋友分享实验成果,因为笔者在学习初期,也遇到不少问 ...

  6. Hadoop学习之旅二:HDFS

    本文基于Hadoop1.X 概述 分布式文件系统主要用来解决如下几个问题: 读写大文件 加速运算 对于某些体积巨大的文件,比如其大小超过了计算机文件系统所能存放的最大限制或者是其大小甚至超过了计算机整 ...

  7. 程序员必须要知道的Hadoop的一些事实

    程序员必须要知道的Hadoop的一些事实.现如今,Apache Hadoop已经无人不知无人不晓.当年雅虎搜索工程师Doug Cutting开发出这个用以创建分布式计算机环境的开源软...... 1: ...

  8. Hadoop 2.x 生态系统及技术架构图

    一.负责收集数据的工具:Sqoop(关系型数据导入Hadoop)Flume(日志数据导入Hadoop,支持数据源广泛)Kafka(支持数据源有限,但吞吐大) 二.负责存储数据的工具:HBaseMong ...

  9. Hadoop的安装与设置(1)

    在Ubuntu下安装与设置Hadoop的主要过程. 1. 创建Hadoop用户 创建一个用户,用户名为hadoop,在home下创建该用户的主目录,就不详细介绍了. 2. 安装Java环境 下载Lin ...

  10. 基于Ubuntu Hadoop的群集搭建Hive

    Hive是Hadoop生态中的一个重要组成部分,主要用于数据仓库.前面的文章中我们已经搭建好了Hadoop的群集,下面我们在这个群集上再搭建Hive的群集. 1.安装MySQL 1.1安装MySQL ...

随机推荐

  1. Python小白学习之路(二十一)—【迭代器】

    迭代器 1.迭代器协议 对象必须提供一个 next 方法,执行该方法要么返回迭代中的下一项,要么就引起一个Stoplteration异常,以终止迭代(只能往后走不能往前退) 2.可迭代对象 实现了迭代 ...

  2. JS滑动到页面底部

    window.scrollTo(0, document.documentElement.clientHeight); 该 window 对象在DOM有一个 scrollTo 滚动到打开窗口 的任意位置 ...

  3. AngularJS常用Directives实例

    在第一篇 认识AngularJS 中,我们已经基本了解了AngularJS,对Directive也有了一定了解,本章我们将继续介绍Directive,对其有一个更深入的了解和掌握. 常用的Direct ...

  4. RabbitMQ和Kafka对比以及场景使用说明

    我目前的项目最后使用的是RabbitMQ,这里依然是结合网上大神们的优秀博客,对kafka和rabbitmq进行简单的比对.最后附上参考博客. 1.架构模型 rabbitmq RabbitMQ遵循AM ...

  5. Java之集合(十)EnumMap

    转载请注明源出处:http://www.cnblogs.com/lighten/p/7371744.html 1.前言 本章介绍Map体系中的EnumMap,该类是专门针对枚举类设计的一个集合类.集合 ...

  6. 使用SharedPreference保存用户数据的步骤

    1. 声明 SharedPreferences sp; 2. 初始化 sp = this.getSharedPreferences("文件名", 0);//0代表的是私有 3. 获 ...

  7. Apache解析和绑定域名

    转载+修改 如果你想让你上线项目的域名解析的是你本地的IP,该怎么做呢?难道要一个个的改配置文件吗? 例 :域名为  aaa.com 端口默认为80. 我试图修改为8080端口,但是出错了 1.本地h ...

  8. 【转】Spark源码分析之-deploy模块

    原文地址:http://jerryshao.me/architecture/2013/04/30/Spark%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8B- ...

  9. docker 微镜像-alpine

    刚想找maven自动发布项目到tomcat, 突然看到个好玩的, docker微镜像 -- alpine 直接粘一段: Alpine Linux Docker镜像基于Alpine Linux操作系统, ...

  10. Joda-Time 学习笔记

    一 Jode-Time 介绍 任何企业应用程序都需要处理时间问题.应用程序需要知道当前的时间点和下一个时间点,有时它们还必须计算这两个时间点之间的路径.使用 JDK 完成这项任务将非常痛苦和繁琐.既然 ...