NightPxy 个人技术博客

Hadoop 优化

Posted on By NightPxy

硬件环境

尽可能提高集群的内部的网络传输带宽

关键节点提升硬件

NameNode,硬件方面应该尽可能的给予最大的内存空间

HDFS

文件存储格式

大数据领域中,数据分析是最大的应用方向
对于大数据量的数据分析领域,最好的存储格式应该是列式存储.这方面比较代表性的就是ORC和Parquet.
列式存储的优势见前篇

小文件问题

危害

大量小文件是非常伤害Hadoop集群的,这种伤害主要体现在两点

  • 耗费宝贵的NameNode内存空间
    HDFS的文件元数据是存储在NameNode空间中的,所以HDFS有个隐含上限是:集群文件的最终数量是受制于NameNode的内存的,并且这种受制还是非集群能解决的,也就是目前只能做到NameNode的切换,而不能做串联,所以对于NameNode的内存是非常宝贵的
    而每一个小文件,都会完全与一个几十G以上的大文件地位相等,独立占用一个完整格式的文件命名空间(一个大约是150byte),这样大量小文件如果耗尽了NameNode内存,会导致整个HDFS的瘫痪,并且难以在短时间内恢复解决

  • 耗费过多的MapTask
    启动一个MapTask的基本标准是一个Block,而一个1byte的小文件也会独立占用一个Block.
    这样每读取一个小文件,也会启动一个MapTask.大量的启动MapTask,也会损失机器计算的性能,对ResourceManager来说,就是大量的资源申请和资源分配,对NodeManager来说,就是大量的内存和计算核被占用

解决

  • 首先应该在应用层就规避小文件的产生
    比如Flume,就要合理调整文件滚动参数,尽可能避免滚动出小文件
  • 归档合并
    如果小文件的产生不能控制也不可避免,可以考虑将多个小文件合并为一个归档文件 这样做的缺点是,读取小文件的时候,必须清楚归档文件与小文件的映射关系

归档合并的方式

har命令 Hadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问

hadoop archive -archiveName NAME -p <parent path> <src>* <dest>
hadoop archive -archiveName NAME -p <parent path> <src>* <dest>

# 单个Src文件夹
hadoop archive -archiveName 419.har -p /fc/src/20120116/ 419 /user/heipark

# 多个src文件夹
hadoop archive -archiveName combine.har -p /fc/src/20120116/ 419 512 334 /user/heipark

# har命令查看
hadoop fs -ls har:////user/heipark/20120108_15.har/
# hdfs命令查看
hadoop fs -ls /user/yue.zhang/20120108_15.har/ 

使用HAR,需要注意的是

  • 原来的小文件不会自行删除,需要手动删除
  • 创建一个HAR文件本质上是一个MapReduce,所以前提必须是集群可用
    缺陷
  • HAR不允许修改,要增加或者移除里面文件必须重新归档
  • 归档文件不允许压缩

Sequence file
Sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件

优缺点:对小文件的存取都比较自由,也不限制用户和文件的多少,但是该方法不能使用append方法,所以适合一次性写入大量小文件的场景

  • CombineFileInputFormat

合理压缩

从HDFS的角度说,当然是压缩比越高越好,但在实际过程中,必须同时考虑CPU能力的耗费,文件大小等等具体使用场景衡量
常用的压缩方式,snappy,LZO,LZ4,GZip,BZip2

一个简单的规则

  • 确定不超过一个块的小文件,可以考虑使用是不分割的快速压缩方式.例如Snappy,LZ4等
  • 大文件,如果涉及MapReduce计算读取,应考虑使用LZO压缩并同时为其建立分割索引
  • 如果是纯粹保存基本不会再使用的冷数据,如果可以接收超长的压缩时间和高耗的CPU能力,可以考虑Biz2压缩

压缩的方式的使用,最好是保证每个节点的压缩方式的Native形式OK

配置优化

dfs.blocksize

HDFS块大小,默认128M.
这个参数会影响到MapTask数量
块小就多,启动的MapTask也会多,耗费计算资源更多但并行度也会提高
块大就少,MapTask也会少,相应时间会延长但耗费资源会更少

dfs.namenode.handler.count
namenode server threads 的数量,默认10. 这些线程会使用RPC与其它DataNode沟通.当集群DataNode很多时,可能会发生RPC TimeOut.此时可以适当提高处理线程数,但主要提高的同时代表NameNode消耗的内存也会提高

计算向的优化

计算向的两个核心是 内存量和计算核
并且其中尤以内存量更加重要. 计算的不足,任务上是慢,内存的不足,任务会挂掉
太大又会浪费集群资源,

预估任务执行使用量

公式计算

合理使用Combine

聚合计算时,Combine,可以在Map-Shuffle时提前聚合,可能会非常大的减少shuffle结果到Reduce的网络传输

JVM优化

每个Container都会执行一个JVM以真正执行任务,可以将JVM堆大小(java.opts中的-Xmx)设置为低于容器(memory.mb)的值,以便让其位于Container的内存边界中,java.opts一般设置为memory.mb的75%左右

MapTask

允许的情况下,可以适当的调高MapTask的内存量,这样可以减少溢写次数

JVM重用

当有大量短任务时,可以考虑使用JVM重用

合理使用分布式缓存

大量连续任务中,如果需要传递一些小的中间数据,可以考虑使用分布式缓存来代替写出到HDFS

参考博客 https://yq.aliyun.com/articles/549597 https://blog.csdn.net/wisgood/article/details/17081367