第一章:初识Hadoop
MapReduce三大设计目标:
- 为只需要短短几分钟或几个小时就可以完成的作业提供服务
- 运行于同一个内部有高速网络连接的数据中心内
- 数据中心内的计算器都是可靠的、专门的硬件
提供Hadoop支持的公司:Cloudera、Hortonworks、MapR等
MapReduce: input --> map --> shuffle --> reduce --> output
Map: extends Mapper 输入参数: 输入键、输入值、输出键、输出值
Reduce: extends Reducer
Job规定步骤:
- 构造Job,需要指定输入和输出数据的路径
- setMapperClass() 和 setReduceClass(),需要指定需要用的map类型和reduce类型
- setOutputKeyClass() 和 setOutputValueClass()方法控制reduce函数的输出类型,并且必须和Reduce类产生的相匹配。
- 在设置定义map和reduce函数的类的之后,可以开始运行作业。Job中的waitForCompletion()方法提交作业并等待执行完成。
数据流:
如果一个任务失败,它将在另一个不同的节点上自动重新调度运行。
Map数确定、分片:Hadoop将MapReduce的输入数据划分成等长的小数据块,称为输入分片
Hadoop为每个分片构建map任务
最佳分片的大小应该与块大小相同,确保可以存储在单个节点上的最大输入块的大小
第一个副本存储在本地节点上,其他复本出于可靠性考虑存储在其他机器的节点中
Reduce的任务的数:独立确定
Combiner: 避免map和reduce任务之间的数据传输,combinner不能取代reduce函数,只能帮助减少map和reduce之间的数据传输量
第三章 Hadoop分布式文件系统
HDFS以流式数据访问模式来存储超大文件
HDFS不适用之处:
- 低时间延迟的数据访问
- 大量的小文件
- 多用户写入,任意修改文件
HDFS块: 默认128MB,小于一个块大小的文件不会占据整个块的空间
HDFS块比磁盘的块大,其目的是为了最小化寻址开销
块抽象优点:
- 一个文件的大小可以大于网络中任意一个磁盘的容量
- 使用抽象块而非整个文件作为存储单元,大大简化了存储子系统的设计。块只需要存储大块数据,而文件的元数据并不需要与块一同存储。其他系统也可以单独管理元数据
- 块还非常适合用于数据备份进而提供数据容错能力和提高可用性
显示块信息: hdfs fsck / -files -blocks
NameNode: 管理文件系统的命名空间,维护着文件系统树及整棵树内所有的文件和目录。
NameNode在内存中保存文件系统中每个文件和每个数据块的引用关系,对于一个拥有大量文件的超大集群来说,内存将成为瓶颈。
2.x版本引入了namenode扩展,每个namenode管理文件系统命名空间的一部分。
联邦环境下,每个namenode维护一个命名空间卷(命名空间元数据 + 数据块池(所有数据块))
DataNode:是文件系统的工作节点,根据需要存储并检索数据块,并且定期向namenode发送它们所存储的块的列表。
NameNode容错:
- 第一种机制是备份那些组成文件系统元数据持久状态的文件,在多个文件系统上保存元数据的持久状态
- 运行一个辅助namenode
块缓存:
对于访问频繁的文件,其对应的块可能被显式地缓存在datanode的内存中,以堆外块缓存的形式存在。可以利用块缓存的优势提高读操作的性能
文件系统的基本操作:
从本地将一个文件复制到HDFS:hadoop fs -copyFromLocal xxxx xxxx
副本系数: drwxr-xr-x 1 tom supergroup 0 2014-10-04 13:22 books
FileSystem基础类:
IOUtils:
InputStream in = fs.open(new Path(uri));
IOUtils.copyBytes(in,System.out,4096,false);
FSDataInputStream对象 / FSDataOutputStream对象:
FileSystem 的open方法返回的是FSDataInputStream对象
FileStatus() 文件元数据:
FileStatus封装了文件系统中文件和目录的元数据,包括文件长度、块大小、副本、修改时间、所有者、权限信息。
listStatus() 列出文件
globStatus() 文件模式
批量处理。返回路径格式与指定模式匹配的所有FileStatus对象组成的数组,并按路径排序
PathFilter对象
用于排除匹配正则表达式的路径
public class RegexExcludePathFilter implements PathFilter{
private final String regex;
public RegexExcludePathFilter(String regex){
this.regex = regex;
}
public boolean accept(Path path){
return !path.toString().matches(regex);
}
}
fs.globStatus(new Path("/2007/*/*"),new RegexExcludeFilter("^.*/2007/12/31$"))
HDFS读取数据过程:
- DistributedFileSystem通过使用远程过程调用(RPC)来调用namenode,确定块位置
- 这些datanode根据它们与客户端的距离进行排序(两个节点的带宽作为距离)
- 客户端选择连接最近的datanode进行连接,并反复执行read()
- DFSInputStream关闭与该datanode的连接,然后寻找下一个块最佳datanode
HDFS写入数据过程:
- DistributedFileSystem对象调用create()来创建文件
- namenode检查以确保这个文件不存在以及客户端有新建文件的权限
- 如果通过,namenode会创建一条新文件记录
- DistributedFileSystem会返回一个FSDataOutputStream对象,由此客户端可以开始写入数据
- DFSOutputStream将它划分成一个个数据包,并写入内部队列
- DataStreamer处理数据队列,并将数据存储到合适的datanode中
- 第一个datanode将数据发送给管线中的第二个datanode,第二个datanode将数据发送给管线中的第三个datanode......
在datanode写入时发生故障时:
关闭管线,从管线中删除datanode,并基于正常的datanode构建一条新管线,余下的数据写入管线中正常的datanode
HDFS复本选择:
- 运行客户端的节点上放第一个复本
- 第2个复本放在与第一个不同且随机另外选择的机架中节点上
- 第3个复本与第2个复本放在同一个机架上,且随机选择另一个节点
HDFS一致性模型:
- 新建一个文件后,在文件系统的命名空间中立即可见
- 但是写入一个文件并不保证能立即可见
- 当写入的数据超过一个块后,第一个数据块对新的reader就是可见的,当前正在写入的块对其他reader不可见
- 强制hflush(),保证所有新的reader均可见
!!hflush() 不保证datanode已经将数据写到磁盘上,仅保证数据在datanode的内存中(如果断电,数据会丢失)。Hdfs关闭其实就隐含了执行hflush() 方法
!!为确保数据写入到磁盘上,可以用hsync()替代
distcp方法
distcp使用MapReduce作业来实现,复制作业是通过集群中并行运行map来完成。没有reduce
hadoop distcp dir1 dir2
-overwirte
-update 仅更新发生变化的文件
-m 指定map数目
-delete 可以删除目标路径中任意没有在源路径中出现的文件或目录
-P 文件状态属性如权限、块大小和复本数被保留
为保证hdfs均衡,可考虑map数量多于节点中的数量
第4章 关于Yarn
Yarn:Yet Another Resource Negotiator
Yarn应用运行机制:
两个长期运行的守护进程:
- 资源管理器(ResourceManager):监控资源使用
- 节点管理器(Node Manager):启动和监控容器(Container)
- Containner: 用于执行特定应用程序的进程,有内存、CPU等资源限制
Yarn运行过程:
- 向ResourceManager 提交Yarn应用
- 通过NodeManager启动Containner
- 一个应用的多个实例都对应一个application master
- Containner通过心跳,向ResourceManager进行通信,Container执行任务
- 一个节点已经运行了别的容器无法再启动新的容器,如果有应用请求该节点,yarn将尝试在同一个机架中的其他节点上启动一个容器,如果不行,则会尝试集群中的任意一个节点
- 当启动一个容器用户处理hdfs数据块时,yarn会向存储数据块的节点申请容器
- Yarn可以在任意时刻提出申请资源
Yarn与MapReduce 1相对比
MapReduce 1中有两类守护进程控制着作业执行:
一个Jobtracker以及多个tasktracker
tasktracker在运行任务的同时将运行进度报告发送给jobtracker,jobtracker记录每项作业任务的整体进度情况
jobtracker 负责作业调度 & 进度监控
MapReduce 1 |
Yarn |
Jobtracker |
ResourceManager、application master、时间轴服务器 |
Tasktracker |
NodeManager |
Slot |
Container |
Yarn优点:
- 可扩展性:MapReduce 1在任务达到4000时会遇到扩展性瓶颈,Yarn利用RM和application master分离架构可将近10000
- 可用性:当服务守护进程失败时,可以为另一个守护进程复制接管工作所需的状态以便继续服务
- 利用率
- 多租户:MapReduce仅仅是许多Yarn应用中的一个
Yarn的三种调度:
- FIFO调度器
- 容量调度器:一个独立的专门的队列保证小作业提交
- 公平调度器:在运行作业之间动态平衡资源,每个作业都能保证公平共享资源
- 启动公平调度器:yarn.resourcemanager.scheduler.class 设置为 org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler
- 队列的放置:(1)specified 表明应用放进指定队列中 (2)primaryGroup 应用放在以用户的主Unix组名命名的队列中 (3)Default 应用放进dev.eng队列中
弹性队列:单个队列不会超过队列容量,但不够时会进行弹性扩容
延迟调度
抢占:
- 开启抢占:yarn.scheduler.fair.preemption
- 最小共享:指定时间未获得被承诺的最小共享资源,调度器就会抢占其他容器
- 公平共享:指定时间内获得的资源仍低于其公平共享份额的一半,调度器就会抢占其他容器
第5章 Hadoop的I/O操作
HDFS数据完整性校验
- Hdfs会对写入的所有数据计算校验和,并在读取数据时验证校验和
- datanode负责在收到数据后存储该数据及其校验和之前对数据进行验证
- 客户端从datanode读取数据时,也会验证校验和,将它们与datanode中存储中存储的校验和进行比较。
- datanode后台会运行DataBolockScanner,定期检查datanode上的数据块
(若不通过,namenode会标记损坏,并将副本复制到另一个datanode)
fs -checksum 检验校验和
LocalFileSystem通过ChecksumFileSystem执行客户端的校验和验证,在写入文件时会产生.filename.crc隐藏文件
压缩
在MapReduce中使用压缩:mapreduce.output.fileoutputformat.compress = true
序列化
将结构化对象转化为字节流以便在网络上传输或写到磁盘进行永久存储的过程
序列化两大领域:进程间通讯 、 永久存储
- Writable接口
- WritableComparable接口和comparator
Wriable类
Java基本类型 Writable实现
boolean BooleanWritable
byte ByteWritable
Short ShortWritable
int IntWritable 定长格式
VintWritable 变长格式
float FloatWritable
long LongWriable
VlongWritable
double DoubleWritable
byte[] BytesWritable
null NullWritable
String[]/enum[] ObjectWritable
Writable集合类:
ArrayWritable、ArrayPrimitiveWritable、TwoDArrayWritable、MapWritable、SortedMapWritable、EnumMapWritable
第6章 MapReduce应用开发
Configuraion: 如果资源按顺序添加,后添加的属性会覆盖之前定义的属性
Maven创建Eclipse配置文件,将项目导入到Eclipse:
mvn eclipse:eclipse -DdownloadSources=true -DdownloadJavadocs=true
作业调优检查:
- mapper的数量
- reducer的数量
- combiner
- 中间值的压缩
- 自定义序列
- 调成shuffle
MapReduce工作流
不同的mapper实现不同的函数,然后使用Hadoop的ChainMapper类库将它们连接成一个mapper,结合使用ChainReducer,可以在MapReduce作业中运行一些列的mapper
管理MapReduce工作流:org.apache.hadoop.mapreduce.jobcontrol : JobControl
(表示一个作业的运行图,可以加入作业配置,告知JobControl实例作业之间的依赖关系)
Apache Oozie:运行工作流系统,由相互依赖的作业组成,Oozie更容易对失败流重运行,Oozie通过回调向客户端通知工作流的状态
- 工作流引擎:负责存储和运行由不同类型Hadoop作业组成的工作流
- coordinator引擎:负责基于预定义的调度策略及数据可用性运行作业流作业
工作流:是一个由动作节点和控制流节点组成的DAG
工作流定义:XML P180
Hue可操作管理的组件包括:HDFS、Hive、Zookeeper、Oozie、MapReduce、Solr、HBase、Spark
第7章 MapReduce的工作机制
- 客户端,提交MapReduce作业
- Yarn资源管理器,负责协调集群上计算机资源的分配
- Yarn节点管理器,负责启动和监视集群中机器上的计算容器
- MapReduce的application master,负责协调运行MapReduce作业的任务。它和MapReduce任务在容器中运行,这些容器由节点管理器进行管理
- 分布式文件系统(HDFS),用来与其他实体间共享作业文件
application master是一个java程序,主类是MRAppMaste,application master必须决定如果构成MapReduce作业的各个任务
Uber任务运行:小作业(少于10个mapper且只有一个reducer)选择在同一个JVM上运行任务
开启Uber:mapreduce.job.ubertask.enable = true
Reduce任务开始:直到5%的map任务完成,reduce请求才开始发出。Reduce任务能在集群中任意位置运行,但是map任务的请求有着本地化局限。
mapreduce.map.memory.mb
mapreduce.reduce.memory.mb
mapreduce.map.cpu.vcores
mapreduce.reduce.cpu.vcoresp.memory.mb
YarnChild : application master 通过与节点管理器通信来启动容器,该任务由主类为YarnChild的一个Java应用程序执行。它在运行前,首先将任务需要的资源本地化,包括作业的配置、jar文件和所有来自分布式缓存的文件,最后,运行map任务和reduce任务。
子进程通信:子进程和自己的父application master 通过 umbilical 接口通信。
每隔3秒钟,任务通过这个umbilical接口向自己的application master报告进度和状态,application master会形成一个作业的汇聚视图。
客户端每秒轮询一次application master接收最新状态
- 任务失败:application master被告知任务失败后,将重新调度该任务的执行,并会试图避免在以前失败过的节点管理器上重新调度该任务,如果一个任务失败过4次,将不会再尝试。
map最多尝试次数:mapreduce.map.maxattempts
reduce最多尝试次数:mapreduce.reduce.maxattempts
允许任务失败的百分比:
mapreduce.map.failures.maxpercent mapreduce.reduce.failures.maxpercent
- application master运行失败:
mapreudce.am.max-attempts
- 节点管理器运行失败:如果10分钟内没有收到一条心跳信息,资源管理器将会通知停止发送心跳信息的节点管理器,并且将其从自己的节点池中移除以调度启动容器。如果应用程序的运行失败次数过高,节点管理器可能会被拉黑
Shuffle和排序:
将map输出作为输入传给reducer的过程成为shuffle,每个map任务都有一个环形内存缓冲区用于存储任务输出
combiner使得map输出结果更紧凑,可以在输入上反复运行,不影响最终结果。
Reduce复制阶段:每个map任务完成时间可能不同,在每个map完成时,reduce开始复制map的输出。reduce有少量的复制线程,因此能够并行取得map输出。默认值是5个线程。(reducer中的一个线程会定期询问master以便获取map输出主机的位置,直到获取所有输出位置)
- 如果map输出相当小,会被复制到reduce任务的JVM内存中
- 否则map输出被复制到磁盘
Reduce排序阶段:复制完所有map输出后,reduce任务进入排序阶段,每个阶段将合并map输出,维持顺序排序。
mapreduce.task.io.sort.factor 合并因子(如果设置为10,每趟将合并10个文件)
Map端调优
mapreduce.task.io.sort.mb |
排序map输出时使用的内存缓冲区的大小 |
mapreduce.map.sort.spill.percent |
map输出内存缓冲和用来磁盘使用的比例 |
mapreduce.task.io.sort.factor |
排序文件时,一次最多合并的流数 |
mapreudce.map.combine.minspills |
运行combiner所需要的最少溢出文件数 |
mapreduce.map.output.compress |
是否压缩map输出 |
mapreduce.map.output.compress.codec |
用于map输出的压缩编解码器 |
mapreduce.shuffle.max.threads |
每个节点管理器的工作线程数 |
Reduce端调优
mapreduce.reduce.shuffle.parallelcopies |
用于把map输出复制到reducer的线程mapreduce.reduce.shuffle.maxfetchfailures 在声明失败前,reducer获取一个map输出所花的最大时间 |
mapreudce.task.io.sort.factor |
排序文件时一次最多合并的流的数量 |
mapreudce.reduce.shuffle.input.buffer.percent |
在shuffle的复制阶段,分配给map输出的缓冲区占堆空间的百分比 |
mapreduce.reduce.shuffle.merge.percent |
map输出缓冲区的阈值使用比例 |
mapreduce.reduce.merge.in.mem.threshold |
启动合并输出和磁盘溢出写过程的map输出的阈值数 |
mapreduce.reduce.input.buffer.percent |
在reduce过程中,在内存中保存map输出的空间占整个空间的比例 |
map端可以通过避免多次溢出写磁盘来获得最佳性能
reduce端,中间数据全部驻留在内存时,就能获得最佳性能
推测执行:在一个任务运行比预期慢的时候,它会尽量检测,并启动另一个相同的任务作为备份。仅仅只针对运行速度低于平均水平的那一部分。一个任务成功完成后,其他的重复任务都将结束。
mapreudce.map.speculative
mapreduce.reduce.speculative
推测执行的优缺点:推测执行的目的是减少作业执行时间,但是以牺牲集群效率为代价的,推测执行会减少整体的吞吐量。
第8章 MapReduce的类型与格式
设置中间类型的原因:Java的泛型机制有很多限制:类型擦除导致运行过程中类型信息并非一直可见,所以Hadoop不得不进行明确规定。
分区操作:默认的partitioner是HashPartitioner,对每条记录的键值进行哈希操作以决定该记录应该属于哪个分区。每个分区由一个reduce任务处理,所以分区数等于作业的reudce数。
记录属于哪个分区的确定:键的哈希值与最大值按位与,并用分区数进行取摸操作
getSplits()计算分片,然后发送到application master,application masster使用其存储位置信息来调度map任务。
map任务调用一个RecordReader来生成键-值对,然后传递给map函数
FileInputFormat类
- 用于指出文件位置
- 为输入文件生成分片的代码实现
- 输入路径:addInputPath、addInputPaths、setInputPaths
如果需要排除特定文件,可以使用FileInputFormat的setInputPathFilter()方法设置过滤器
FileInputFormat默认会使用过滤器排除隐藏文件(“.”,"_"开头)
- 输出分片:FileInputFormat只分割大文件(超过HDFS块的大小)
小文件和CombineFileInputFormat类
小文件的危害:(1)处理小文件将增加运行作业必需的寻址次数 (2)HDFS集群中存储大量的小文件会浪费namenode的内存
CombineFileInputFormat将多个文件打包到一个分片中,以便每个mapper可以处理更多的数据。使得map操作中处理的数据量与HDFS中文件的块大小之间的耦合度降低。
保证文件不被切分的方法:
(1)增加最小分片的大小,将它设置成大于要处理的最大文件大小。
(2)使用FileInputFormat具体子类,并且重写isSplitable()方法,把返回值设置为false
mapper中的信息:
调用Mapper的Context对象上的getInputSplit()方法,当输入源自FileInputFormat时,该方法返回的InputSplit可以被强制转换为一个FileSplit
文本输入 / 输出:
- TextInputFormat 、TextOutputFormat:键是字节偏移量、值是这行的内容
跨行问题:TextInputFormat的逻辑记录是以行为单位的,有可能某一行会跨文件块存放
这意味着map会执行一些远程的读操作
超长行会表现为一个超长行,会导致内存溢出的错误。通常将mapreduce.input.linerecordreader.line.maxlength设置为用字节数表示的,在内存范围内的值
- KeyValueTextInputFormat:使用分界符对行进行分割,键为排在制表符之前的Text序列
例: line1 -> abc
line2 -> bcd
(line1,abc) (line2,bcd)
- NLineInputFormat:
以上两种mapper输入行数不同,如果希望mapper收到固定的行数的输入,需要将NLineInputFormat作为InputFormat使用,键是行字节偏移量,值是行本身。
N是mapper收到的输入行数,由mapreduce.input.lineinputformat.linespermap属性控制
- StreamXmlRecordReader:
用来处理XML文档
把stream.recordreader.class属性设置为org.apache.hadoop.streaming.mapreduce.StreamXmlRecordReader
- SequenceFileInputFormat 、SequenceFileOutputFormat:处理二进制输入
- SequenceFileAsTextInputFormat、SequenceFileAsBinaryOutputFormat
- SequenceFileAsBinaryInputFormat
- FixedLengthInputFormat:用于从文件中读取固定宽度的二进制记录
- 多个输入:MultipleInputs MultipleInputs.addInputPath(......)
- 数据库输入、输出:使用JDBC从关系型数据库中读取数据
- MapFileOutputFormat:把map文件作为输出
- 多输出:MultipleOutputFormat:
将数据写入到多个文件,允许每个reducer创建多个文件。
map命名格式:name-m-nnnnn (nnnnn:块号)
reduce命名格式:name-r-nnnnn
public class PartitionByStationUsingMultipleOutputs extends Configured implements Tool{
static class StationMapper extends Mapper<LongWritable,Text,Text,Text>{
private NcdcRecordParser parser = new NcdcRecordParser();
@Override
protected void map(LongWritable key,Text value,Context context) throws IOException,InterruptedException{
parser.parse(value);
context.write(new Text(parser.getStationId()),value);
}
}
static class MultipleOutputsReducer extends Reducer<Text,Text,NullWritable,Text>{
private MultipleOutputs<NullWritable,Text> multipleOutputs;
@Override
protected void setup(Context context) throws IOException,InterruptedException{
multipleOutputs = new MultipleOutputs<NullWritable,Text>(context);
}
@Override
public void reduce(Text key,Iterable<Text> values,Context context) throws IOException,InterruptedException{
for(Text value:values){
multipleOutputs.write(NullWritable.get(),value,key.toString());
}
}
@Override
protected void cleanup(Context context) throws IOException,InterruptedException{
mutipleOutputs.close();
}
}
@Override
public int run(String[] args) throws Exception{
Job job = JobBuilder.parseInputAndOutput(this,getConf(),args);
if(job == null){
return -1;
}
job.setMapperClass(StationMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setReducerClass(MultipleOutputsReducer.class);
job.setOutputKeyClass(NullWritable.class);
return job.waitForCompetion(true)?0:1;
}
}
第9章 MapReduce特性
- 计数器
- 数据集
- 排序和连接
计数器:收集作业统计信息的有效手段之一
Hadoop内置计数器:
- MapReduce任务计数器(TaskCounter)
- 文件系统计数器(FileSystemCounter)
- FileInputFormat计数器(FileInputFormatCounter)
- FileOutputFormat计数器(FileOutputFormatCounter)
- 作业计数器(JobCounter)
p245 - 247:任务计数器、作业计数器
public class MaxTemperatureWithCounters extends Configured implements Tool{
enum Temperature{
MISSING,
MALFORMED
}
static class MaxTemperatureMapperWithCounters extends Mapper<LongWritable,Text,Text,IntWritable>{
private NcdcRecordParser parser = new NcdcRecordParser();
@Override
protected void map(LongWritable key,Text value,Context context) throws IOException,InterruptedException{
parser.parse(value);
if(parser.isValidTemperature()){
int airTemperature = parser.getAirTemperature();
context.write(new Text(parser.getYear()),new IntWritable(airTemperature));
}else if(parser.isMalformedTemperature()){
System.err.println("...")
context.getCounter(Temperature.MALFORMED).increment(1);
}else if(parser.isMissingTemperature()){
context.getCounter(Temperature.MISSING).increment(1);
}
//动态counter,不由枚举定义的计数器
context.getCounter("TemperatureQuality",parser.getQuality()).increment(1);
}
}
}
//counters的获取
Counters counters = job.getCounters();
counters.findCounter(MaxTemperatureWithCounters.Temperature.MISSING).getValue();
Hadoop内置采样器
- InputSampler
InputSampler.Sampler<IntWritable,Text> sampler
= new InputSampler.RandomSampler<IntWritable,Text>(0.1,1000,10)
- IntervalSample 以一定间隔定期从分片中选择键
- RandomSampler
分布式缓存
及时将任务过程中的文件和存档复制到任务节点以供使用,各个文件通常只需要复制到一个节点一次,将文件“本地化”。
当缓存容量超过一定范围,根据最近最少使用的原则删除文件以腾出空间。
-archives 向任务中复制存档文件(jar)
-libjars 把jar文件添加到mapper和reducer任务的类路径中
-files 分发文件
缓存API:
两类对象:Files(Path)、Achives(URI)
- addCacheXXXX()
- setCacheXXXXs():一次性添加一组文件、存档
- addXXXXToClassPath():将文件或存档添加到MapReduce任务的类路径
第10章 构建Hadoop集群
Apache Ambari
一个集群保存两年的数据大致需要100台机器
格式化HDFS:创建一个空的文件系统,创建初始版本的namenode(不涉及datanode)
hdfs namenode -format
start-dfs.sh的过程
- 在每台机器上启动一个namenode,这些机器由执行hdfs getconf -namenodes得到的返回值确定
- 在slaves文件列举的每台机器上启动一个datanode
- 在每台机器上启动一个辅助namenode,这些机器由执行hdfs get conf -secondarynamenodes 得到的返回值所确定
start-yarn.sh的过程
- 在本地机器上启动一个资源管理器(ResourceManager)
- 在slaves文件列举的每台机器上启动一个节点管理器(NodeManager)
namenode目录:dfs.namenode.name.dir
datanode目录:dfs.datanode.data.dir
dfs检查点:dfs.namenode.checkpoint.dir 指定一系列目录来保存检查点
缓冲区大小:io.file.buffer.size
块大小:dfs.blocksize
datanode能够使用存储目录上的所有闲置空间:dfs.datanode.du.reserved
回收站回收的时间:fs.trash.interval
HDFS会自动删除回收站中的文件,但其他文件系统并不具备这项功能
执行以下命令可以删除已在回收站中超过最小时限的所有文件:
hadoop fs -expunge
慢启动Reduce:百分之多少的map完成才开始reduce
mapreduce.job.reduce.slowstart.completedmaps
短回路本地读:dfs.client.read.shortcircuit = true
客户端联系datanode,然后通过tcp连接发送给客户端
如果正在读取的数据块和客户端在同一个节点上,那么客户端绕过网络从磁盘上直接读取数据效率会更高
安全性:
Hadoop文件许可模块只提供一种简单的认证机制来决定各个用户对特定文件的访问权限
Kerberos:实现用户认证,鉴定登录帐号是否就是所声称的用户
Hadoop:决定该用户到底拥有多少权限
Kerberos:
- 认证:客户端向认证服务端发送一条报文,并获取一个含时间戳的票据授予票据(TGT)
TGT具有一定的有效期(10个小时)
- 授权:客户端使用TGT向票据授予服务器,并请求一个服务票据(TGS)
- 服务请求:客户端向服务器出示服务票据(TGS),以证实自己的合法性
认证服务器(TGT) + 票据服务器(TGS) = KDC (kerberos key distribution center)
通用的做法是自动认证:在登录操作系统的时候自动执行认证操作,从而只需单次登录到Hadoop
ktutil命令创建一个Kerberos的keytab文件
- 将coresite.xml文件中的hadoop.security.authentication 属性设置为true
- 启动服务级别的授权,将同一文件中的hadoop.security.authorization属性设置为true
klist:命令查看票据的过期时间
kdestroy:指定可消毁票据
委托令牌:Hadoop使用委托令牌支持后续的认证访问,避免多次访问KDC,委托令牌的创建和使用过程均由Hadoop代表用户透明地进行,因而用户执行kinit命令登录之后,无需再做额外的操作。
委托令牌由服务器创建(namenode),可以视为客户端和服务器之间共享的一个密文
默认hdfs实例会自动获取委托令牌,但是如果访问其他·hdfs集群,mapreduce.job.hdfs-servers作业属性设置为一个逗号隔离开的HDFS URI列表,才能够获取相应的委托令牌。
Hadoop基准评测程序:
hadoop-mapreduce-client-jobclient-xx-tests.jar
hadoop-mapreudce-*-tests.jar
TeraSort:对输入进行全排序
- 使用teragen生成随机数据
hadoop jar $HADOOP_HOME/share/hadoop /mapreduce/hadoop-mapreduce-examples-*.jar
teragen -Dmapreduce.job.maps=1000 10t random-data
- 运行TeraSort
hadoop jar $HADOOP_HOME/share/hadoopmapreduce/hadoop-mapreudce-exmaples-*.jar terasort random-data sorted-data
- 验证sorted-data文件中的数据是否已经排好序
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar teravalidate sorted-data report
- TestDFSIO : 测试I/O性能
- MRBench:多次运行小型作业,检验小型作业能否快速响应
- NNBench:测试namenode硬件的加载过程
- Gridmix:基准评测程序套装
- SWIM:真实的MapReduce工作负载库,用来测试负载
- TPCx-HS:基本TeraSort的标准基准测评程序
第11章 管理Hadoop
namenode目录结构:
${dfs.namenode.name.dir} / dfs.namenode.name.dir描述了一组目录,各个目录存储着镜像内容
|---------- current
| |----------VERSION //Java属性文件,包含着正在运行的HDFS的版本信息
| |----------edits_000001-0000019
| |----------edits_inprogress_000000070
| |----------fsimage_000000 //fsimage文件都是文件系统元数据的一个完整永久性检查点
//如果namenode发生故障,最近的fsimage文件将被载入到内存以重构元数据的最近状态
| |----------fsimage_000000.md5
| |----------fsimage_0000019
| |----------fsimage_0000019.md5
| |----------seen_txid
|------------ in_use.lock //文件锁文件,namenode使用该文件对目录进行加锁
VERSION:
namespaceID :文件系统命名空间唯一标示符,在namenode首次格式化创建
clusterID:集群整体赋予的标示符
cTime:namenode存储系统创建时间
storageType:存储目录包含的namenode的数据结构
blockpoolID:数据池唯一标示符
layoutVersion:hdfs持久性数据结构的版本(与Hadoop版本无关)
- 编辑日志在概念上是单个实体,在磁盘上体现为多个文件。每个文件称为一个“段”,后缀edits及后缀组成,后缀是该文件包含的事务ID
- 任一时刻只有一个文件处于打开可写状态,在每个事务完成之后,且在向客户端发送成功代码之前,文件都需要更新和同步
- 当namenode向多个目录写数据时,只有在所有写操作更新并同步到每个复本之后可返回成功代码
主namenode,辅namenode(一般运行在另一个机器上)
- 辅助namenode请求主namenode停止使用正在进行中的edits文件,这样新编辑记录到一个新文件中。主namenode还会更新所有存储目录中的seen txid文件
- 辅助namenode从主namenode获取最近的fsimage和edits文件
- 辅助namenode将fsimage文件载入内存,逐一执行edits文件中的事务,创建新的合并后的fsimage文件
- 辅助namenode将新的fsimage文件发送回主namenode,主namenode将其保存为临时的.ckpt文件
- 主namenode重新命名临时的fsimage文件,便日后使用
安全模式创建检查点:hdfs dfsadmin -saveNamespace
查看namenode是否处于安全模式:hdfs dfsadmin -safemode get
namenode进入安全模式:hdfs dfsadmin -safemode enter
退出安全模式:hdfs dfsadmin -safemode leave
执行某些命令前namenode退出安全模式:hdfs dfsadmin -safemode wait
创建检查点的条件:
(1)dfs.namenode.checkpoint.period 检查周期
(2)dfs.namenode.checkpoint.txns 事务文件的大小
辅助namenode发生故障时,辅助namenode恢复数据的方法:
(1)将相关存储目录复制到新的namenode
(2)使用-importCheckpoint选项启动namenode守护进程,从而将辅助namenode用作新的主namenode
namenode启动时,首先将文件(fsimage)载入内存中,并执行编辑日志(edits)中的各项编辑操作。一旦在内存中成功建立文件系统元数据的映象,则创建一个新的fsimage文件和一个空的编辑日志。
datanode目录结构:
${dfs.datanode.data.dir}/
|- current
| |------BP-xxx-127.0.0.1-xxx
| | |---current
| | |---VERSION
| | |---finalized
| | | |---blk_xxxxx
//hdfs数据块在以blk_为前缀名的文件中,文件名包含了该文件存储的块原始字节数
| | | |---blk_xxxxx.meta //版本和类型信息、校验和
| | | |---blk_yyyyy
| | | |---blk_yyyyy.meta
| | |---row
| |---VERSION
|-----in_use.lock
dfsadmin 工具:查看HDFS状态信息,又可在HDFS上执行管理操作
fsck:检查监控状况,缺失或过多的块
fsck只是从namenode获取信息,并不与任何datanode进行交互,并不真正获取块数据
hdfs 查找文件的数据块:hdfs fsck /user/tom/xxxx -files -blocks -racks
datanode块扫描器
扫描并检测块(dfs.datanode.scan.period.hours )
均衡器
start-balancer.sh
将块从忙碌的datanode移动到相对空闲的datanode,从而重新分配块
均衡器会一直运行,知道集群变得均衡为止
度量(Metrics)和JMX
度量:度量为管理员服务
计数器:主要为MapReduce用户服务
计数器:MapReduce确保计数器值由任务JVM产生,再传回application master,最终传回MapReduce作业的客户端
度量:收集机制独立于接收更新的组件
委任:扩大和缩小存储容量
向集群添加新节点的步骤如下:
1. 将新节点的网络地址添加都include文件中
2. 运行以下指令,将审核过的一系列datanode集合更新至namenode信息:
hdfs dfsadmin -refreshNodes
3. 将审核过的一系列节点管理器信息更新到资源管理器:
yarn rmadmin -refreshNodes
4. 在以新节点更新slaves文件
5. 启动新的datanode和节点管理器
向集群解除旧节点的步骤如下:
用户将拟退出的若干datanode告知namenode,Hadoop系统就可在这些datanode停机之前将块复制到其他datanode
节点是否出现在include文件中 |
节点是否出现在exclude文件中 |
解释 |
否 |
否 |
节点无法连接 |
否 |
是 |
节点无法连接 |
是 |
否 |
节点可连接 |
是 |
是 |
节点可连接,将被删除 |
1. 将待解除节点的网络地址添加到exclude文件中,不更新include文件
2. 使用一组新的审核过的datanode来更新namenode设置:
hdfs dfsadmin -refreshNodes
3. 使用新的审核过的节点管理器来更新资源管理器设置:
yarn rmadmin -refreshNodes
4. 从include文件中移除这些节点,并运行以下命令:
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes
5. 从slaves文件中移除节点
Hadoop升级过程:
- 在执行升级任务之前,确保前一升级已经定妥
- 关闭yarn和mapreduce守护进程
- 关闭hdfs,并备份namenode目录
- 在集群和客户端安装新版本的hadoop
- 使用 -upgrade选项启动hdfs
- 等待,直到升级完成
- 检查hdfs是否运行正常
- 启动yarn和mapreudce守护进程
- 回滚或定妥升级任务
启动升级:start-dfs.sh -upgrade
等待、直到升级完成:hdfs dfsadmin -upgradeProgress status
回滚:stop-dfs.sh start-dfs.sh -rollback