1. MapReduce程序开发步骤
编写map 和 reduce 程序–> 单元测试 -> 编写驱动程序进行验证-> 本地数据集调试 -> 部署到集群运行
用到的工具:
Junit、Mockito、Ant
2. 使用Configuration
关键点:
1、 Configuration类可以加载配置文件,包括系统的和自定义的
2、 addResource方法后面的配置文件会覆盖前面的
3、 配置文件的几个特性:name、value、description、final、${} 引用
4、 系统属性(System.setProperty)中的优先级高于源文件中的优先级
代码:
其中,添加配置文件最好使用 Path对象的方法,否则会找不到配置文件。注意黄色背景内容
public static void main(String[]args) {
// TODO Auto-generatedmethod stub
String baseDir = Thread.currentThread().getContextClassLoader()
.getResource(“”).getPath().substring(1)+ “demo/chp5/conf-1.xml”;
String fileStr = newFile(baseDir).getAbsolutePath();
Path filePath = newPath(baseDir);
System.out.println(“filePath=”+filePath);
Configuration conf = new Configuration();
conf.addResource(filePath);
//conf.addResource(“conf-2.xml“); //后面添加的会覆盖前面的
System.out.println(conf.get(“color”));
System.out.println(conf.get(“fs.default.name”));
}
3. 环境准备
1、 尽量保证运行和程序分离,也就是运行环境、运行程序、运行数据、配置文件之间的分离存放。
2、 Hadoop.job.ugi (用户标识)
辅助类:GenericOptionsParser,Tool 和 ToolRunner
GenericOptionsParser:解释常用命令选项
Tool接口,ToolRunner:运行应用程序,内部调用GenericOptionsParser
通过上面的方式,构建一个任务的执行框架,代码样例如下:
public classConfigurationPrinter extends Configured implements Tool {
//静态构造函数
static{
Configuration.addDefaultResource(“hdfs-default.xml”);
}
/* (non-Javadoc)
* @seeorg.apache.hadoop.util.Tool#run(java.lang.String[])
*/
@Override
public int run(String[] arg0) throws Exception{
// TODO Auto-generated method stub
Configuration conf = getConf();
for(Entry<String,String> entry :conf){
System.out.printf(“%s=%s\n”,entry.getKey(),entry.getValue());
}
return 0;
}
/**
* @paramargs
* @throwsException
*/
public static void main(String[] args) throwsException {
// TODO Auto-generated method stub
int exitCode = ToolRunner.run(newConfigurationPrinter(), args);
System.exit(exitCode);
}
}
4. 程序开发及测试
a) 编写单元测试
使用Mockito框架模拟进行测试。
b) 运行的代码框架包括:
驱动程序:XXXDriver,运行的主程序
Mapper:XXXMapper,mapper的程序
Reducer:XXXReducer,reducer的程序
失败
Tasktracker失败:
失败检测机制,是通过心跳进行检测。主要有:
(1) 超时:mapred.tasktracker.expiry.interval属性设置,单位毫秒
(2) 黑名单机制:失败任务数远远高于集群的平均失败任务数。
失败处理机制:
(1) 从等待任务调度的tasktracker池中移除
(2) 未完成的作业,重新运行和调度
(3) 黑名单中的tasktracker通过重启从jobtracker中移出。
JobTracker失败:
最严重的一种,目前Hadoop没有处理jobtracker失败的机制(单点故障)
3. 作业的调度
早期版本:先进先出算法(FIFO)
随后:加入设置作业优先级的功能(mapred.job.priority属性、JobClient的setJobPriority())
不支持抢占(FIFO算法决定)
默认调度器:FIFO;用户调度器:Fair Scheduler、Capacity Scheduler
Fair Scheduler(公平调度器)
目的:让每个用户公平的共享集群能力
特点:
(1) 支持抢占
(2) 短的作业将在合理的时间内完成
使用方式:
属于后续模块,需要专门调整
需要将其JAR文件放在Hadoop的类路径(从Hadoop的contrib/fairscheduler目录复制到lib目录)
设置mapred.jobtracker.taskScheduler属性:mapred.jobtracker.taskScheduler= org.apache.hadoop.mapred.FairScheduler
Capacity Scheduler
针对多用户的调度
允许用户或组织为每个用户或组织模拟一个独立的使用FIFO Scheduling的MapReduce集群。
4. Shuffle和排序
Shuffle:将map输出作为输入传给reducer(系统执行排序的过程)
MapReduce的核心部分,属于不断被优化和改进的代码库的一部分。
Map端:
环形内存缓冲区:
100MB:io.sort.mb 阀值:io.sort.spill.percent80% mapred.local.dir : 作业特定子目录
超过阀值则写入磁盘。如果写入过程中缓冲区填满,则堵塞直到写磁盘完成。
io.sort.factor:一次最多合并多少流,默认10
压缩:mapred.compress.map.output
Tracker.http.threads:针对每个tasktracker,而不是针对每个map任务槽,默认40;在运行大型作业的大型集群上,可以根据需要而增加。
Reduce端
Map输出文件位于运行map任务的tasktracker的本地磁盘;reduce输出并不这样
复制阶段(copyphase):mapred.reduce.parallel.copies ,默认5;设置多少并行获取map输出
排序、合并、合并印子、合并的次数
配置的调优:重要章节
1、给shuffle过程尽量多提供内存空间(猜测原因:避免写入磁盘、提高性能???)。所以,map和reduce应尽量少用内存
2、运行map任务和reduce任务的JVM,其内存大小在mapred.child.java.opts属性设置,应该尽量大。
3、在map端,可以通过避免多次溢出写磁盘来获取最佳性能
4、在reduce端,中间的数据全部驻留在内存时,就能获得最佳性能。
整个调优的思路是:减少磁盘读写(使用内存)、减少数据大小(压缩)
5. 任务的执行
推测执行:
提取为可能出错的任务建立一个备份任务,做好预案。
进行冗余,牺牲性能作为代价。
解决方式:在集群上关闭此选项,但根据个别作业需要再开启。
问题:推测执行选项是对整个集群还是作业???
答案:可以针对某个map和reduece开启,有两个选项
mapred.map.tasks.speculative.execution
mapred.reduce.tasks.speculative.execution
任务JVM重用:
对短时间执行的任务,启用JVM重用,避免启动JVM(1秒左右)的消耗。
mapred.job.reuse.jvm.num.tasks:指定给定作业每个JVM运行的任务的最大数,默认为1
-1则表示同一作业的任务都可以共享同一个JVM
JobConf中的setNumTaskToExecutePerJvm()来设置。
这个设置是针对作业粒度的。
重用是指JVM空闲后可以被分配给其他任务使用。
另一个好处:各个任务之间状态共享;共享数据;
跳过坏记录:
处理坏记录的最佳位置在于mapper和reducer代码。
skipping mode:
出现失败,报告给tasktracker,重新执行后,跳过该记录。
只有在任务失败两次后才会启用skippingmode
流程如下:
(1) 任务失败
(2) 任务失败
(3) 开启skipping mode。任务失败,但是失败记录由tasktracker保存
(4) 仍然启用skipping mode。任务继续运行,但跳过上一次尝试中失败的坏记录。
缺点:每次都只能检测一条坏记录,所以对多条坏记录的话,这个就是个灾难。。。。。
可以通过设置taskattempt的最多次数来设置:mapred.map.max.attemps mapred.reduce.max.attemps
坏记录保存在:_logs/skip
Hadoop fs –text 诊断
任务执行环境:
1、 Mapper和reducer中提供一个 configure() 方法实现。
2、 Streaming环境变量
3、 任务附属文件
防止文件覆盖
将任务写到特定的临时文件夹({mapred.output.dir}/_temporary/${mapred.task.id}),任务完成后,将该目录中的内容复制到作业的输出目录(${mapred.output.dir})。
Hadoop提供了方式便于程序开发使用:
检索mapred.work.output.dir检索
调用FileOutputFormat的getWorkOutputPath()静态方法得到表示工作目录的Path对象
MapReduce的类型和格式
要点:
1、MapReduce类型
1.1默认的MapReduce Job
2、输入格式
2.1输入分片与记录
2.2文本输入
2.3二进制输入
2.4多种输入
2.5数据库输入(和输出)
3、输出格式
3.1文本输出
3.2二进制输出
3.3多个输出
3.4延迟输出
3.5数据库输出
============================================
1、 MapReduce类型
Map和Reduce函数的常规格式:
map:(K1,V1) ——> list(K2,V2)
reduce:(K2,list(V2)) ——> list(K3,V3)
combine:(K2,list(V2)) ——> list(K2,V2)
partition:(K2,V2) ——> integer
类型分类:可以设置的属性和必须与类型相容的属性。其中可设置的属性,需要在程序中显式指定。
类型冲突是在作业执行过程中被检测出来的,所以比较明智的做法是先用少量的数据跑一次测试任务,发现并修正任何类型不兼容的问题。
1.1默认的MapReduce Job
0.20.2 后,相比之前,改变了如下内容:
1、Job替换JobConf,通过Configuration来代入。
可以在Job中设置MapperClass和ReduceClass,以及分区、任务数等属性。
选择reducer的个数:
1、 reducer最优个数与集群中可用的reducer任务槽数相关。
2、 总槽数=集群中节点数*每个节点的任务槽数。
3、 总槽数可以在mapred.tasktracker.reduce.tasks.maximun属性设置
常用方法:
- 设置比总槽数稍微少一些的reducer数,给任务留余地(容忍一些错误发生而不需要次延长作业运行时间)。
- 如果reduce任务很大,较好的做法是使用更多reducer,使任务粒度变小,这样任务的失败才不至于显著影响作业执行时间。
默认的Streaming作业
Hadoop streaming是Hadoop的一个工具, 它帮助用户创建和运行一类特殊的map/reduce作业, 这些特殊的map/reduce作业是由一些可执行文件或脚本文件充当mapper或者reducer。例如:
$HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \
-input myInputDirs \
-output myOutputDir \
-mapper /bin/cat \
-reducer /bin/wc
注意:必须提供一个mapper。
可以通过一个可配置的分隔符来进行分割,也可以由多个字段组合(Maper和Reduce的分隔符配置是相对独立的,可以分别设置)。可以由一条记录的前n个字段组成(由stream.num.map.output.key.fields 或 stream.num.reduce.output.key.Fields进行定义),剩下的字段就是值。
2、 输入格式
2.1输入分片与记录
层次关系是:输入分片(split)与map对应,是每个map处理的唯一单位。每个分片包括多条记录,每个记录都有对应键值对。
输入切片的接口:InputSplit接口(在org.interface InputSplit extends Writable){
long getLength() throws IOException;
String[] getLocations() throws IOException;
}
一个分片并不包含数据本身,而是指向数据的引用。存储位置供MapReduce系统使用以便将map任务尽量放在分片数据附近,而长度用来排序分片,以便优化处理最大的分片,从而最小化作业运行时间。
InputSplit不需要开发人员直接处理,由InputFormat创建。
FileInputFormat类:静态方法:addInputPath addInputPaths
路径可以表示一个文件、一个目录或是一个glob,即一个文件和目录的集合。
表示目录的路径包含这个目录下的所有的文件(是否包括子目录?答案:不包括,如果包含子目录,会被当做文件,出现错误)
过滤文件的方法:setInputPathFilter()
不设置过滤器,则默认排除隐藏文件(名称中已”.”和“_”开头的文件)
FileInputFormat类的输入分片:
FileInputFormat只分割大文件(超过HDFS块大小)。分片通常与HDFS块大小一样,但可以通过属性设置:mapred.min.split.size 和 mapred.max.split.size 和 dfs.block.size
最小分片大小,通常是1个字节。
分片大小的计算公式:
Max(minimumSize,min(maximumSize,blockSize))
minimumSize < blockSize < maximumSize
通过CombineFileInputFormat来合并小文件,环节小文件过多影响执行速度的问题。
应该尽量避免小文件,因为MapReduce处理数据的最佳速度最好与数据在集群中的传输速度相同,小文件会增加寻址次数、浪费NameNode的内存。
使用CombineFileInputFormat的时候需要自己实现getRecordReader()方法。
避免切分
1、 把最小分片大小设置为最大
2、 使用FileInputFormat具体子类,并且重载isSplitable()方法,将返回值设置为false
继承CombineFileInputFormat而不是FileInputFormat。
2.2文本输入
TextInputFormat:
键:LongWritable类型,存储该行在整个文件中的字节偏移量
值:这行的内容,不包括任何终止符(换行符和回车符)
输入分片和HDFS块之间可能不能很好的匹配,出现跨块的情况。
KeyValueTextInputFormat : 分界符 :key.value.separator.in.input.line
NLineInputFormat:与TextInputFormat一样,键是文件中行的字节偏移量,值是行本身。主要是希望mapper收到固定行数的输入。
XML:
1、 大多数XML文件不大,可以通过“把一个文件当成一条记录处理”的方式解决。
2、 StreamXmlRecordReader
2.3二进制输入
SequenceFileInputFormat
SequenceFileAsTextInputFormat
SequenceFileAsBinaryInputFormat
2.4多种输入
1、MultipleInputs类处理多种格式的输入,允许为每个输入路径指定InputFormat和Mapper。
2、两个mapper的输出类型是一样的,所以reducer看到的是聚集后的map输出,并不知道输入是不同的mapper产生的。
3、重载版本:addInputPath(),没有mapper参数,主要支持多种输入格式只有一个mapper。
2.5数据库输入(和输出)
DBInputFormat/DBOutPutFormat:
1、 使用JDBC
2、 适合加载小量的数据集,否则对数据库负担较重
在关系数据库和HDFS中移动数据的另一个办法是:使用Sqoop
3、 输出格式
3.1文本输出
1、TextOutputFormat
2、默认分隔符制表符。可以设置:mapred.textoutputformat.separator
3.2二进制输出
SequenceFileOutputFormat:输出为顺序文件,结构紧凑,易压缩
SequenceFileAsBinaryOutputFormat
SequenceFileOutputFormat
3.3多个输出
默认输出文件名格式:part-00000
通过MultipleOutputFormat 和MultipleOutputs进行文件名控制和输出多个文件。
通过setOutputFormat指定。
MultipleOutputFormat:格式化输出
MultipleOutputs:可以为不同的输出产生不同的类型
3.4延迟输出
3.5数据库输出
MapReduce的特性
要点:
1、计数器
1.1内置计数器
1.2用户定义的Java计数器
1.3用户定义的Streaming计数器
2、排序
2.1准备
2.2部分排序
2.3全排序
2.4辅助排序
3、连接
3.1map端连接
3.2reduce端连接
4、边数据分布
3.1利用JobConf来配置作业
3.2分布式缓存
5、MapReduce库类
============================================
1、 计数器
计数器主要用来收集系统信息和作业运行信息,用于知道作业成功、失败等情况,比日志更便利进行分析。
1.1内置计数器
Hadoop内置的计数器,记录作业执行情况和记录情况。包括MapReduce框架、文件系统、作业计数三大类。
计数器由关联任务维护,定期传递给tasktracker,再由tasktracker传给jobtracker。
计数器可以被全局聚集。内置的作业计数器实际上由jobtracker维护,不必在整个网络中传递。
当一个作业执行成功后,计数器的值才是完整可靠的。
1.2用户定义的Java计数器
MapReduce框架将跨所有map和reduce聚集这些计数器,并在作业结束时产生一个最终结果。
多个计数器由一个Java枚举类型来定义,以便对计数器分组。
通过reporter输出和写入。在0.20.2之上版本中使用context.getCounter(groupName, counterName) 来获取计数器配置并设置。
动态计数器
动态计数器,incrCounter(String group,String counter,long amount)
组名称,计数器名称,计数值
尽量为计数器提供易读的名称,以Java枚举类型为名创建一个属性文件,用下划线分割嵌套类型。属性文件与包含该枚举类型的*类放在同一目录。
CounterGroupName = Air Temperature Records //只有一个该属性,就是组的显示名称
MISSING.name = Missing //字段名称.name 格式
MALFORMED.name = malformed
可以采用本地化机制
获取计数器:
两种获取计数器的方法:
1、 hadoop job –counter 指令
2、 通过java API,在作业运行完成后,计数器稳定后获取。 使用job.getCounters()得到Counters
可能的问题:无法获取到有效的RunningJob对象,原因可能是:
1、 错误的指定了jobid
2、 内存中仅保留最新的100个作业(可以在mapred.jobtracker.completeuserjobs.maximun控制)
1.3用户定义的Streaming计数器
Streaming MapReduce程序通过向标准错误流发送一行特殊格式的信息来增加计数器的值,格式如下:
Reporter:counter:group,counter,amount
Python用法:
Sys.stderr.write(“reporter:counter:Temperature,Missing,1\n”)
状态信息:
Reporter:status:mesage
2、 排序
排序是MapReduce的核心技术。
2.1准备
每个map创建并输出一个块压缩的顺序文件。
2.2部分排序
控制排列顺序
1、 若属性mapred.output.key.comparator.class设置,则使用该类实例
2、 否则,键必须是WritableComparable的子类。
应用:基于分区的MapFile查找技术。
2.3全排序
只有一个分区可以实现,但无法利用并行的优势。
替代方案:
1、 创建一系列排好序的文件
2、 串联这些文件,
3、 生成一个全局排序的文件
思路:使用一个partitioner来描述全局排序的输出。
关键点在于如何划分各个分区。尽量使各分区的记录数相等。
1、 可以写一个MapReduce程序来计算各个范围数据的分布,用来做评估。但性能较低
2、 可以通过对键空间进行采样,获取键的近似分布。
Hadoop内置了采样器,不需要自己编写。
Input Sampler类实现了Sampler接口,getSampler方法,返回一系列的样本键。
通常不直接由客户端调用,而是由InputSampler类的静态方法writePartitionFile()调用,目的是创建一个顺序文件来存储定义分区的键。
顺序文件供TotalOrderPartitioner使用,为排序作业创建分区。
2.4辅助排序
主要解决对键所对应的值的排序。
1、 定义包括自然键和自然值的组合键
2、 键的comparator根据组合键对记录进行排序,即同时利用自然键和自然值进行排序
3、 针对组合键的comparator和分组comparator在进行分区和分组时均只考虑自然键
3、 连接
连接操作的具体实现技术取决于数据集的规模和分区方式。
1、 如果一个数据集很大,一个数据集很小,则将集合分发到集群中每一个节点,从而实现连接
2、 对两个数据集都很大,则需要根据数据的组织方式,来决定是在map端连接还是在reduce端连接。
3.1map端连接
在两个大规模输入数据集之间的map端连接会在数据到达map函数之前就执行连接操作。
3.2reduce端连接
Reduce端连接并不要求输入数据集符合特定结构,因而reduce端连接比ap端连接更为常用。但由于两个数据集均需经过MapReduce的shuffle过程,所以reduce端连接的效率往往更低一些。
基本思路:mapper为各个记录标记源,并且使用连接健作为map输出键,使键相同的记录放在同一个reducer中。
主要技术有:
多输出:MultipleInputs
辅助排序:
4、 边数据分布
“边数据”(side data)是作业所需的额外的只读数据,以辅助处理主数据集。
3.1利用JobConf来配置作业
如果只需向任务传递少量元数据则非常有用。如果想获取任务的值,只需覆盖Mapper或Reducer类的configure()方法,并调用传入JobConf对象的getter方法即可。
3.2分布式缓存
Hadoop的分布式缓存拷贝机制,它能够在任务运行过程中及时将文件和存档复制到任务节点以供使用。为了节约网络带宽,在每一个作业中,各个文件通常只需复制到一个节点一次。
缓存的容量是有限的,默认10G,可以在local.cache.size进行配置
工作机制:
1、 用户启动一个作业,hadoop将由-files 和 –archieves选项所指定的文件复制到jobtracker的文件系统中。
2、 在任务运行之前,tasktracker将文件从jobtracker的文件系统中复制到本地磁盘—缓存—使任务能够访问文件。
Tasktracker为缓存中的文件维护一个计数器统计使用情况,如果计数器为0,则清除。
分布式缓存的API:DistributedCache API
通过GenericOptionsParser间接使用分布式缓存。
方法:addCachedFile() 和 addCacheArchive() 方法告诉分布式缓存在HDFS中的位置。
获取缓存中的有效文件的列表:
方法:getLocalCachedFiles() 和 getLocalCacheArchives() 返回一个指向本地文件路径对象数组。
5、 MapReduce库类
1、 ChainMapper、ChainReducer
2、 FieldSelectionMapReduce
3、 IntSumRecuder LongSumReducer
4、 InverseMapper
5、 TokenCounterMapper
6、 RegexMapper
构建Hadoop集群
要点:
1、集群规范
1.1网络拓扑
2、集群的构建和安装
2.1安装Java
2.2创建Hadoop用户
2.3安装Hadoop
2.4测试安装
3、SSH配置
4、Hadoop配置
3.1配置管理
3.2环境设置
3.3 Hadoop守护进程的关键属性
3.4 Hadoop守护进程的地址和端口
3.5 Hadoop的其他属性
3.6 创建用户账号
5、安全性
3.1Kerberos和Hadoop
3.2委托令牌
3.3 其他安全性改进
6、利用基准测试程序测试Hadoop集群
3.1Hadoop基准测试程序
3.2用户的作业
7、云端的Hadoop
3.1Amazon EC2上的Hadoop
============================================
1、 集群规范
Hadoop运行在商业硬件上,注意两个问题:
1、 商业硬件并不等同于低端硬件,低端机器便宜的零部件会导致维护成本巨大。
2、 也不建议构建在大型机器上,因为集群服务器较少,某一台出现故障,对整个集群影响较大。(故障硬件所占的比重增大了)
尽管集群采用的机器硬件会有所不同,但Hadoop一般使用多核CPU和多磁盘,以便充分利用现代化硬件的强大功能。
2010年搭建Hadoop硬件的典型规格为:
处理器:2个四核 2-2.5GHz CPU
内存: 16 – 24GB ECC RAM
存储器:4 * 1TB SATA硬盘
网络:千兆以太网
不适用RAID的原因:
1、 不会给HDFS带来好处;HDFS本身已满足数据备份需求。
2、 尽管RAID条带化(RAID 0)技术被广泛用于提升性能,但其速度仍然比HDFS的JBOD(Just a Bunch Of Disks)慢
3、 JBOD配置的某一磁盘出现故障,HDFS还可以忽略该磁盘继续工作,RAID的某一盘片故障可能会导致整个磁盘阵列不可用。
Hadoop是用Java编写,可用在任意装了JVM的机器上运行,但仍有部分代码(控制脚本等)需要在Unix环境下执行;所以:hadoop并不适宜在非Unix平台上运行供生产用。
1、 集群大小可用根据需要逐步扩展(初始大概在10台左右)。
2、 辅助namenode和namenode可用运行在同一机器之中,但由于内存的原因(辅助与主需要同样的内存需求),二者最好运行在独立的硬件只上。
3、 运行namenode的机器一般采用64位硬件,避免32位架构下Java堆的3GB内存限制。
网络拓扑:
1、 通常Hadoop集群架构包含两级网络拓扑。
2、 这一架构的突出特点是:同一机架内部节点间的总带宽要远高于不同机架节点的带宽。
典型场景是:
1、 各机架装配30-40个服务器,共享一个1GB的交换机
2、 各机架的交换机又通过上行链路与一个核心交换机或者路由器互联。
对多机架的集群,要搞清楚节点和机架之间的映射关系,主要是网络位置、距离。
Hadoop配置需要通过一个java接口DNSToSwitchMapping来记录节点地址和网络位置之间的映射关系。
一定要注意配置映射关系
2、 集群的构建和安装
1、Hadoop安装方式,可以用工具安装,也可以通过SHELL自己实现。
2、安装Java,需要java 6或者更新版本,首选方案采用最新稳定的sun JDK
3、 创建Hadoop用户,最好是创建特定的Hadoop用户账号以区分Hadoop和本机上的其他服务。安装方式可以采用NFS挂载的方式 或者 本地安装;如果选择NFS,则有必要考虑autofs
4、 安装Hadoop,安装可行的路径有:/usr/local 、 /opt 、 /home/hadoop(自定义) ;注意:hadoop并没有安装再hadoop用户的home目录下,最好是在某一NFS挂载的目录上。(便于维护,多服务器同步)
5、 HDFS和MapReduce最好分别安装在不同位置,便于升级(可以打一个补丁,但HDFS仍在运行);独立安装后,仍然可以共享配置信息,方法是使用 –config(启动守护进程时)选项指向同一目录。主要的核心是:独立安装、共享配置、共用日志目录。
6、 安装后,要注意进行测试安装。
7、 SSH配置
创建公钥/私钥对,利用NFS在整个集群共享该密钥对。可以通过NFS或者本地复制的方式共享。
8、 Hadoop配置
1、 配置文件通常安装再安装程序外部,便于程序升级和同步。
2、 配置文件同步工具:rsync、dsh、pdsh
3、 也支持为所有的主机器和工作机器采用同一套配置文件。
4、 增加“机器类”来解决不同配置服务器组成的集群。
5、 对大型集群来说,同步化所有机器上的配置文件极有挑战性(如某台机器有异常,但此时发出更新配置的指令,如何保证机器恢复正常后也能更新配置?),推荐使用控制管理工具管理集群。
6、 Masters 和slaves文件;无须分发到所有节点,只在namenode和jobtracker上配置即可。
7、 对小型集群(几十个节点),可以直接将所有守护进程都部署在一台机器上;但对大型集群,最好能让守护进程运行在不同机器上。
8、 Namenode在内存中保存整个命名空间的所有文件和块元数据,内存需求很大。辅助namenode需要同样大小的内存空间。Jobtracker会使用大量的CPU和内存资源。这两者最好是部署在一个专用节点上。
9、 默认情况,每个守护进程1000M内存(可以在配置中设置);tasktracker启动独立的子JVM也消耗内存;内存需求需要结合守护进程和独立的子JVM进行运算;
10、 任务数(map和reduce)设置的规则是:任务数/处理器核数 在1和2之间,考虑到datanode和tasktracker也需要,所以一般设置为n-1;也可以设置MapReduce所能操作的最大内存量。一般1000M的内存可以存储几百万个文件的数据块的引用。
11、 可以使用一些工具监控集群的内存使用情况,以优化分配方案;Ganglia是采集此类信息的有效工具。
12、 日志目录可以设置,推荐独立程序之外;两类日志:
a) 日志文件(.log)应用程序的日志信息
b) .out 日志,记录标准输出和标准错误日志;系统保留最新的5个日志文件,在日志文件后加一个后缀,5表示最旧的文件。
c) 日志文件的名称包括运行守护进程的用户名称、守护进程名称和本地主机名等信息,所以可以将日志文件输出到同一目录(NFS)
13、 StrictHostKeyChecking不适合大型集群环境。大型集群下从某机器源获取配置需要注意对源机器的影响。
14、 配置文件中的目录可配置多个,根据属性的不同作用主要有:
a) 同时存储,多备份
b) 分散在不同磁盘,提高IO性能;
c) 为了提高性能,最好为各个本地磁盘指定一个存储目录;使用noatime挂载磁盘也是提高性能的方法。
15、 HDFS端口8020;MapReduce端口8021
16、 集群成员可以进行设置,来加入或者排除服务器;
17、 缓冲区大小最好修改为64KB或者128KB;默认为4KB
18、 可以通过dfs.datanode.du.reserved设置保留的存储空间
19、 回收站特性
20、 设置任务的内存限制,防止出现任务异常,用光内存;有两个办法:
a) 设置mapred.child.ulimit项,需要大于任务的JVM的内存
b) 通过limits.conf在操作系统层面限制进程所消耗的资源
21、 创建用户账号,并最好设置各用户的目录容量
9、 安全性
1、 主要通过Kerberos来实现用户认证。
2、 在0.20版本后逐步加入,在0.22版本之前,这项特性的有效性和稳定性均不成熟。
10、 利用基准测试程序测试Hadoop集群
1、 集群正确验证:运行若干作业,并确信获得了预期结果。同时也可以根据此调整集群设置以优化性能。
2、 为获得最佳效果,不能在运行基准测试程序时还同时运行其他任务;
3、 硬盘故障是新系统常见的硬件故障。
4、 Hadoop自带若干基准测试程序
a) 使用TestDFSIO来测试HDFS:测试读和写
b) 使用Sort程序测试MapReduce;对排序程序总执行时间比较关注,可以通过web界面观察作业执行过程。
c) 其他基准测试:
i. MPBench(使用mrbench选项)会多次运行一个小型作业,以检验小型作业是否能快速响应
ii. NNBench(使用nnbench选项)专门用于测试namenode硬件的负载
iii. Gridmix是一个基准测试程序套装,可以模拟真实常见的数据访问模式,逼真的为一个集群的负载建模。对用户搭建的第一个集群,这个工具比较合适。
11、 云端的Hadoop
Amazon提供Hadoop云服务:Elastic MapReduce。
Apache Whirr项目可以比较方便的在EC2和其他云服务提供商上运行Hadoop
由于S3系统并不和EC2节点兼容,所以不可以直接使用S3系统。
管理Hadoop
要点:
1、HDFS
1.1永久性数据结构
1.2 安全模式
1.3 日志审计
1.4 工具
2、监控
2.1 日志
2.2 度量
2.3 Java管理扩展(JMX)
3、维护
3.1 日常管理过程
3.2 委任和解除节点
3.3 升级
============================================
1、 HDFS
1、 永久性数据结构
对管理员来说,需要深入了解namenode、辅助namenode和datanode等HDFS组件如何在磁盘组织永久性数据。
Namenode的目录结构:Namenode格式化后,将产生如下的目录结构:
${dfs.name.dir}/current/VERSION –java属性文件,包括HDFS版本信息等
/edits
/fsimage
/fstime
文件系统映像和编辑日志:
1、 fsimage文件是文件系统元数据的一个永久性检查点。包含文件系统中的所有目录和文件inode序列化信息。
2、 解决edits文件无限增长的问题,主要解决方案是:运行辅助namenode,为主namenode内存中的文件系统元数据创建检查点。
辅助namenode的目录结构:
${dfs.name.dir}/current/VERSION –java属性文件,包括HDFS版本信息等
/edits
/fsimage
/fstime
/previous.checkpoint/VERSION
/edits
/fsimage
/fstime
1、 辅助namenode的previous.checkpoint目录、辅助namenode的current目录和主namenode的current目录的布局相同。好处在于:在主namenode发生故障时,可以从辅助namenode回复数据。
datanode的目录结构:
datanode的存储目录是启动时自动创建的,不需要额外格式化。
datanode的关键文件和目录如下:
${dfs.name.dir}/current/VERSION
/blk_<id_1>
/blk_<id_1>.meta
/blk_<id_2>
/blk_<id_2>.meta
/…….
/blk_<id_64>
/blk_<id_64>.meta
/subdir0/
/subdir1/
/……
/subdir63/
1、VERSION中的namespaceID是首次访问namenode的时候,从namenode获取的。
2、各个datanode的storageID都不相同(但对于存储目录来说是相同的)
Current中两种文件类型:HDFS块文件(原始文件)和块的元数据文件(头部和该块各区段的一系列的校验和)。
2、 目录存储64个(dfs.datanode.numblocks设置)后就创建一个子目录
3、 同一个datanode上的每个磁盘上的块不会重复,不同datanode之间的块才可能重复。
安全模式:
启动过程中的准确阶段,安全模式
1、 安全模式下,只有访问文件系统元数据的文件系统操作是会成功的。
2、 系统中数据块的位置并不是由namenode维护的,而是以块列表的形式存储在datanode中。系统正常操作期间,namenode会在内存中保留所有块位置的映射信息。安全模式下,各个datanode会向namenode检查块列表信息,namenode了解到足够多的块位置信息之后,即可高效运行文件系统。
3、 安全模式下,namenode并不向datanode发出任何块复制和块删除的指令。
4、 如果满足“最小复本条件”,namenode会在30秒之后退出安全模式。
5、 启动刚格式化的HDFS集群时,不会进入安全模式(没有任何块)
查看namenode是否处于安全模式:hadoop dfsadmin –safemode get
执行某条命令之前,先退出安全模式:hadoop dfsadmin –safemode wait
进入安全模式:hadoop dfsadmin –safemode enter
离开安全模式:hadoop dfsadmin –safemode leave
日志审计:
1、对日志审计是log4j在INFO级别实现的。默认的设置为WARN,未启动该项特性。
2、 为了不与namenode日志混在一起,最好配置log4j,将审计日志写到单独的文件中。
工具:
1、 dfsadmin工具
作用:查找HDFS状态信息,又可在HDFS上执行管理操作。
只有当用户具有超级用户权限,才可以使用这个工具修改HDFS的状态。
2、 fsck工具
作用:检查HDFS中文件的健康状况。
执行fsck可以执行如下操作:
移动: -move 转移到HDFS的/lost+found目录
删除: -delete
3、 datanode块扫描器
作用:定期检测本节点上的所有块,从而在客户端读到坏块之前及时地检测和修复坏块。
默认每隔三周(504小时)执行一次,dfs.datanode.scan.period.hours设置
损坏的块被报给namenode,并被及时修复。
http://datanode:50075/blockScannerReport
http://datanode:50075/blockScannerReport?Listblocks
4、 均衡器
Balancer是一个Hadoop守护进程,它将块从忙碌的datanode移到相对空闲的datanode,从而重新分配块。同时坚持复本放置策略,将复本分散到不同机架,以降低数据损坏率。
均衡的条件:每隔datanode的使用率和集群的使用率非常接近
启动:start-balancer.sh
-threshold 指定阀值;默认10%
均衡器后台运行,且带宽是有限的(默认1M/s )在hdfs-site.xml的dfs.balance.bandwidthPerSec指定(单位字节)
2、 监控
1、 主守护进程最需要被监控。
2、 Datanode和tasktracker经常出现故障,在大型集群中故障率比较高
3、 除了监控,可以定期运行一些测试作业,检查集群的运行情况
4、 常用的监控工具是:Chukwa
日志:
1、 可以通过守护进程的网页,在守护进程的网页的 /logLevel 目录下来改变日志级别
2、 日志名称最好从源代码中查找
3、 获取堆栈轨迹:网页界面的/stacks目录
度量:
1、 HDFS和MapReduce守护进程收集的事件和度量相关的信息,这些信息统称为“度量”
2、 度量从属于特定的上下文(context)。目前Hadoop使用“dfs”、“mapred”、“rpc”、“jvm”四个上下文。
3、 度量和计数器的区别:
a) 主要区别是使用范围不同。度量由守护进程收集。计数器由mapreduce任务收集后再生成针对整个作业进行汇总。
b) 工作方式也不同,包括数据采集和聚集过程。计数器是MapReduce的特性;度量是收集机制和接收更新的组件独立。
4、 FileContext:将度量写到一个文件
5、 GangliaContext:Ganglia针对超大规模集群的开源的分布式监控系统。
6、 NullContextWithUpdateThread
7、 CompositeContext
个人理解:度量主要是用来收集集群运行情况,进行监控
Java管理扩展(JMX)
1、 标准的Java API,可监控和管理应用。
2、 Hadoop包括多个托管bean(MBean),可以将Hadoop度量发布给支持JMX的应用。目前支持dfs和rpc,不支持mapred和jvm
3、 JDK自带的JConsole工具来浏览JVM中的MBean,可以浏览Hadoop的度量
比较常用普遍的方案是:
同时使用Ganglia和Nagios这样的警告系统来监控Hadoop系统。Ganglia擅长高效收集大量度量,并以图形化界面呈现;Nagios和类似系统擅长在某项度量的关键阀值被突破之后及时报警。
3、 维护
日常管理过程
1、 元数据备份
2、 数据备份
3、 Fsck工具
4、 文件系统均衡器
委任和解除节点
1、 正常情况下,节点同时运行datanode和tasktracker,二者一般同时委任或解除。
委任新节点:
1、 配置hdfs-site.xml 指向namenode
2、 配置mapred-site.xml文件,指向jobtracker
3、 启动datanode和jobtracker守护进程
允许连接的机器的配置:dfs.hosts属性()
解除旧节点:
用户将拟退出的若干datanode告知namenode,方可在这些datanode停机之前将块复制到其他datanode。
升级:
需要细致的规划,特别是HDFS的升级,防止数据丢失。
规划过程最好包括在一个小型测试集群上的测试过程,以评估是否能够承担数据丢失的损失。
如果文件系统布局不改变,升级集群就比较简单:
1、 在集群上安装新的HDFS和MapReduce
2、 关闭旧的守护进程,升级配置文件
3、 启动新的守护进程,令客户端使用新的库
整个过程完全可逆。
升级成功后,需要执行几个清除步骤:
1、 从集群中移除旧的安装和配置文件
2、 在代码和配置文件中修补被弃用的警告信息。
HDFS的数据和元数据升级:
1、 仅当系统健康时,才可升级,升级之前要用fsck工具全面检查。
2、 升级前,最好清空临时文件。
转载:http://www.cnzqs.com/?p=29