Hadoop权威指南笔记①(HDFS,MR)

第三章 Hadoop分布式文件系统

一、数据流

读数据

客户端通过调用FileSystem对象的open()方法来打开希望读取的文件,DistributedFileSystem通过RPC来调用Namenode,以确定文件起始块的位置;对于每一个块,Namenode返回存有该副本的datanode的地址。这些datanode根据它们与客户端的距离来排序(根据集群的网络拓扑结构)
PS:如果该客户端本身就是一个datanode,并保存有该数据块的副本时,该节点就会从本地datanode提取数据块。

读取数据API流程

客户端对输入流调用read()方法,DFSInputStream(存储文件起始几个块的datanode地址)连接最近的datanode;反复调用read()方法,将数据从datanode传输到客户端。到达块的末端,DFSInputStream关闭与datanode的连接,然后寻找下一个块的最佳datanode;客户端从流中读取数据按照DFSInputStream与datanode的连接顺序读取的。询问namenode检索下一批数据块的datanode位置,当客户端无法读取时,对FSDataInputStream调用close()方法。
如果文件有损坏,则从另一个最邻近datanode读取数据,也会记住故障datanode,以后不会反复读取节点上后续的块,并从其他datanode读取之前通知namenode。这种设计使HDFS扩展到大量的并发客户端。namenode只需要响应块位置(这些信息存储在内存中,高效)的请求,

写数据

client通过对DistributedFileSystem对象调用create()函数新建文件。(namenode执行检查确保文件不存在,以及客户端又新建文件的权限);DistributedFileSystem向客户端返回FSDataOutputStream对象(该对象封装一个DFSoutPutstream对象),处理datanode与namenode之间的通信

写入数据API流程

DFSOutputStream将数据分成数据包,写入内部队列–<数据队列dataqueue>。DataStreamer处理数据队列:根据datanode列表来要求namenode分配合适的新块来存储数据复本。这一组datanode构成一个管线:DataStreamer将数据包流式传输到管线中第一个datanode,该datanode存储并且将数据包发送到管线中的第2个,第2个发送给第3个……直至复本数量足够。同事DFSOutputStream也维护者一个内部数据包队列等待datanode的收到确认回执–<确认队列>,收到管道中所有datanode的确认信息后,该数据包才会从确认队列删除。
如果数据写入datanode故障,那么:首先关闭管线,把队列中数据添加回数据队列前端,以确保故障的节点下游不会漏掉数据,在正常存储的datanode的当前数据块指定标识,并将标识传送给namenode,以便故障的datanode回复后可以删除已经存储了的部分数据块。从管线中删除故障数据节点并且把剩下的数据块写入管线中另外的datanode,namenode注意到块复本量不足时,会自动创建新的复本。
客户端完成数据写入后,对数据流调用close()方法:将剩余所有数据包写入datanode管线,等待确认。namenode已经知道文件的块存储,他在返回成功前只需要等待数据块来进行最小量的复制。
复本存放要权衡三个要素:可靠性,写入带宽,读取带宽。
Hadoop默认布局策略:在运行客户端的节点放第一个复本。(客户端运行在集群之外,则随机,避免存储太满或太忙的节点),第二个放在离架中的节点上(非复本①的机架),第三个同第二个机架,不同节点。其他复本放在集群随机选择节点,确定复本的放置位置,会根据网络拓扑创建一个管线。(存储在两个机架中,很好的负载均衡);写入带宽(写入操作,遍历一个交换机);读取性能(可以从两个机架中选择读取);集群中块均匀分布。

第五章 MapReduce应用开发

一、作业历史

作业历史包括已完成作业的事件和配置信息,提供信息日志。存放在jobTracker本地文件系统中logs/history子目录中。默认保存30天。

二、作业调优

作业调优检查表

mapper数量:mapper需要运行时间,用更少的mapper运行更长的时间。时间长短取决于使用的输入格式。
reducer数量:高性能,集群中reducer数略少于reducer任务数。这使reducer能够在同一周期完成任务,并充分使用集群
combiner:作业能否充分利用combiner来减少通过shuffle传输的数据量
中间值压缩:对map输出压缩能使作业执行的更快
自定义序列:使用自定义writable/comparator,则必须确保已实现RawComparator
调整shuffle:MapReduce的shuffle过程可以对一些内存管理的参数进行调整

将问题分解成MapReduce作业

数据处理任务都是使用两个或更多的MapReduce作业来实现的。
mapper:一般执行输入格式解析,投影(选择相关的字段)和过滤(去掉无关记录)。
ChainMapper类库将多个mapper连接成一个mapper,结合使用ChainReducer可以在一个MapReduce作业中运行一系列的mapper,再运行一个reducer和另一个mapper链!

JobControl

MapReduce工作流中的作业不止一个时,需要管理按照顺序执行。主要考虑是否有一个线性的作业链或一个更复杂的作业有向无环图DAG。否则如果一个作业失败,就会抛出异常,管道后面作业无法执行,希望捕获异常并清除前一个作业输出的中间数据。
JobControl的实例表示一个作业的运行图,你可以加入作业配置,然后告知JobControl实例作业之间的依赖关系。在一个线程中运行JobControl时,它将按照依赖顺序来执行作业;可查看进程,查询错误失败信息,作业状态。如果一个作业失败,JobControl将不执行与之有依赖的后续作业。

第六章 MapReduce的工作机制

一、YARN

YARN划分两个独立的守护进程:管理集群上资源使用的资源管理器;管理集群上运行任务生命周期的应用管理器。
基本思路:应用管理器与资源管理器协商集群的计算资源:容器。每个容器都有特定的内存上限,在容器上运行特定应用程序进程。容器由集群节点上运行的节点管理器监视,以确保应用程序使用的资源不会超过分配的资源。
YARN的设计精妙之处,在于同的YARN应用可以在同一集群上共存。
每个MapReduce作业有一个专用的应用master,master进程协调在一组worker上运行的map任务和reduce任务。
MapReduce运行在YARN上,提供更多实体:
①提交MapReduce作业
②YARN资源管理器,负责协调集群上计算资源的分配
③YARN节点管理器,负责启动监视集群中机器上的计算容器
④MapReduce应用程序master负责协调运行MapReduce作业
⑤HDFS,用来与其他实体间共享作业文件

二、Hadoop使用YARN运行MapReduce的过程

MapReduce运行全流程


YARN的客户端<—->ResourceManager
客户端:向RM请求运行程序,返回提交程序的资源(jar,配置文件路径,应用ID等)
客户端:提交job资源(jar,分片信息等),提交完毕后通知RM。
RM得知提交后,封装task给RM的调度器,调度器分配各个容器(cpu,ram等),RM在NM的管理下在容器中启动应用程序的master进程(跟踪作业进度,完成报告),master运行yarn child来与NM通信,启动容器。
MRAppMaster向RM请求maptask资源,后各NM(含该文件切片)领取到任务,map输出。
MRAppMaster启动reduceTask,执行完后,获取各分区数据

三、shuffle和排序

系统执行排序的过程,也就是将map输出作为输入传给reducer称为shuffle。下面是shuffle原理

不是直接写入而是在内存里,环形缓冲区内不断写入,存储kv对;
每个分区内,后台线程按’K’来排序,如果有combiner则运行在排序之后,会使数据更紧凑;
溢出的文件spiller,多个小的spill file会merge成一个大的file(有分区标识)
多个MapTask输出的大spill file再次按照分区归并排序(k),合并文件后存储。
备注要点:环形缓冲区–>分区排序溢出后合并–>多个map输出按照分区归并排序–>合并文件结果

第七章 MapReduce的类型与格式

MapReduce的类型

Hadoop的MR中,map和reduce函数均遵循如下常规格式:
map: (k1,v1) -> list(k2,v2)
reduce: (k2,list(v2)) -> list(k3,v3)

Partitioner

#

默认的partitioner是HashPartitioner,它对每条记录的键进行哈希操作以决定该记录应该属于哪个分区。每个分区对应一个reducer任务,所以分区数等于作业的reducer的个数。(而对于mapper的个数,该数量等于输入文件被划分成的分块数,这取决于输入文件的大小以及文件块的大小)
键的哈希码被转换为一个非负整数—-由哈希值与最大的整形值做一次按位与操作而获得。然后用分区数进行取模操作,来决定该记录属于哪个分区索引。
默认情况下,只有一个reducer,因此默认就是一个分区。

#

关于选择reducer的个数
首先必须明确所有的中间数据放入一个reducer中,作业处理极其低效。注意,在本地模式运行作业时,只支持0,1个reducer。
常用设置:reducer数比总槽数(集群中节点数 x 每个节点的任务槽数),给reducer任务留点儿余地。如果reducer任务很大,则使用更多的reducer,使任务粒度更小。

输入格式

输入分片与纪录

一个输入分片split,就是由单个map操作处理的输入块;每个map操作,只处理一个输入分片;每个分片被划分为若干个记录,(也就是一个键/值对)

文本输入

TextInputFormat

TextInputFormat是默认的InputFormat,每条记录是一行输入。键是LongWritable类型,存储该行在文件中的字节偏移量。值是这行内容,被打包成一个Text对象。
输入分片与hdfs块:行的边界与hdfs块的边界可能不会对齐。造成的结果是多余的远程读取操作。
……等等不多赘述

多个输入时

读取多个文件输入,多个文件,可能会格式不同等等问题,此时运用MultipleInputs类妥善处理,允许为每条输入路径指定InputFormat和Mapper;不同数据格式的输入文件指定不同的mapper。但最重要的是mapper输出的数据类型一样,reducer收到聚集后的map的输出,并不知道由不同的mapper产生。

输出格式

文本输出

默认的输出格式是TextOutputFormat,它把每条记录写为文本行,他的键值对可以是任意类型,因为TextOutputFormat会调用.toString()方法把它们转为字符串,键值对由制表符分割。

多个输出时

即之前实验中不同地区流量的多个分区,输出到多个文件。
比如:按气象站区分气象数据,输出每个气象站对应一个文件。
必须做两件事:①写一个partitioner,把同一个气象站的数据放在同一个分区;②把作业的reducer数设为气象站的个数。
该partitioner完成L输入一个所有气象站ID列表,并且返回该气象站ID的索引。
考虑到实际,k,v 的数据可能不匹配,有多有少;应用程序严格限定分区数导致分区数少或者分区不均。比较好的是使用更少的reducer做更多的事情
最好让集群为作业决定分区数:集群的reducer的任务槽越多,作业完成的越快。这就是默认的HashPartitioner的优点,因为它处理的分区数不限,并且确保每个分区都有一个很好的键值组合使分区更均匀。

输出到自定义文件中

#

MultipleOutputFormat类可以将数据写到多个文件,这些文件名源于输出的键、值或者任意字符串。这允许每个reducer创建多个文件。name-m-nnnn是map输出的;name-r-nnnn是reduce输出。
name是由程序设定的任意名字
multipleOutputs.write(NullWritable.get(),vale,key.toString)

第八章 MapReduce的特性

排序

默认情况下,MR程序根据输入记录的键对数据集排序

控制排列顺序

键的排列顺序是由RawComparator控制的,规则如下。
①属性mapred.output.key.comparator.class显式设置,后者job类setSortComparatorClass()方法设置,则用该类的实例;
②否则,键必须是WritableComparator的子类,并使用针对该键类的已登记的comparator;
③如果没有已登记的comparator,则使用RawComparator将字节流反序列化为一个对象,再由WritableComparator的compareTo()方法进行操作

连接

采用更高级的框架Hive,将连接操作作为整个实现的核心部分
map端或者join端连接易造成数据倾斜,某端操作的数据量特别大
①map端连接:缓存数据,读取数据。然后,context.write(new Text(a_itemid), new Text(a_amount + “\t” + “:” + localpath + “\t” +b_name ));//在原有信息的基础上,添加上新表的数据。
②reduce端连接:将两表文件同时读取,自动shuffle后,对每个key的多个value进行字符串串联成一个数据。

当有多个value时,遍历时按照字段名分类存储

for (Text val : values){
  //将集合中的数据对应添加到Vector中
 if (val.toString().startsWith("a#")){
    vectorA.add(val.toString().substring(2));
  }
 else if (val.toString().startsWith("b#")){
    vectorB.add(val.toString().substring(2));
 }
}
//获取两个Vector集合的长度
int sizeA = vectorA.size();
int sizeB = vectorB.size();
//遍历两个向量将结果写出去
for (int i=0; i<sizeA; i++){
  for (int j=0; j<sizeB; j++){
    context.write(key, new Text(" " + vectorA.get(i) + " " + vectorB.get(j)));
 }
}

边数据分布

side data 是作业所需的额外的只读数据,辅助处理主数据集。所面临的挑战在于如何使用map或reduce任务都能够方便而高效的使用边数据。

分布式缓存

public void addCacheFile(URI uri)
缓存数据,完成map端的数据连接join

第九章 构建Hadoop集群

Hadoop集群构建步骤重在操作,简略说明,不再赘述

网络拓扑结构

Hadoop集群架构通常包含两级网络拓扑

如图,Rack为机架,各机架配备了30~40台服务器,共享1GB的交换机;各机架的交换机又通过上行链路与核心交换机与其他机架互联(同一机架内部的节点之间总带宽远高于不同机架上的节点间的带宽)

Hadoop补充

当Hadoop将MR程序分配到各个节点时,会倾向于执行机架内的数据传输(因为拥有更多带宽),而非跨越机架进行数据传输。hdfs更加智能的放置复本,取得弹性平衡。
namenode使用网络位置来确定在哪里放置块的复本;
MR程序的调度器根据网络位置查找最近的复本作为map任务的输入。
机器地址:/switch/rack1

关于namenode需要内存

保守估计1百万个数据块分配1000MB内存;1百万~1GB
Hadoop系统日志文件:HADOOP_LOG_DIR=/home/hadoop/** 在hadoop-env.sh中

关于dfs.name.dir

该属性项指定一些列目录来给namenode存储永久性的文件系统元数据(编辑日志edits.log和文件系统映像fsimage)
namenode发生故障,可以恢复这些元数据文件并且重构新的namenode(辅助namenode只是定期保存namenode的检查点,不维护namenode的最新备份)

关于dfs.data.dir

该属性指定datanode存储数据的目录,描述一系列目录,目的是使datanode循环地在各个目录中写数据

关于fs.checkpoint.dir

该属性指定一系列目录来保存检查点,与namenode类似,检查点映像文件会存储在各个目录之中,以支持冗余备份。

#

默认情况下,hdfs的存储目录放在Hadoop的临时目录之中(hadoop.tmp.dir属性)。
以上几个属性配置的文件夹路径都是该临时目录下。

YARN补充

yarn启动后,会在slaves文件列举的每台机器上各启动一个节点管理器。

第十章 管理Hadoop

永久性数据结构

namenode的目录结构

dfs.name.dir.current{
VERSION
edits
fsimage
fstime}
①VERSION:包含正在运行的hdfs的版本信息
layoutVersion:描述hdfs持久性数据结构的布局版本,布局变更版本号就会递减
namespaceID:文件系统的唯一标识符,首次格式化hdfs时设置的。namenode使用该属性鉴别是否新建的datanode。
cTime:标记了namenode存储系统的创建时间。刚刚格式化的存储系统属性值为0;hdfs升级之后,该值会更新到新的时间戳
storageType:说明该存储目录包含的是namenode的数据结构

fsimage和edits

hdfs客户端执行写操作时,这些操作首先记录到编辑日志中。编辑日志修改时,namenode在内存中维护的元数据信息也同步更新。
fsimage文件是文件系统元数据的一个永久性检查点

checkpoint过程

①secondary Namenode请求主namenode停止使用edits文件,暂时将新的写操作记录到一个新文件中
②secondary Namenode从主namenode获取fsimage和edits文件 (http 的 get 请求)
③secondary Namenode将fsimage载入内存,逐一执行edits文件中的操作,创建新的fsimage文件
④secondary Namenode将新的fsimage文件发送会主namenode (http 的 post 请求)
⑤主namenode用从secondary Namenode接收的fsimage文件替换旧的fsimage文件,用①产生的edits文件替换旧的edits文件,同时更新fsimage文件来记录检查点执行的时间。
最终,主namenode拥有最新的fsimage和一个更小的edits文件

datanode的目录结构

datanode存储目录自动创建,不需额外格式化
version,namespaceID,cTime,layoutVersion同namenode的值
datanode的current目录中的其他文件都blk_前缀,两种文件类型:①hdfs块文件;②块的元数据文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值