hadoop要点

来源:互联网 发布:美团程序员工资待遇 编辑:程序博客网 时间:2024/05/29 08:05
(1)hadoop小文件影响效率原因:
小文件是指文件size小于HDFS上block大小的文件。这样的文件会给hadoop的扩展性和性能带来严重问题。首先,在HDFS中,任何block,
文件或者目录在内存中均以对象的形式存储,每个对象约占150byte,如果有1000 0000个小文件,每个文件占用一个block,则namenode
大约需要2G空间。如果存储1亿个文件,则namenode需要20G空间(见参考资料[1][4][5])。这样namenode内存容量严重制约了集群的扩展。 
其次,访问大量小文件速度远远小于访问几个大文件。HDFS最初是为流式访问大文件开发的,如果访问大量小文件,需要不断的从一个
datanode跳到另一个datanode,严重影响性能。最后,处理大量小文件速度远远小于处理同等大小的大文件的速度。每一个小文件要占用一个slot,
而task启动将耗费大量时间甚至大部分时间都耗费在启动task和释放task上。
(2)secondary namenode最重要的任务不是为了nn元数据热备份,而是定期合并fsimage(HDFS元数据镜像文件)和edit日志(HDFS改动日志),
并传输给nn
(3)set dfs.block.size
set hive.default.fileformat;
(4)对表数据文件存储格式为textfile和rcfile的解析过程
textfile:执行select col1 from tablename,会读取整张表的数据进行查询计算;
rcfile(Record Columnar File,列式记录文件)处理步骤:
优点:一个集行存储和列存储的优点于一身,压缩比更高,读取列更快。
(1)水平划分(按行划分),经过水平划分之后的各个数据块称之为Row Split或Record。
(2)垂直划分(按列划分),每一个Row Split或Record再按照“列”进行垂直划分。
(3)列式存储:Record存储数据时,首先存储该Record内第一列的全部数据、然后存储该Record内第二列的全部数据、…、依次将各列数据存储完毕,然后继续下一个Record的存储。
Record实际由Key、Value两部分组成,其中Key保存着Record的元数据,如列数、每列数据的长度、每列数据中各个列值的长度等;Value保存着Record各列的数据。实际上Record Key相当于Record的索引,利用它可以轻松的实现Record内部读取/过滤某些列的操作。
而且RCFile将“行式”存储变为“列式”存储,相似的数据以更高的可能性被聚集在一起,压缩效果更好。

RCFile是一种“允许按行查询,提供了列存储的压缩效率”的混合列存储格式。它的核心思想是首先把Hive表水平切分成多个行组(row groups),然后组内按照列垂直切分,这样列与列的数据在磁盘上就是连续的存储块了。
当一个行组内的所有列写到磁盘时,RCFile就会以列为单位对数据使用类似zlib/lzo的算法进行压缩。当读取列数据的时候使用惰性解压策略( lazy decompression),也就是说用户的某个查询如果只是涉及到一个表中的部分列的时候,RCFile会跳过不需要的列的解压缩和反序列化的过程。

(5)yarn内存资源隔离实现原理(基于线程监控的内存隔离方案)
yarn支持的两种类型的资源隔离:cpu和内存
解释:
资源隔离:Hadoop Yarn的资源隔离是指为运行着不同任务的“Container”提供可独立使用的计算资源,以避免它们之间相互干扰。
1.CPU:对于CPU,它是一种“弹性”资源,使用量大小不会直接影响到应用程序的存亡,因此CPU的资源隔离方案采用了Linux Kernel提供的轻量级资源隔离技术Cgroup;Cgroup会严格限制应用程序的资源使用上限,一旦使用量超过预先定义的上限值,会被杀死。
2.内存:
(6)inputFormat
InputFormat为我们提供两个很重要的功能:
 (1)如何将数据源中的数据(不一定是文件)形成切片(InputSplit,可能有多个),数据只有被合理切分,我们才可以分布式处理;
(2)如何读取并解析切片中的数据(RecordReader),数据源中的数据形式各异,只有转换为通用的Key-Value Pair,我们才可以利用MapReduce框架完成计算过程。
InputSplit中保存着两个信息:
(1)数据大小:InputSplit所关联数据的大小,MapReduce根据此值对所有InputSplit进行排序,使“大”的InputSplit得以优先运行,进而缩短整个Job的运行时间;
(2)数据存储位置:MapReduce根据此值完成Map Task的调度,即对于某个InputSplit来说,选取哪个计算节点运行Map Task完成这个InputSplit的数据处理,旨在拉近计算与数据之间的“距离”,移动计算而非移动数据,减少集群网络带宽资源。
RecordReader:
Map Task实际处理的是InputSplit的一条条“记录”(Record),我们需要一种方式能够将InputSplit关联的数据转换为一条条的“记录”,即Key-Value Pairs。对于文本文件的一条Record而言,key为数据在文本文件的起始偏移量,value为对应的一行字符串数据。

(7)FileInputFormat(org.apache.hadoop.mapreduce.lib.input.FileInputFormat)是专门针对文件类型的数据源而设计的,也是一个抽象类,是inputFormat的其中一个类型,它提供两方面的作用:
(1)定义Job输入文件的静态方法;
(2)为输入文件形成切片的通用实现;

(8)CombineFileInputFormat:是FileInputFormat其中一个类型,FileInputFormat还包括TextInputFormat,KeyValueTextInputFormat,SequenceFileInputFormat等类型。
设计目的就是用来应对小文件的场景,FileInputFormat为每一个小文件生成一个切片,而CombineFileInputFormat会将许多小文件“打包”为一个切片,使得每一个Map Task可以处理更多的数据。
更为关键的是CombineFileInputFormat在决定将哪些小文件的数据块“打包”为一个切片时会充分考虑数据本地性(节点本地性、机器本地性)的特性,因此不会在运行时间和网络带宽方面来很大的开销。

(9)datanode节点挂载磁盘:
查看属性<name>dfs.datanode.data.dir</name>可知hdfs文件存储磁盘位置;

第一步:制定分盘,设置hdfs-site.xml文件中的dfs.datanode.data.dir属性:
<property>
<name>dfs.datanode.data.dir</name>
   <value>
     /data/data01,/data/data02,/data/data03,/data/data04,/data/data05,/data/data06,/data/data07,/data/data08,/data/data09,/data/data10,/data/data11,/data/data12
   </value>
</property>
第二步:把/data/data01-12目录分别挂载到不同的磁盘分区,hdfs在写数据的时候就会选择datanode之后在这12个目录轮询。
/dev/sda              3.6T  3.3T  200G  95% /data/data01
/dev/sdb              3.6T  3.3T  201G  95% /data/data02
/dev/sdc              3.6T  3.3T  202G  95% /data/data03
/dev/sdd              3.6T  3.2T  206G  95% /data/data04
/dev/sde              3.6T  3.3T  201G  95% /data/data05
/dev/sdf              3.6T  3.3T  204G  95% /data/data06
/dev/sdg              3.6T  3.3T  205G  95% /data/data07
/dev/sdh              3.6T  3.3T  201G  95% /data/data08
/dev/sdi              3.6T  3.3T  202G  95% /data/data09
/dev/sdj              3.6T  3.2T  206G  95% /data/data10
/dev/sdk              3.6T  3.3T  203G  95% /data/data11
/dev/sdl              3.6T  3.2T  207G  95% /data/data12

(10)Hadoop默认数据块复本存储策略(写):对数据文件按照估计大小进行分块,然后按块存放副本到不同的节点上面。
    数据块复本存储策略的设计需要综合考虑可靠性、写带宽、读带宽三者之间的相互影响。跨机架的服务器之间的通信需要通过交换机,跨数据中心的服务器之间的通信需要通过专线连接,对于公司而言,交换机和专线的带宽资源都是有限的,
跨机架或数据中心的服务器之间大量的数据传输通常都会带来比较高昂的带宽成本。Hadoop默认数据块复本存储策略是以“一个数据中心、多个机架”为基础设计的:
(1)从HDFS Cluster中随机选取一个Datanode(Rack r1/Datanode d12)用于存储第一个复本Replica1;(优先选择本地节点,若客户端所在的服务器为dn节点)
(2)从其它机架(非Rack r1)中选取一个Datanode(Rack r2/Datanode d21)用于存储第二个复本Replica2;
(3)从机架Rack r2中随机选取一个Datanode(Rack r2/Datanode d22)用于存储第三个复本Replica3;
(4)如果复制因子大于3,则继续从HDFS Cluster中随机选取Datanode用于存储第n(n >= 4)个复本Replica;
 说明:
(1)选取的Datanode需要满足:磁盘空间使用不是很多,系统负载不是很高(Datanode不是很繁忙);
(2)同一个机架中不要存储同一个数据块太多的复本; 


解析:
1.选择一个本地节点
    这里所说的本地节点是相对于客户端来说的,也就是说某一个用户正在用一个客户端来向HDFS中写数据,如果该客户端上有数据节点,那么就应该最优先考虑把正在写入的数据的一个副本保存在这个客户端的数据节点上,它即被看做是本地节点,
但是如果这个客户端上的数据节点空间不足或者是当前负载过重,则应该从该数据节点所在的机架中选择一个合适的数据节点作为此时这个数据块的本地节点。另外,如果客户端上没有一个数据节点的话,则从整个集群中随机选择一个合适的数据节点作为此时
这个数据块的本地节点。那么,如何判定一个数据节点合不合适呢,它是通过isGoodTarget方法来确定的。
2.优化数据传输的路径
   以前说过,HDFS对于Block的副本copy采用的是流水线作业的方式:client把数据Block只传给一个DataNode,这个DataNode收到Block之后,传给下一个DataNode,依次类推,...,最后一个DataNode就不需要下传数据Block了。
所以,在为一个数据块确定了所有的副本存放的位置之后,就需要确定这种数据节点之间流水复制的顺序,这种顺序应该使得数据传输时花费的网络延时最小。


(11)HDFS读取副本的选择策略:由namenode决定
    当客户端读到一个文件的某个数据块时,它就需要向NameNode节点询问这个数据块存储在那些DataNode节点上。
    客户端至少需要向NameNode传输三个参数:文件路径、读取文件的起始位置、读取文件的长度,而NameNode会向该客户端返回它所要读取文件内容所在的位置——LocatedBlock对象,该对象包含对应的数据块所有副本所在的DataNode节点的位置信息,客户端接着就会依次从这些DataNode节点上读取该数据块,
直到成功读取为止。这里就设计到了一个优化问题了:客户端应该总是选择从距离它最近的可用DataNode节点上读取需要的数据块,所以此时的关键就是如何来计算客户端与DataNode节点之间的距离。这个计算距离的问题本质上涉及到我前面介绍过的一种数据结构
——NetworkTopology,这种数据结构被NameNode节点用来形象的表示HDFS集群中所有DataNode节点的物理位置,自然这个优化工作就交由NameNode来处理了。
    NameNode对文件的读优化的实现很简单,基本原理就是按照客户端与DataNode节点之间的距离进行排序,距客户端越近的DataNode节点越被放在LocatedBlock的前面,该算法的基本思路如下:
    1.如果该Block的一个副本存在于客户端,则客户端优先从本地读取该数据块;
    2.如果该Block的一个副本与客户端在同一个机架上,且没有一个副本存放在客户端,则客户端优先读取这个同机架上的副本;否则客户端优先读取同机器的副本,失败的情况下然后再优先考虑这个同机架上的副本;
    3.如果该Block既没有一个副本存在客户端,又没有一个副本与客户端在同一个机架上,则随机选择一个DataNode节点作为优先节点。

这种策略的缺陷:完全没有考虑到DataNode上的负载情况,从而致使HDFS的读性能急速下降。

(12)distcp任务

    distcp是个MapReduce任务,但只有map没有reducer。

  distcp把一大堆文件平均分摊开交给map去执行每个文件单独一个map任务。那么默认会分成几个map合适呢?首先按256mb平均分,如果总大小低于256mb,distcp只会分配一个map。但如果平分得结果出现节点得map数大于20的情况,每个节点的map数就会按20算,看下流程图:



(13)启用备份secondaryNamenode时候后对外的工作:
1.把命名空间的镜像加载到内存中
2.重新运行编辑日志
3.接受各个datanode节点的block报告
在一个大型一点的hdfs系统中,等这些做完需要30分钟左右。
2.x已经支持了高可用性(HA),通过一对namenode热备来实现,一台挂掉,备机马上提供无中断服务
要实现HA,要做三点微调:
1.namenode节点必须使用高可用的共享存储。
2.datanode节点必须象两个namenode节点发送block报告
3.客户端做改动可以在故障时切换到可用的namenode节点上,而且要对用户是无感知的
(14)hdfs数据完整性
dn除了读写操作会检查校验和以外,datanode还跑着一个后台进程(DataBlockScanner)来定期校验存在在它上面的block,因为除了读写过程中会产生数据错误以外,硬件本身也会产生数据错误,比如说位衰减(bit rot)。
如果客户端发现有block坏掉呢,会怎么恢复这个坏的块,主要分几步:
  1.客户端在抛出ChecksumException之前会把坏的block和block所在的datanode报告给namenode
  2.namenode把这个block标记为已损坏,这样namenode就不会把客户端指向这个block,也不会复制这个block到其他的datanode。
  3.namenode会把一个好的block复制到另外一个datanode
  4.namenode把坏的block删除掉
如果出于一些原因在操作的时候不想让hdfs检查校验码,在调用FileSystem的open方法前调用setVerityCheckSum方法,并设为为false即可,命令行下可以使用-ignoreCrc参数。
(15)hadoop权限访问控制
hadoop访问控制分为两级,其中ServiceLevel Authorization为系统级,用于控制是否可以访问指定的服务,例如用户/组是否可以向集群提交Job,它是最基础的访问控制,优先于文件权限和mapred队列权限验证。
Access Control on Job Queues在job调度策略层(mapred scheduler)之上,控制mapred队列的权限。
DFSPermmision用户控制文件权限。
目前版本中,连接到hadoop集群的用户/组信息取决于客户端环境,即客户端主机中`whoami`和`bash –c groups`取到的用户名和组名,没有uid和gid,用户属组列表中只要有一个与集群配置的用户组相同即拥有该组权限。

ServiceLevel Authorization配置在core-site.xml:
<property>  
 <name>hadoop.security.authorization</name>  
  <value>true</value>  
</property>  
Service LevelAuthorization有9个可配置的属性,每个属性可指定拥有相应访问权限的用户或者用户组。这9个ACL属性如下(hadoop-policy.xml):
<property>  
  <name>security.job.submission.protocol.acl</name>  
  <value>alice,bobgroup1,group2</value>  
</property>
1.security.client.protocol.acl  用于控制访问HDFS的权限
2.security.client.datanode.protocol.acl  用于block恢复
3.security.datanode.protocol.acl  用于控制datanode到namenode的通信权限
4.security.inter.datanode.protocol.acl 用于控制datanode之间更新timestamp
5.security.namenode.protocol.acl 用于second namenode和namenode之间的通信
6.security.inter.tracker.protocol.acl 用于tasktracker与jobtracker之间通信
7.security.job.submission.protocol.acl 用于控制提交作业,查询作业状态等权限
。。。
默认情况下,这9个属性不对任何用户和分组开放。
该配置文件可使用以下命令动态加载:
(1)更新namenode相关属性:bin/hadoop dfsadmin –refreshServiceAcl
(2)更新jobtracker相关属性:bin/hadoopmradmin –refreshServiceAcl
(16)报错:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space(oom)
原因:内存溢出
解决方法:
(1)增量并行的map数,-m 5 -spilt-by 字段
(2)调大jvm参数
mapreduce.map.java.opts='-Xmx4096m -XX:+UseG1GC...'  
mapreduce.reduce.java.opts='-Xmx4096m -XX:+UseG1GC...'
(3)若是由sqoop命令导致的oom,则通过设置参数-fetch-size减少一次加载数据量
(17)报错:17/08/30 18:16:24 ERROR sqoop.Sqoop: Got exception running Sqoop: java.lang.ArrayIndexOutOfBoundsException: 0
java.lang.ArrayIndexOutOfBoundsException: 0
数组越界,一般从参数值考虑,可能某个参数的值为空,导致数组第一个元素为空,移位!
(18)mr过程
map过程---combine过程---partition过程---reduce过程
map: (K1, V1) → list(K2, V2) 
combine: (K2, list(V2)) → list(K2, V2) 
reduce: (K2, list(V2)) → list(K3, V3)

原创粉丝点击