最近读完了《Hadoop.The.Definitive.Guide.4th.Edition.2015.3》英文第4版,个人感觉这本书是hadoop目前最权威、最全面、最靠谱的书籍,强烈建议大家好好研读。不建议大家去读hadoop权威指南第1版、第2版和第3版,第3版我也看完了,但是里面的知识已经与当前Apache hadoop 2.X严重脱节,比如第3版还在大篇幅的讲解hadoop1.X的jobtracker和tasktracker,这早就被抛弃。
《Hadoop.The.Definitive.Guide.4th.Edition.2015.3》全书从五个部分向读者诠释了hadoop相关知识,第一部分讲解了hadoop的基础知识(mapreduce、HDFS、YARN),第二部分详细讲解了mapreduce,第三部分讲解了hadoop集群的搭建管理和监控,第四部分讲解了hadoop生态圈一系列相关的子项目(Avro Parquet Flume Sqoop Pig Hive Crunch Spark Hbase Zookeeper),第五部分讲解了实战案例。给我感触最深的是第一部分中的YARN,从这里我学习到了FIFO CAPACITY FAIR3种调度器的详细知识,第二部分的mapreduce使我在对mapreduce进行优化时候有了明确的思路不至于那么迷茫,第三部分使我学会了如何站在公司的角度去思考搭建公司级hadoop要考虑的硬件和软件要求,hadoop管理和监控要求,总之,这本书值得购买,值得花时间去读,值得推荐给想了解hadoop又不知选啥资料的国人。
国人也在出hadoop相关书籍,和《Hadoop.The.Definitive.Guide.4th.Edition.2015.3》比起来,大部分可以说是一本文字垃圾,要么片面,要么不够深入,比如一本书就只讲一点YARN解析,另一本书讲mapreduce解析,不免让人觉得这在浪费广大读者的money,读者被动的接受着作者在金钱利益驱动下写下的垃圾,强烈建议这些作者好好学习下《Hadoop.The.Definitive.Guide.4th.Edition.2015.3》,建议出书的作者知识积累丰富点,所讲解的内容尽量囊括在一本书中(不要分成那么多子系列),建议作者要有持续更新版本的忍耐力,建议出书的作者资质再老点,不要是个人弄了几下hadoop就出书,国人很多技术书甚至作者的年龄都在20-35岁,不免让人觉得这些书籍是否可靠,也很少看到这些数据在随着时间的推移过程中持续更新,出第1版,第2版,第3版......可以说很多作者的书籍在第一版本发布后,就永远没了下文,随着时间推移,只会被淘汰。
看了很多hadoop相关的书籍,收获最大的就是《Hadoop.The.Definitive.Guide.4th.Edition.2015.3》,有感而发,在使用hadoop这条路上走过很多弯路,踩过很多坑,对于参考资料,只希望少一点垃圾,多一点经典。
答:读取HDFS的block需要做两件事,一是找到block在哪里,也就是寻址,这里消耗的时间为寻址时间,比如需要10毫秒;二是将这个block对应的数据传输到客户端,这里消耗的时间为磁盘传输时间,比如磁盘数据传输速度为128MB/秒,那么128MB数据需要1秒,也即1000毫秒。现在来做个试验,如下表:
文件大小 | blocksize | 寻址时间(10ms/block) | 传输时间(128MB/s) | 总计耗时 |
128MB | 128MB | 10ms/block*1block | (128MB*1block/(128MB/s))*1block | 1010毫秒 |
128MB | 1.28MB | 10ms/block*100block | (1.28MB*1block/(128MB/s))*100block | 2000毫秒 |
上面试验表明:在blocksize比较小的时候,频繁的在进行block的寻址操作,寻址操作越多,所消耗的时间就越多,最终总计耗时越大。试验充分说明了一个问题,要调大blocksize,设置多大好呢?hadoop目前推荐的设置是,寻址时间/传输时间=1%,所以官网上推荐的默认值为128MB,第一个问题回答完毕。
随着磁盘硬件性能的提升,你可以更改这个blocksize,让它大于128MB,比如256MB,不过不建议?这里说下我的理由,目前hadoop中很多地方都是据blocksize=128MB值之上对其他参数进行了默认设置,比如mapreduce.task.io.sort.mb=100MB,splitsize=128MB,hbase中memstore=128MB,这些与blocksize=128MB是有关的,当你变动了blocksize,这些参数你也要相应调整,除非你是hadoop高级掌握者,否则不要轻易的去改动。
答:namenode维护两类数据:(1)namespace image(2)edit log
来看下hdfs-site.xml中配置的dfs.namenode.name.dir目录的文件结构:
${dfs.namenode.name.dir}/ ├── current │ ├── VERSION │ ├── edits_0000000000033667872-0000000000033668028 │ ├── ... │ ├── edits_0000000000034678717-0000000000034678900 │ ├── edits_0000000000034678901-0000000000034679140 │ ├── edits_0000000000034679141-0000000000034679336 │ ├── edits_inprogress_0000000000034679337 │ ├── fsimage_0000000000034668015 │ ├── fsimage_0000000000034668015.md5 │ ├── fsimage_0000000000034675376 │ ├── fsimage_0000000000034675376.md5 │ └── seen_txid └── in_use.lock
开始第二个问题,namenode维护的逻辑文件系统及其block分布信息不是固定不变的,信息是在变化的,也不会写死,里面的block分布信息在各个datanode启动时候会主动向namenode上报,随着datanode的关闭也会动态更新。
配置项 | 使用者 | 单节点是否设置多个目录 | 作用 |
dfs.namenode.name.dir | namenode | 可以多个 | 每个目录是一份独立完整数据, 多个目录就是多份完整独立数据COPY |
dfs.datanode.data.dir | datanode | 可以多个 | 每个目录中只会存储所有文件数据中的某一部分,所有节点所有目录中才构成一份完成数据的默认3份COPY |
dfs.namenode.checkpoint.dir | secondary namenode | 可以多个 | 每个目录是一份独立完整数据, 多个目录就是多份完整独立数据COPY |
dfs.journalnode.edits.dir | journalnode | 只能一个 | 存储的是此journalnode的状态和一部分edit log信息,这份edit log 在大多数其他journalnode上也有备份 |
答:HDFS中namenode+secondarynamenode的冷切换加载过程:
HDFS中HA(Active namenode+Standby namenode)热切换过程:
HDFS中HA(Active namenode+Standby namenode)冷切换过程(效果比namenode+sencondarynamenode冷切换要好,因为journalnode上edit log不需加载):
答:
HDFS HA方式 | 启动 | 配置 | edit log |
QJM | 无差别 | 用journalnode存储edit log | 只有一个namenode可写edit log,容易控制 |
NFS | 无差别 | 用NFS共享edit log | 比较难控制只有一个namenode写edit log |
答:HDFS HA方式下,服务端配置的hadoop集群名字是个虚拟名称,目前客户端需要配置上这个虚拟名称以及这个名称后面对应的多个namenode节点,从而客户端自己通过检测来实现连接处于active状态的namenode,一定要配置给客户端的必要参数如下:
dfs.nameservices=mycluster dfs.client.failover.proxy.provider.mycluster=org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider dfs.ha.namenodes.mycluster=nn1,nn2 dfs.namenode.rpc-address.mycluster.nn1=192.168.77.38:9000 dfs.namenode.rpc-address.mycluster.nn2=192.168.77.39:9000
答:网络距离依次递增,规则如下:
答:(1)读数据剖析:
(2)写数据剖析
答:distcp本质是个mapreduce,使用时候最好指定map和reduce个数,这样效率才会高。
答:
文件系统 | URI前缀 | hadoop的具体实现类 |
Local | file:// | fs.LocalFileSystem |
HDFS | hdfs:// | hdfs.DistributedFileSystem |
WebHDFS | webhdfs:// | hdfs.web.WebHdfsFileSystem |
Secure WebHDFS | swebhdfs:// | hdfs.web.SWebHdfsFileSystem |
HAR | har:// | fs.HarFileSystem |
View | viewfs:// | viewfs.ViewFileSystem |
FTP | ftp:// | fs.ftp.FTPFileSystem |
S3 | s3a:// | fs.s3a.S3AFileSystem |
Azure | wasb:// | fs.azure.NativeAzureFileSystem |
Swift | swift:// | fs.swift.snative.SwiftNativeFileSystem |
hadoop是提供了对于以上各种文件系统的默认实现,稍作配置即可使用上述文件系统,比如S3 Support in Apache Hadoop 基于Amazon S3的文件系统
HDFS只是hadoop实现的文件系统之一,默认dfs.webhdfs.enabled=true,是开启了WebHDFS,如果觉得不安全,可以设置dfs.webhdfs.enabled=false来禁止WebHDFS。
答:(1)hadoop的文件压缩好处:
(2)选择文件压缩格式考虑三个因素:
(3)支持的文件压缩格式有哪些:
默认Apache hadoop的安装文件提供了Bzip2、Gzip、DEFLATE的支持,只需配置mapreduce.map.output.compress和mapreduce.map.output.compress.codec即可使用,但是在Apache hadoop安装文件里并没有提供对于snappy和LZO的支持,这两个需要自己去安装整合,关于snappy和LZO的安装整合参见如下地址参见我的另外一篇博客hadoop 压缩 gzip biz2 lzo snappy
(4)不同后缀的文件HDFS是如何编解码读取的?
答:HDFS是通过文件后缀名来找编解码的,所以只要你的文件的后缀和相应的编码格式里的文件后缀匹配上了,那么HDFS就能知道用何种编解码,不过前提是对应的编码你首先都集成到hadoop中了,默认Apache hadoop能处理.deflate、.gz、.bz2后缀的文件,因为默认Apache hadoop就不支持LZO和SNAPPY,所以无法读取.snappy、.lzo和.lzo_deflate为后缀的文件,关于LZO和SNAPPY怎么集成到hadoop请参见我的另外一篇博客hadoop 压缩 gzip biz2 lzo snappy
(5)为什么Apache hadoop默认不支持LZO和SNAPPY?
答:Apache hadoop官网提供的hadoop版本本身就支持Bzip2、Gzip、DEFLATE3种压缩格式,不支持Snappy和LZO格式,原因是Snappy和LZO的代码库拥有GPL开源协议许可,而不是Apache开源协议许可,关于Snappy和LZO需要hadoop运维或者hadoop提供商自己集成。关于开源代码协议GPL、BSD、MIT、Mozilla、Apache和LGPL的区别详见下图:
(6)LZO对应的文件后缀就是.lzo吗?
答:hadoop是根据文件的后缀去寻找编解码用哪个,之前认为com.hadoop.compression.lzo.LzoCodec对应的后缀为".lzo"是错误的,查看了hadoop-lzo源代码发现".lzo"对应的编解码为com.hadoop.compression.lzo.LzopCodec,查看了源代码发现".lzo_deflate"对应的编解码为com.hadoop.compression.lzo.LzoCodec
答:hadoop支持的结构化文件类型有如下:
(1)ResourceManager进行资源分配时,采用了和HDFS相同的网络距离计算算法,尽量把block所在节点让NodeManager启动containner;
(2)执行的具体流程如下:
(3)判定client提交的application为小任务的依据:
答:
(1)Apache Slider 是一个 Yarn 应用,它可以用来在 Yarn 上部署并监控分布式应用。Slider 可以在应用运行期随意扩展或者收缩应用。目前它是 Apache 的孵化项目。参见董西城的Apache Slider—将已有服务或者应用运行在YARN上
(2)Apache Twill(官方首页:Apache Twill)这个项目则是为简化YARN上应用程序开发而成立的项目,该项目把与YARN相关的重复性的工作封装成库,使得用户可以专注于自己的应用程序逻辑。参见董西城的Apache Twill—YARN上应用程序开发包
答:
(1)hadoop version<=2.5.1,使用job historyserver,默认MapReduce Application Master将Job history存储在HDFS上,保留的期限是7天,存储的路径通过mapreduce.jobhistory.done-dir设置;
(2)hadoop version> 2.5.1,使用timelineserver,historyserver仍然保留。application history server支持MapReduce作业,引入timeline server之后,Application History Server变成了Timeline Server的一个应用,history服务基于timeline store建立,history可以存储在内存中或者采用leveldb数据库存储,采用leveldb数据库存储可以保证history在timeline server 重启后仍会保留。
答:
|
FIFO |
CAPACITY |
FAIR |
描述 | 每一个job占有所有资源,第二个job等第一个job执行完毕才开始执行 |
预先按照设定的queue资源比例为每个queue预留资源,一个job在queue对应的资源下执行,这个job所在queue不会占有所有资源,同一queue里面不同job仍然按照FIFO执行 |
各个queue按照预设的比重获得资源,当只有一个job时候,独占所有资源,不过也可以设置最大资源来限制独占所有资源,此时如果有第二个queue里启动了job,那么会通过延迟调度等待资源或者通过资源抢占来让第一个job腾出资源 |
特点 | 先进先出, 资源独占 |
不同组按比例分配资源, 不同组的比例之和为100%, 同组内按照FIFO处理, 只有一个组时也不会独占资源,存在资源浪费 |
不同组按照权重对应比例分配总资源, 只有一个组时可以独占资源, 多个组运行时,会腾出资源, 同组内可设置FAIR、FIFO、DRF |
Apache hadoop | 默认调度策略 | ||
Cloudera hadoop | 默认调度策略 | ||
指定queue | 通过mapreduce.job.queuename指定使用哪个queue | 默认通过规则来自己判定用哪个queue。 1)specified意思是按照mapreduce.job.queuename值判断用哪个queue 2)primaryGroup意思是按照client所在用户组去找queue 3)user意思是按照client所在用户去找queue |
|
配置文件 | capacity-scheludel.xml |
fair-scheduler.xml 可修改yarn.scheduler.fair.allocation.file修改配置文件名字 |
|
资源抢占 | FAIR支持资源抢占: 1)minum.share.preemption.timeout时间未获得最小资源要求,进行资源抢占; 通过defaultMinSharePreemptionTimeout设置所有queue超时; 通过minSharePreemptionTimeout设置单个queue超时 2)fair.share.preemption.timeout未获得资源要求的50%,进行资源抢占; 通过defaultFairSharePreemptionTimeout设置所有queue超时; 通过fairSharePreemptionTimeout设置单个queue超时; 通过defaultFairSharePreemptionThreshold设置所有queue最低资源要求比例(默认0.5); 通过fairSharePreemptionThreshold设置单个queue最低资源要求比例(默认0.5) |
||
延迟调度 | 可以设置延迟等待,以便等待最优的资源被分配来执行job(比如尽量离block最近)
yarn.scheduler.capacity.node-locality-delay设置一个正整数N,代表错过N次调度机会后放弃延迟等待 |
可以设置延迟等待,以便等待最优的资源被分配来执行job(比如尽量离block最近)
yarn.scheduler.fair.locality.threshold.node设置一个浮点数,代表等待直到这个比例的节点资源处于空闲就开始执行job
yarn.scheduler.fair.locality.threshold.rack设置正整数,代表当应用程序请求某个机架上资源时,它可以接受的可跳过的最大资源调度机会 |
|
DRF(Dominant Resource Fairness) | 同时考虑CPU和MEMORY两个资源,默认DRF为开启,默认只考虑MEMORE不考虑CPU
通过设置yarn.scheduler.capacity.resource-calculator=org.apache.hadoop.yarn.util.resource.DominantResourceCalculator来在容量调度开启DRF |
同时考虑CPU和MEMORY两个资源,默认DRF为开启,默认只考虑MEMORE不考虑CPU
通过设置fair-scheduler.xml中的defaultQueueSchedulingPolicy=drf来在公平调度里开启DRF |
答:(1)后加载的配置信息会覆盖之前加载的信息;
(2)加了Final的配置项不可被覆盖;
(3)配置文件中定义在前的属性可通过${属性name}在后面进行引用;
(4)可以使用System设置配置属性;
(5)可以使用JDK的-Dproterty=value设置配置属性。
答:(1)maven中添加hadoop-client依赖jar,该jar包含所有客户端与HDFS和MAPREDUCE相关的所有类;maven中添加hadoop-minicluster依赖jar,该jar支持在单个JVM中模拟hadoop集群进行测试
(2)ToolRunner是hadoop提供的工具类以减轻shell脚本的工作,它里面的使用的是工具类GernericOptionsParser作用是与hadoop命令行配置信息交互并将这行配置设置到Configuration对象上;
MRUnit可以用来在本地用断言的方式测试mapreduce程序,比如MRUnit.MapDriver可以构造map的输入信息。
4.0.0 com.hadoopbook hadoop-book-mr-dev 4.0 UTF-8 2.5.1 org.apache.hadoop hadoop-client ${hadoop.version} junit junit 4.11 test org.apache.mrunit mrunit 1.1.0 hadoop2 test org.apache.hadoop hadoop-minicluster ${hadoop.version} test hadoop-examples org.apache.maven.plugins maven-compiler-plugin 3.1 1.6 1.6 org.apache.maven.plugins maven-jar-plugin 2.5 ${basedir}
答:
(1)默认hadoop是没有开启提交mapreduce程序的用户身份认证,因为hadoop.security.authorization=false
(2)默认hadoop的client所在用户组和用户信息会被作为参数传入到服务端与HDFS文件权限进行匹配
(3)如果client所在用户组和用户于HDFS权限体系不同,可通过HADOOP_USER_NAME或者hadoop.user.group.static.mapping.overides设置
(4)WebHdfs交互的用户权限可通过hadoop.http.staticuser.user设置
答:
(1)默认通过环境变量HADOOP_HOME和HADOOP_CONF_DIR寻找配置文件,另外一种方法是可以通过-conf指定配置文件;
(2)开发者可以通过工具类GernericOptionsParser类加载Configuration配置文件后,将所有配置信息打印出来,这是方法一;第二种方法是去hadoop官网进行查询
(3)开发者可以设置HADOOP_USER_CLASSPATH_FIRST=true和mapreduce.job.user.classpath.first=true来让hadoop优先加载用户自己的jar。
答:
(1)首先,所有在YARN resource manager上运行的application的命名规则是:application_${时间戳}_${第几个application程序},比如application_1410450250506_0003代表是在时间戳1410450250506经YARN resource manager运行的第0003个application程序;
(2)Job的命名规则是继承了部分application的信息,规则是:job_${时间戳}_${第几个application程序},比如job_1410450250506_0003代表是在时间戳1410450250506经YARN resource manager运行的第0003个application程序的job;
(3)Task的命令规则有继承了Job的信息,规则是:task_${时间戳}_${第几个application程序}_${m代表map,r代表reduce}_${第几个map程序或者第几个reduce程序},比如task_1410450250506_0003_m_000003代表是在时间戳1410450250506经YARN resource manager运行的第0003个application程序job里对应的第000003个map程序,task_1410450250506_0003_r_000001代表是在时间戳1410450250506经YARN resource manager运行的第0003个application程序job里对应的第000001个reduce程序;
(4)AttemptTask是在Task失败后尝试执行的任务,它的命名规则:attempt_${时间戳}_${第几个application程序}_${m代表map,r代表reduce}_${第几个map程序或者第几个reduce程序}_${尝试次数},比如attempt_1410450250506_0003_m_000003_0代表是在时间戳1410450250506经YARN resource manager运行的第0003个application程序job里对应的第000003个map程序失败后又被执行了一次
日志类型 | 归属 | 描述 |
System daemon logs | Administrators | (1)后台进程namenode、datanode、journalnode、zkfc、nodemanager、resoucemanager等产生的日志默认存放在HADOOP_HOME/logs,可以设置HADOOP_LOG_DIR改变日志目录位置,如果目录不存在hadoop会主动创建但必须要给权限; (2).log结尾的日志按天存储,所有日志不会主动删除,会永久保留; (3).out结尾的日志默认保留最近的5个,会自动清理过期的日志 |
HDFS audit logs | Administrators | 记录所有的HDFS的请求的日志,写入后台进程namenode的.log日志文件,默认是关闭的可以配置开启 |
MapReduce job history logs | Users | MapReduce Application Master将Job history存储在HDFS上,保留的期限是7天,存储的路径通过mapreduce.jobhistory.done-dir设置 |
MapReduce task logs | Users | (1)记录每个Task相关程序产生的日志,日志有syslog stdout stderr3类 (2)存放的目录通过环境变量YARN_LOG_DIR设置,默认在linux机器的YARN_LOG_DIR/userlogs目录下面 |
答:
(1)Apache oozie
(2)Apache Azkaban
答:通常的优化检查列表如下:
优化项 | 优化建议 |
map个数 | (1)关注map个数以及每个map执行消耗的平均时间,使得每个map执行平均时间在一个合理范围(合理建议:map平均耗时在1分钟左右) (2)处理的数据文件的格式直接影响到map,不可分割的文件压缩格式比如SNAPPY使得大的数据文件无法被切分从而导致有些map消耗过多时间;合理的结构化文件比如Apache ORC可以提升hive的效率; (3)大量的小文件不仅增加寻址总耗时,也会加剧map任务量大小,建议是添加CombineFileInputFormat将小文件进行整合 |
reduce个数 | (1)确保reduce个数大于1(合理建议:reduce平均耗时5分钟左右,每个reduce写的数据大小刚好一个blocksize=128MB大小) (2)reduce个数不能多不能少,个数的依据是尽量使得每个reduce刚好写一个blocksize=128MB大小的文件。 |
Combiners | (1)确保数据从map出来到达reduce之间使用了combiners来较少这之间shuffle传递的数据 |
Intermediate Compression | (1)设置mapreduce中间值的压缩,减少了存储文件所需的空间,加速了网络、磁盘或磁盘的数据传输; (2)设置mapreduce.map.output.compress=true,默认mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.DefaoultCodec,可以设置其它压缩格式比如LZO LZ4 Snappy |
Custom serialization | (1)自定义序列必须保证实现了RawComparator |
Shuffle tweaks | (1)MapRduce的shuffle过程可以对一些内存管理的参数进行调整,以弥补性能的不足 (2)深入了解map端的shuffle过程,然后对其内存进行优化; (3)深入了解reduce端的shuffle过程,然后对其内存进行优化。 |
答:
(1)MapReduce job的参与实体有:
(2)MapReduce job运作流程:
1)MapReduce job提交:client调用Job.submit()方法会产生一个JobSubmitter对象,然后调用JobSubmitter.submitJobInternal()提交Job,最后通过Job.waitForCompletion()每秒中获取Job的运行状态同时通知console状态变化,否则通知console错误日志信息。详细过程如下:
2)MapReduce job初始化
3)TASK分配
4)TASK运行
5)进度和状态更新
答:
(1)MapReduce job失败相关处理:
(2)MapReduce application master的失败相关处理:
(3)YARN node manager的失败相关处理:
(4)YARN resource manager的失败相关处理:
答:MapReduce会确保从map task产生的结果传输到reduce task时候数据都已经进行了排序处理,从map task到reduce task中间对于数据的排序处理和传输处理就是MapReduce的shuffle;
map task和reduce task是的执行可能在不同的机器节点上YARN node manager写下的containner,所以要了解shuffle和sort的具体流程需要分别站在map task和reduce task的角度去看待;
(1)map task端的shuffle处理
1)每个map task持有一个环形的内存缓冲区buffer用于存储map task输出。缓冲区默认大小为100M(可以通过mapreduce.task.io.sort.mb设置)。一旦缓冲的内容达到阈值(mapre
duce.map.sort.spill.percent,默认0.80),会开启一个后台线程,将buffer内容spill(溢出)到本地linux磁盘。map task的输出继续写到缓冲区buffer,但如果在此期间缓冲区buffer被填满,map task会被阻塞直到写磁盘过程完成。溢出写过程按轮询方式将缓冲区内容写到mapreduce.cluster.local.dir属性指定的linux目录中
2)map task的buffer数据在写入linux磁盘前,那个开启的后台线程首先根据最终要输出的reducer将数据分区。在每个分区中,后台线程会在内存中按key执行排序,如果client设置了combiner,它就在排序后的输出上运行。运行combine函数会使map输出更加紧凑,减少写到磁盘的数据和传递给reducer的数据
3)map task的buffer每次达到阈值后,都会新建一个spill文件。因此在map写完其最后一个输出记录后,会有几个溢出文件。在task完成之前,spil文件被合并成一个已分区且已排序的输出文件。mapreduce.task.io.sort.factor属性控制着一次最多能合并多少流,默认值为10
4)如果至少存在3个spill文件(mapreduce.map.combine.minspills可以配置),这output写入到磁盘之前会再次运行combiner。反复调用combiner不会对最终结果产生影响。如果只有一个或者两个spill 文件,那么就不值得再对map输出调用combiner,所以不会再运行combiner。
5)建议将map输出结果压缩后再写到磁盘,这样写入磁盘会更快,节约磁盘空间,并且减少传给reducer的数据量。在默认情况下,输出是不压缩的,需要将mapreduce.map.output.compress设置未true。使用的压缩库由mapreduce.map.output.compress.codec属性指定
6)reduce task通过HTTP方式得到map task输出文件的分区,文件分区的工作线程的数量是由属性mapre
duce.shuffle.max.threads(默认值为0,此时默认是处理器数量的2倍,这个应该是继承自netty的reactor线程池设置)控制的,此设置是针对每一个YARN nodemanager,不是针对每个map task
(2)reduce task端的shuffle处理
1)map task的输出文件都存储在linux上mapreduce.cluster.local.dir目录中,一个reduce task需要的是来自多个map task输出文件中的特殊parttion数据。每个map task的完成时间可能不同,因此只要有一个map task完成,reduce task就开始复制map task输出,reduce task有少量的copier线程来并行的取得map task的输出,默认为5个线程,并且可以通过mapreduce.reduce.shuffle.parallelcopies属性设置
2)reduce task如何知道要从哪台机器取得map输出的呢? map task成功完成后,它会通过heartbeat机制通知MapReduce application master。因此,对于一个MapReduce job,MapReduce application master知道 map output和hosts之间的映射。reduce task会有一个线程轮询MapReduce application master获取map task输出的位置,直至获取所有输出的位置
3)如果map task的输出足够小,会被拷贝到reduce task的JVM内存中(mapreduce.reduce.shuffle.input.buffer.percent设置用于此用途的内存占有堆空间JVM的百分比,默认为0.70,意思是JVM*0.70),否则,将会被复制到磁盘。一旦达到缓冲区大小的阈值时(mapreduce.reduce.shuffle.merge.percent,默认值0.66,此时阈值为JVM*0.70*0.66)或者达到map task输出的阈值(mapreduce.reduce.merge.inmem.threshold,意思是拷贝来自map task的输出文件个数大于1000则合并写到磁盘),则合并后spill到磁盘。如果指定combiner,则在合并期间运行它,降低写入硬盘的数据量
4)当从map task复制而来的副本在reduce task的本地linux上累积时,一个后台线程被启动来合并这些文件,如果之前map task的输出被压缩过此时会被解压然后在内存中进行合并。
5)复制完所有的map task输出后,reduce task进入sort阶段(准确的说是merge阶段,sort是在map端发生的),这个阶段维持map输出的顺序,合并map task输出,最后直接将结果写入HDFS,HDFS的第一个block一般会优先写入nodemanager所在机器上的datanode。举个例子:如果有50个map outputs,merge factor是10(mapreduce.task.io.sort.factor可以设置大小),合并将进行5次,每10个文件合并成一个文件,最后有5个中间文件。 最后将这个5个文件合并未一个文件是调用的reduce函数。
(3)熟悉了MapReduce job的map task和reduce task各自的shuffle之后,如何优化MapReduce job?
1)优化建议如下:
2)从map task端优化MapReduce job
属性 | 类型 | 默认值 | 描述 |
mapreduce.task.io.sort.mb | int | 100 | 每个map task持有的一个环形内存缓冲区大小 |
mapreduce.map.sort.spill.percent | float | 0.80 | 当每个map task持有的一个环形内存缓冲区使用比例大于此值就spill写linux磁盘文件 |
mapreduce.task.io.sort.factor | int | 10 | 10个spill的linux本地文件会进行一次合并 |
mapreduce.map.combine.minspills | int | 3 | map task最后的输出文件个数必须小于此值,不然就触发合并 |
mapreduce.map.output.compress | boolean | false | map task的输出的压缩是否开启 |
mapreduce.map.output.compress.codec | Classname | org.apache.hadoop.io.compress.DefaultCodec | map task输出的压缩格式设置 |
mapreduce.shuffle.max.threads | int | 0 | 每一个nodemanager上开启多少个线程来将map task输出数据传输给reduce task,0表示处理器数量的2倍,此属性继承自netty设置 |
3)从reduce task端优化MapReduce job
属性 | 类型 | 默认值 | 描述 |
mapreduce.reduce.shuffle.parallelcopies | int | 5 | reduce task的COPY阶段,用来复制map task数据的线程数 |
mapreduce.reduce.shuffle.maxfetchfailures | int | 10 | reduce task尝试从map task获取数据失败后的最大尝试次数,尝试次数大于此值后直接跑错 |
mapreduce.task.io.sort.factor | int | 10 | 10个spill的linux本地文件会进行一次合并 |
mapreduce.reduce.shuffle.input.buffer.percent | float | 0.70 | 拷贝到reduce task的数据存储到内存缓冲区,该内存缓冲区大小为reduce task的JVM * 0.70 |
mapreduce.reduce.shuffle.merge.percent | float | 0.66 | 拷贝到reduce task的数据存储到内存缓冲区,该缓冲区数据达到一定比例就写文件到linux磁盘,该比例对应内存阈值为为reduce task的JVM * 0.70 *0.66 |
答:(1)MapReduce job的MapReduce tasks有快有慢,针对那些假死或挂起或者耗时的task,会启动一个和该TASK一样的另外一个推测任务MapReduce task并行执行,当推测TASK在原TASK执行完之前完成那么原TASK被中止,当推测TASK在原TASK执行完之后完成那么推测TASK被中止;推测TASK只会在MapReduce job的所有MapReduce tasks都启动后才会开始被启动,这种任务就是推测任务(speculative execution);
(2)推测任务的相关设置属性如下:
属性 | 类型 | 默认值 | 描述 |
mapreduce.map.speculative | boolean | true | 是否开启针对map task的推测任务 |
mapreduce.reduce.speculative | boolean | true | 是否开启针对reduce task的推测任务 |
yarn.app.mapreduce.am.job.speculator.class | Class | org.apache.hadoop.mapreduce.v2.app.speculate.DefaultSpeculator | 推测任务执行策略 |
yarn.app.mapreduce.am.job.task.estimator.class | Class | org.apache.hadoop.mapreduce.v2.app.speculate.LegacyTaskRuntimeEstimator | 推测任务使用的评估策略 |
(3)建议关闭推测任务(speculative execution),理由如下:
答:FileInputFormat默认自己有InputPathFilter,这个InputPathFilter会将所给输入数据目录下所有以(点号.和下划线_打头的隐藏文件进行排除,放置参与数据处理计算);
client通过setInputPathFilter()添加自己的InputPathFilter,这个InputPathFilter不会覆盖默认的InputPathFilter,只会基于其上做叠加;
默认hadoop MapReduce job的FileInputFormat不会级联读取所给目录下子目录中的数据文件,相反会把子目录当作数据文件进行读取,此时会直接向外抛出error;如果想让其级联读取目录下子目录的数据文件需要设置mapreduce.input.fileinputformat.input.dir.recursive=true
答:(1)计数器:计数器可以辅助MapReduce job的相关统计信息;计数器可以用来诊断MapReduce job出现的问题;计数器相对于通过日志去排查MapReduce job更容易。
计数器分类:
计数器类型 | 计数器实现类 |
MapReduce task counters | org.apache.hadoop.mapreduce.TaskCounter |
Filesystem counters | org.apache.hadoop.mapreduce.FileSystemCounter |
FileInputFormat counters | org.apache.hadoop.mapreduce.lib.input.FileInputFormatCounter |
FileOutputFormat counters | org.apache.hadoop.mapreduce.lib.output.FileOutputFormatCounter |
Job counters | org.apache.hadoop.mapreduce.JobCounter |
(2)排序sort
(3)链接join
(4)分布式缓存(类似于spark的广播变量)
答:
版本 | 安装包 | 优点 | 缺点 |
Apache hadoop | Tar | 扩展性好,更灵活,开源免费 | 工作量大, 没有完整的管理和监控功能 |
Apache Bigtop | RPM | Debian提供各种子项目的整合和测试, 比如整合hive |
扩展不灵活受制于人 |
Cloudera hadoop | Tar、RPM | 具备安装、管理和监控功能, 有开源版本和商用版本, 目前开源版本有使用限制 |
扩展不灵活受制于人, 需要root或者sudo权限, 一家独大时商业纠纷问题 |
Hortonworks hadoop | Tar、RPM | 具备安装、管理和监控功能, 有开源版本和商用版本, 目前开源版本有使用限制 |
扩展不灵活受制于人, 需要root或者sudo权限, 一家独大时商业纠纷问题 |
Ambari hadoop | Tar、RPM | 具备安装、管理和监控功能, 开源免费 |
扩展不灵活受制于人, 需要root或者sudo权限 |
答:(1)hadoop被设计用来在商业硬件上运行,企业可以选择普通硬件供应商生产的标准化的、广泛有效的硬件来搭建集群,这里的商业硬件注意两个原则:一是商业硬件不等同于低端硬件,低端硬件故障概率高;二是商业硬件也不推荐使用大型的数据库级别的机器,因为这类机器性价比太低。
对于商业硬件的配置推荐如下(基于2014年的硬件市场和配置推荐):
推荐的hadoop cluster网络拓扑结构如下:
(2)企业如何估算hadoop cluster硬件服务器需求量:
答:详见hadoop2.7.1安装准备 和 1.x和2.x都支持的集群安装
(1)安装JDK(详查官网每个版本对于JDK的要求)
(2)创建用于管理的linux用户(建议分别创建linux用户hdfs mapred yarn)
(3)安装hadoop(下载tar.gz文件直接解压,安装目录建议为/usr/local,其次可以安装在/opt)
(4)配置SSH(方便从一个节点SSH登录其他节点从而实现集群启动和停止)
(6)格式化HDFS文件系统
(7)启动和关闭hadoop(可以设置hadoop-env.sh中HADOOP_SLAVES来改变默认slaves文件位置)
(8)在HDFS上创建用户目录
#在HDFS上创建文件目录/user/username并授权给username:username hadoop fs -mkdir /user/username hadoop fs -chown username:username /user/username #设置HDFS文件目录/user/username的最大使用磁盘空间 hdfs dfsadmin -setSpaceQuota 1t /user/username
答:(1)hadoop的配置文件列表如下:
(2)在CDH和Ambari中,默认使用dsh和pdsh来管理进群配置;集群节点个性化或者差异化配置工具参考Chef, Puppet, CFEngine, and Bcfg2
(3)hadoop的环境变量初始化脚本主要为hadoop-env.sh和yarn-env.sh,一些特别的设置建议如下:
(4)后台进程相关重要设置
fs.defaultFS hdfs://namenode/
dfs.namenode.name.dir /disk1/hdfs/name,/remote/hdfs/name dfs.datanode.data.dir /disk1/hdfs/data,/disk2/hdfs/data dfs.namenode.checkpoint.dir /disk1/hdfs/namesecondary,/disk2/hdfs/namesecondary
yarn.resourcemanager.hostname resourcemanager yarn.nodemanager.local-dirs /disk1/nm-local-dir,/disk2/nm-local-dir yarn.nodemanager.aux-services mapreduce.shuffle yarn.nodemanager.resource.memory-mb 16384 yarn.nodemanager.resource.cpu-vcores 16
在mapreduce1中,map个数和reduce的个数是固定的,默认2个map2个reduce,所以计算tasktracker节点上内存为:1G(datanode内存)+1G(tasktracker内存)+2(map个数)*200MB(map task JVM)+2(reduce个数)*200MB(reduce task JVM)
在mapreduce2也即YARN中,map和reduce个数不再固定,只默认设置了map和reduce能申请的总的资源(8G内存,8CPU CORE),所以一般在nodemanager节点上,内存开销为:1G(datanode内存)+1G(nodemanager内存)+x(map个数)*1Gmap task JVM)+y(reduce个数)*1G(reduce task JVM),但总量x(map个数)*1Gmap task JVM)+y(reduce个数)*1G(reduce task JVM)不会超过默认的8G;YARN支持JVM虚拟内存设置,设置的虚拟内存不超过2.1倍JVM内存,默认yarn.nodemanager.vmem-pmem-ratio=2.1;YARN通过yarn.nodemanager.resource.cpuvcores、mapreduce.map.cpu.vcores、mapreduce.reduce.cpu.vcores来控制对于CPU的使用;可以设置yarn.nodemanager.containerexecutor.class和yarn.nodemanager.linux-container-executor来让YARN启用linux的cgroups资源隔离。
(5)其他设置
通过dfs.hosts、dfs.hosts.exclude、yarn.resourcemanager.nodes.include-path和yarn.resourcemanager.nodes.exclude-path来上线和下线节点
默认hadoop访问文件的IO缓存大小io.file.buffer.size=4K,这个建议增大到128K
blocksize=128MB,不建议修改,很多地方依赖次配置
设置dfs.datanode.du.reserved预留磁盘空间供非HDFS程序或进程使用
设置fs.trash.interval启用回收站以免HDFS文件误删除后可以恢复
YARN调度器在Apache hadoop中默认为容量调度,而在CDH默认为公平调度,对于Apache hadoop建议优化为公平调度
默认reduce task在5%的map task完成后即开始启动,对于数据量大的任务建议设置mapreduce.job.reduce.slowstart.completedmaps进行优化
建议如果client和数据block在同一节点,建议开启short-circuit,通过设置dfs.client.read.shortcircuit=true和dfs.domain.socket.path开启
答:2009年,雅虎把Kerberos组件运用到了Hadoop之中,在RPC连接等多个组件上进行认证。时至今日,Kerberos依然是hadoop使用比较广泛的安全机制之一。
hadoop中开启kerberos认证:
hadoop的委托令牌:
其它的安全加强机制:
答:啊红斗篷自带若干基准测试工具,这些工具放置在hadoop-*-test.jar的文件中,安装开销小,运行方便。基准测试工具很多无需传递额外参数,基准测试工具有利于快速检查搭建的hadoop cluster的性能状况,以供下一步的性能调优或者集群扩容甚至问题发现。
基准测试工具 | 用途 | 特点 |
TeraSort | 测试数据排序能力 | 1TB排序通常用于衡量分布式数据处 理框架的数据处理能力。Terasort是 Hadoop中的的一个排序作业,在2008年, Hadoop在1TB排序基准评估中赢得 第一名,耗时209秒。 |
TestDFSIO | 测试HDFS的I/0性能 | 本质为MapReduce |
MRBench | 测试小型作业是否快速响应 | 多次运行一个小型作业 |
NNBench | 测试namenode的加载过程 | |
Gridmix | 测试集群负载情况 | 是一个基准测试程序集合, 通过模拟真实场景数据来 逼真的为一个集群负载建模。 |
SWIM (Statistical Workload Injector for MapReduce) |
测试mapreduce负载情况 | 是一个针对mapreduce 负载的测试程序 |
TPCx-HS | 基于TeraSort和事务处理TPPC (Transaction Processing Performance Council) |