第1章 HDFS概论
1.1 HDFS产生背景及定义
1.1.1 HDFS产生背景
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系 统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理堕胎机器上的文件, 这就是分布式文件管理系统;HDFS只是分布式文件管理系统中的一种
1.1.2 HDFS定义
HDFS(Hadoop Distributed File System)它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器 有各自的角色
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用
1.2 HDFS优缺点
1.2.1 优点(高容错性/高可用/高扩展)
A. 高容错性
· 数据自动保存多个副本;它通过增加副本的形式,提高容错性
· 某一个副本丢失以后,它可以自动恢复
B. 适合处理大数据
· 数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据
· 文件规模:能够处理百万规模以上的文件数量,数量相当之大
C. 可构建在廉价的机器上,通过多副本机制,提高可靠性
1.2.2 缺点
A. 不适合低延时数据访问,比如毫秒的存储数据,是做不到的
B. 无法高效的对大量小文件进行存储
· 存储大量小文件的话,会占用NameNode大量的内存来存储文件目录和块信息;这样是不可取的,因为NameNode的内存总是有限的
· 小文件存储的寻址时间会超过读取时间,违反了HDFS的设计目标
C. 不支持并发写入、文件随机修改
· 同一时间一个文件只能有一个用户执行写操作,不允许多个线程同时写
· 仅支持数据append(追加),不支持文件的随机修改
1.3 HDFS组成架构
A. NameNode(nn):就是Master,它是一个主管、管理者
· 管理HDFS的名称空间
· 配置副本策略
· 管理数据块(Block)映射信息
· 处理客户端读写请求
B. DataNode:就是Slave,NameNode下达命令,DataNode执行实际的操作
C. Client:就是客户端
· 文件切分;文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传
· 与NameNode交互,读取文件的位置信息
· 与DataNode交互,读取或者写入数据
· Client提供一些命令来管理HDFS,比如NameNode格式化
· Client可以通过一些命令来访问HDFS,比如对HDFS增删改查操作
D. SecondaryNameNode:并非NameNode的热备;当NameNode挂掉的时候,它并不 能马上替换NameNode并提供服务
· 辅助NameNode,分担工作量,如定期合并simage和Edits,并推送给NameNode
· 在紧急情况下,可辅助恢复NameNode
1.4 HDFS文件块大小
HDFS中的文件在物理上是分块存储(Block), 块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在Hadoop2.x版本中是128M,老版本中是64M
- 为什么块的大小不能设置太小,也不能设置太大?
HDFS的块设置太小,会增加寻址时间,程序一直在找块的开始位置;
如果块设置的太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时 间;导致程序在处理这块数据时,会非常慢
- 总结:HDFS块的大小设置主要取决于磁盘传输速率
第2章 HDFS的Shell操作
A.基础语法
bin/hadoop fs 具体命令 or bin/hdfs dfs 具体命令
dfs是fs的实现类
B.常用命令操作(一定要注意hadoop下的hdfs-site.xml中配置的节点数一定要和启动的 datanode节点数一致,只能大不能小)
· 启动hadoop集群:start-dfs.sh start-yarn.sh
· 输出命令参数:-help rm
本地文件 -> HDFS
-put 将本地数据上传至hdfs
-copyFromLocal 将本地文件数据拷贝到hdfs
-moveFromLocal 将本地文件数据移动到hdfs,成功后本地数据会删除
-appendToFile 追加一个文件到已经存在的文件末尾
HDFS与HDFS之间
-ls 查看hdfs文件目录
-mkdir 在HDFS上创建目录
-rm 删除文件或者文件夹
-rmr 递归删除
-cp 从一个目录拷贝文件至另一目录
-mv 在HDFS目录中移动文件
-chown 修改文件所属用户权限
-chmod 修改文件所属读写权限
-du -h 文件夹暂用的空间大小
-df -h 查看系统分区情况
-cat 查看文件
-tail:显示一个文件的末尾
-setrep:设置hdfs中文件的副本数量
HFDS -> 本地
-get 从hdfs下载文件至本地
-getmerge 合并hdfs目录下的文件至本地
-copyToLocal 从hdfs拷贝文件至本地
第3章 HDFS客户端操作
3.1 HDFS客户端环境准备
3.1.1 根据自己电脑的操作系统拷贝对应的编译后的hadoop jar包到非中文路径
3.1.2 配置HADOOP_HOME环境变量
3.1.3 配置path环境变量
3.1.4 创建一个Maven工程HdfsClient
3.1.5 导入相应的依赖坐标+日志添加
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
</dependencies>
如果Eclipse/Idea打印不出日志,在控制tai上只显示
1.log4j:WARN No appenders could be found for logger (org.apache.hadoop.util.Shell).
2.log4j:WARN Please initialize the log4j system properly.
3.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
3.1.6 创建包名:com.jinghang.hdfsclient
3.1.7 创建HdfsClient类
public class HdfsClient {
private Configuration configuration;
private FileSystem fileSystem;
@Before
public void init() throws IOException, InterruptedException {
System.out.println("----执行开始----");
this.configuration = new Configuration();
this.fileSystem = FileSystem.get(
// URI:统一资源标识符(包含URL、URN)
// URL:统一资源定位符
// URN:统一资源名称
URI.create("hdfs://hadoop01:9000") ,
configuration ,
"jinghang"
); // alt+enter
}
@After
public void after() throws IOException {
fileSystem.close();
System.out.println("----执行完毕----");
}
}
3.2 HDFS的API操作
参数优先级排序(从高到低):
· 客户端代码中设置的值
· classpath下的用户自定义配置文件
· 服务器的默认设置
3.2.1 HDFS文件上传
@Test
public void put() throws IOException, InterruptedException {
// 本地文件路径D:\jinghang\Java\java\jh_java_01
Path localPath = new Path("D:\\jinghang\\Java\\java\\jh_java_01");
// hdfs文件路径
Path hdfsPath = new Path("/code01/");
// 将本地文件上传至hdfs通过copyFromFile方法
fileSystem.copyFromLocalFile(localPath, hdfsPath);
// 关闭文件系统
fileSystem.close();
}
3.2.2 HDFS文件下载
@Test
public void get() throws IOException {
// hdfs文件路径
Path hdfsPath = new Path("/code1/hdfs.txt");
// 本地文件路径
Path localPath = new Path("D:\\jinghang\\Java\\idea\\aa");
// 使用copyLocalFile将hdfs文件下载到本地
fileSystem.copyFromLocalFile(hdfsPath, localPath);
}
3.2.3 HDFS文件夹删除
@Test
public void delete() throws IOException {
// 指定需要删除的文件的路径
Path hdfsPath = new Path("/code01");
boolean b = fileSystem.delete(hdfsPath, true);
if (b) {
System.out.println("文件删除成功");
} else {
System.out.println("文件删除失败");
}
}
3.2.4 HDFS文件名更改
@Test
public void rename() throws IOException {
// 获取需要重命名的文件的路径
Path hdfsPath = new Path("/code01");
// 重命名的名称
Path newPath = new Path("/code1");
boolean b = fileSystem.rename(hdfsPath, newPath);
if (b) {
System.out.println("文件名修改成功");
} else {
System.out.println("文件名修改失败");
}
}
3.2.5 HDFS文件追加
@Test
public void append() throws IOException {
// 要追加的文件路径(hdfs)
Path hdfsPath = new Path("/code1/.classpath");
// 本地文件的路径
String localPath = "D:\\jinghang\\Java\\java\\jh_java_01\\.project";
// hdfs的文件输出流
FSDataOutputStream append = fileSystem.append(hdfsPath, 1024);
// 本地文件的输入流
FileInputStream inputStream = new FileInputStream(localPath);
IOUtils.copyBytes(inputStream, append, 1024, true);
// 手动关闭输入流和输出流
inputStream.close();
append.close();
}
3.2.6 HDFS文件和文件夹判断
@Test
public void readFileAndDir() throws IOException {
// listStatus:读取文件和文件夹
Path hdfsPath = new Path("/code1/src/");
FileStatus[] fileStatuses = fileSystem.listStatus(hdfsPath);
for (FileStatus fileStatus : fileStatuses) {
if (fileStatus.isDirectory()) {
System.out.println("是一个文件夹");
System.out.println(fileStatus.getPath()); // 路径
System.out.println(fileStatus.getLen()); // 文件长度
System.out.println(fileStatus.getPermission()); // 文件的权限
System.out.println(fileStatus.getOwner()); // 文件夹的所有者
System.out.println(fileStatus.getGroup()); // 文件夹的所属组
} else {
System.out.println("是一个文件");
System.out.println(fileStatus.getPath()); // 路径
System.out.println(fileStatus.getLen()); // 文件长度
System.out.println(fileStatus.getReplication()); // 副本数
System.out.println(fileStatus.getBlockSize()); // 块大小
}
}
}
3.3 HDFS的I/O流操作
3.3.1 HDFS文件上传
@Test
public void cusPut() throws IOException {
// 获取去本地文件作为输入流
String localPath = "D:\\jinghang\\IDEA2019.1\\Install-Windows-zip.txt";
FileInputStream inputStream = new FileInputStream(localPath);
// 获取hdfs的输出流
Path hdfsPath = new Path("/code2");
FSDataOutputStream outputStream = fileSystem.create(hdfsPath);
IOUtils.copyBytes(inputStream, outputStream, configuration, true);
// 手动关闭
outputStream.close();
inputStream.close();
}
3.3.2 HDFS文件下载
@Test
public void cusGet() throws IOException {
//hdfs文件作为输入流
Path hdfsPath = new Path("/code2");
FSDataInputStream open = fileSystem.open(hdfsPath);
//添加本地的输出流(指定下载后的文件的文件名)
String localPath = "D:\\jinghang\\Java\\idea\\aa\\a.txt";
FileOutputStream outputStream = new FileOutputStream(localPath);
IOUtils.copyBytes(open, outputStream, configuration, true);
}
第4章 HDFS的数据流
4.1 HDFS写数据流程
4.1.1 刨析文件写入
A.客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在
B.NameNode返回是否可以上传
C.客户端请求第一个 Block上传到哪几个DataNode服务器上
D.NameNode返回3个DataNode节点,分别为dn1、dn2、dn3
E.客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成
F.dn1、dn2、dn3逐级应答客户端
G.客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答
H.当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)
4.1.2 网络拓扑-节点距离计算
在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接 收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和
4.1.3 机架感知(副本存储节点选择)
A.官方ip地址
B.Hadoop2.7.2副本节点选择
· 第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个
· 第二个副本和第一个副本位于相同机架,随机节点
· 第三个副本位于不同机架,随机节点
C. 副本节点选择的作用
减少网络的IO传输,提高安全性
4.2 HDFS读数据流程
A.客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址
B.挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据
C.DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)
D.客户端以Packet为单位接收,先在本地缓存,然后写入目标文件
第5章 NameNode和SecondaryNameNode
5.1 NN和2NN工作机制
A.第一阶段:NameNode启动
·第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存
·客户端对元数据进行增删改的请求
·NameNode记录操作日志,更新滚动日志
·NameNode在内存中对元数据进行增删改
B.第二阶段:SecondaryNameNode工作
·Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果
·Secondary NameNode请求执行CheckPoint
·NameNode滚动正在写的Edits日志
·将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
·Secondary NameNode加载编辑日志和镜像文件到内存,并合并
·生成新的镜像文件fsimage.chkpoint
·拷贝fsimage.chkpoint到NameNode
·NameNode将fsimage.chkpoint重新命名成fsimage
5.2 Fsimage和Edits解析
· Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件 系统的所有目录和文件inode的序列化信息
· Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有 写操作首先会被记录到Edits文件中
· seen_txid文件保存的是一个数字,就是最后一个edits_的数字
· 每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操 作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就 将Fsimage和Edits文件进行了合并
5.3 CheckPoint时间设置
A.通常情况下,SecondaryNameNode每隔一个小时执行一次
hdfs-default.xml
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
B.一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>操作动作次数</description>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description> 1分钟检查一次操作次数</description>
</property >
5.4 NameNode故障处理
NameNode故障后,可以采用如下两种方法恢复数据
A.将SecondaryNameNode中数据拷贝到NameNode存储数据的目录
· kill -9 NameNode进程
· 删除NameNode存储的数据:rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*
· 拷贝SecondaryNameNode中数据到原NameNode存储数据目录
· 重新启动NameNode
B.使用-importCheckpoint选项启动NameNode守护进程,从而将SecondaryNameNode中数据拷贝到NameNode目录中
· 修改hdfs-site.xml中的
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>120</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/module/hadoop-2.7.2/data/tmp/dfs/name</value>
</property>
· kill -9 NameNode进程
· 删除NameNode存储的数据:rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*
· 如果SecondaryNameNode和NameNode不在一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到NameNode存储数据的平级目录,并删除in_use.lock文件
· 导入检查点数据(等待一会ctrl+c结束掉):bin/hdfs namenode -importCheckpoint
· 启动NameNode
5.5 集群安全模式
5.5.1 概述
A.NameNode启动
NameNode启动时,首先将镜像文件(Fsimage)载入内存,并执行编辑日志(Edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的Fsimage文件和一个空的编辑日志。此时,NameNode开始监听DataNode请求。这个过程期间,NameNode一直运行在安全模式,即NameNode的文件系统对于客户端来说是只读的
B.DataNode启动
系统中的数据块的位置并不是由NameNode维护的,而是以块列表的形式存储在DataNode中。在系统的正常操作期间,NameNode会在内存中保留所有块位置的映射信息。在安全模式下,各个DataNode会向NameNode发送最新的块列表信息,NameNode了解到足够多的块位置信息之后,即可高效运行文件系统
C.安全模式推出判断
如果满足“最小副本条件”,NameNode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有 任何块,所以NameNode不会进入安全模式
5.5.2 基本语法
· 查看安全模式状态:bin/hdfs dfsadmin -safemode get
· 进入安全模式状态:bin/hdfs dfsadmin -safemode enter
· 离开安全模式状态:bin/hdfs dfsadmin -safemode leave
· 等待安全模式状态:bin/hdfs dfsadmin -safemode wait
第6章 DataNode
6.1 DataNode工作机制
· 一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳
· DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息
· 心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用
· 集群运行中可以安全加入和退出一些机器
6.2 掉线时限参数设置
A.DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信
B.NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长
C.HDFS默认的超时时长为10分钟+30秒
D.如果定义超时时间为TimeOut,则超时时长的计算公式为:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval
默认dfs.namenode.heartbeat.recheck-interval 大小为5分钟
默认dfs.heartbeat.interval大小为3秒
E.hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒
<property>
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value>
</property>
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value>
</property>
6.3 服役新数据阶段
A.在hadoop01主机上再克隆一台hadoop04主机
B.修改IP地址和主机名称
C.删除原来HDFS文件系统留存的文件(data和logs)
D.source一下配置文件
E.直接启动DataNode,即可关联到集群
F.在hadoop04上上传文件
G.如果数据不均衡,可以用命令实现集群的再平衡
6.4 退役旧数据节点
6.4.1 添加白名单
添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,会被退出
A.在NameNode的/opt/module/hadoop-2.7.2/etc/hadoop目录下创建dfs.hosts文件
添加主机名称(不添加hadoop04)
hadoop01
hadoop02
hadoop03
B.在NameNode的hdfs-site.xml配置文件中增加dfs.hosts属性
<property>
<name>dfs.hosts</name>
<value>/opt/module/hadoop-2.7.2/etc/hadoop/dfs.hosts</value>
</property>
C.配置文件分发:myrsync hdfs-site.xml
D.刷新NameNode:hdfs dfsadmin -refreshNodes
E.更新ResourceManager节点:yarn rmadmin -refreshNodes
F.在web浏览器上查看
G.如果数据不均衡,可以用命令实现集群的再平衡
6.4.2 黑名单退役
在黑名单上面的主机都会被强制退出
A.在NameNode的/opt/module/hadoop-2.7.2/etc/hadoop目录下创建dfs.hosts.exclude文件
添加主机名称(要退役的节点)
hadoop04
B.在NameNode的hdfs-site.xml配置文件中增加dfs.hosts.exclude属性
<property>
<name>dfs.hosts.exclude</name>
<value>/opt/module/hadoop-2.7.2/etc/hadoop/dfs.hosts.exclude</value>
</property>
C.刷新NameNode、刷新ResourceManager:hdfs dfsadmin -refreshNodes yarn rmadmin -refreshNodes
D.检查Web浏览器,退役节点的状态为decommission in progress(退役中),说明数据节点正在复制块到其他节点
E.等待退役节点状态为decommissioned(所有块已经复制完成),停止该节点及节点资源管理器。
注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役
F.如果数据不均衡,可以用命令实现集群的再平衡
注意:不允许白名单和黑名单中同时出现一个主机名称
6.5 DataNode多目录配置
A.DataNode也可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本
B.配置hdfs-site.xml
<property>
<name>dfs.datanode.data.dir</name>
<value>file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2</value>
</property>
第7章 HDFS 2.X新特性
7.1 集群间数据拷贝
scp实现两个远程主机之间的文件复制
采用distcp命令实现两个Hadoop集群之间的递归数据复制
7.2 小文件存档
- HDFS存储小文件弊端
大量的小文件会耗尽NameNode的大部分内存,因此HDFS存储小文件会非常低效; 但存储小文件所需要的磁盘容量和数据块的大小无关
- 解决存储小文件办法之一
HDFS存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少NameNode内存使用的同时,允许对文件进行透明的访问;具体说来,HDFS存档文件对内还是一个一个独立文件,对NameNode而言却是一个整体,减少了NameNode的内存
第8章 HDFS HA高可用
8.1 HA概述
A. 所谓HA(High Available),即高可用(7*24小时不中断服务)
B. 实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制:HDFS的HA和YARN的HA
C. Hadoop2.0之前,在HDFS集群中NameNode存在单点故障(SPOF)
D. NameNode主要在以下两个方面影响HDFS集群
·NameNode机器发生意外,如宕机,集群将无法使用,直到管理员重启
·NameNode机器需要升级,包括软件、硬件升级,此时集群也将无法使用
·HDFS HA功能通过配置Active/Standby两个NameNodes实现在集群中对NameNode的热备来解决上述问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种方式将NameNode很快的切换到另外一台机器
8.2 HDFS-HA工作机制
通过双NameNode消除单点故障
8.2.1 HDFS-HA工作要点
A. 元数据管理方式需要改变
·内存中各自保存一份元数据
·Edits日志只有Active状态的NameNode节点可以做写操作
·两个NameNode都可以读取Edits
·共享的Edits放在一个共享存储中管理(qjournal和NFS两个主流实现)
B. 需要一个状态管理功能模块
实现了一个zkfailover,常驻在每一个namenode所在的节点,每一个zkfailover负责监控自己所在NameNode节点,利用zk进行状态标识,当需要进行状态切换时,由zkfailover来负责切换,切换时需要防止brain split现象的发生
C. 必须保证两个NameNode之间能够ssh无密码登录
D. 隔离(Fence),即同一时刻仅仅有一个NameNode对外提供服务
8.2.2 HDFS-HA自动故障转移工作机制
自动故障转移为HDFS部署增加了两个新组件:ZooKeeper和ZKFailoverController(ZKFC)进程,如图3-20所示。ZooKeeper是维护少量协调数据,通知客户端这些数据的改变和监视客户端故障的高可用服务。HA的自动故障转移依赖于ZooKeeper的以下功能:
A. 故障检测:集群中的每个NameNode在ZooKeeper中维护了一个持久会话,如果机器崩溃,ZooKeeper中的会话将终止,ZooKeeper通知另一个NameNode需要触发故障转移
B. 现役NameNode选择:ZooKeeper提供了一个简单的机制用于唯一的选择一个节点为active状态。如果目前现役NameNode崩溃,另一个节点可能从ZooKeeper获得特殊的排外锁以表明它应该成为现役NameNode
ZKFC是自动故障转移中的另一个新组件,是ZooKeeper的客户端,也监视和管理NameNode的状态。每个运行NameNode的主机也运行了一个ZKFC进程,ZKFC负责:
A. 健康监测:ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode,只要该NameNode及时地回复健康状态,ZKFC认为该节点是健康的。如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非健康的
B. ZooKeeper会话管理:当本地NameNode是健康的,ZKFC保持一个在ZooKeeper中打开的会话。如果本地NameNode处于active状态,ZKFC也保持一个特殊的znode锁,该锁使用了ZooKeeper对短暂节点的支持,如果会话终止,锁节点将自动删除
C. 基于ZooKeeper的选择:如果本地NameNode是健康的,且ZKFC发现没有其它的节点当前持有znode锁,它将为自己获取该锁。如果成功,则它已经赢得了选择,并负责运行故障转移进程以使它的本地NameNode为Active。故障转移进程与前面描述的手动故障转移相似,首先如果必要保护之前的现役NameNode,然后本地NameNode转换为Active状态
8.3 HDFS-HA集群配置
8.3.1 环境准备
A. 修改IP
B. 修改主机名及主机名的IP地址映射
C. 关闭防火墙
D. ssh免密登录
E. 安装JDK,配置环境变量等
8.3.2 规划集群
hadoop01 | hadoop02 | hadoop03 |
---|---|---|
NameNode | NameNode | |
JournalNode | JournalNode | JournalNode |
DataNode | DataNode | DataNode |
ZK | ZK | ZK |
ResourceManager | ||
NodeManager | NodeManager | NodeManager |
8.3.3 配置Zookeeper集群
-
解压安装
解压zookeeper安装包到/opt/module/目录下
在/opt/module/zookeeper-3.4.10/这个目录下创建zkData
重命名/opt/module/zookeeper-3.4.10/conf这个目录下的zoo_sample.cfg为zoo.cfg
-
配置zoo.cfg文件
A. 具体配置
dataDir=/opt/module/zookeeper-3.4.10/zkData
增加如下配置
#########cluster######### server.1=hadoop01:2888:3888 server.2=hadoop02:2888:3888 server.3=hadoop03:2888:3888
B. 配置参数解读
server.A=B:C:D。
A是一个数字,表示这个是第几号服务器
B是这个服务器的IP地址
C是这个服务器与集群中的Leader服务器交换信息的端口
D是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口
集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server
-
集群操作
A. 在/opt/module/zookeeper-3.4.10/zkData目录下创建一个myid的文件
B. 编辑myid文件
在文件中添加与server对用的编号;如1
C. 拷贝(分发)配置号的zookeeper到其他机器上(scp -r zookeeper-3.4.10/ root@hadoop02.jinghang:/opt/app/ 等);并分别修改myid文件中内容为2、3
D. 分别启动zookeeper(bin/zkServer.sh start)
E. 查看状态(bin/zkServer.sh status)
8.3.4 配置HDFS-HA集群
-
在opt目录下创建一个ha文件夹
-
将/opt/app/下的hadoop-2.7.2拷贝到/opt/ha目录下
-
配置hadoop-env.sh
export JAVA_HOME=/opt/module/jdk1.8.0_144
-
配置core-site.xml
<configuration> <!-- 把两个NameNode)的地址组装成一个集群mycluster --> <property> <name>fs.defaultFS</name> <value>hdfs://mycluster</value> </property> <!-- 指定hadoop运行时产生文件的存储目录 --> <property> <name>hadoop.tmp.dir</name> <value>/opt/ha/hadoop-2.7.2/data/tmp</value> </property> </configuration>
-
配置hdfs-site.xml
<configuration> <!-- 完全分布式集群名称 --> <property> <name>dfs.nameservices</name> <value>mycluster</value> </property> <!-- 集群中NameNode节点都有哪些 --> <property> <name>dfs.ha.namenodes.mycluster</name> <value>nn1,nn2</value> </property> <!-- nn1的RPC通信地址 --> <property> <name>dfs.namenode.rpc-address.mycluster.nn1</name> <value>hadoop01:9000</value> </property> <!-- nn2的RPC通信地址 --> <property> <name>dfs.namenode.rpc-address.mycluster.nn2</name> <value>hadoop02:9000</value> </property> <!-- nn1的http通信地址 --> <property> <name>dfs.namenode.http-address.mycluster.nn1</name> <value>hadoop01:50070</value> </property> <!-- nn2的http通信地址 --> <property> <name>dfs.namenode.http-address.mycluster.nn2</name> <value>hadoop02:50070</value> </property> <!-- 指定NameNode元数据在JournalNode上的存放位置 --> <property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://hadoop01:8485;hadoop02:8485;hadoop03:8485/mycluster</value> </property> <!-- 配置隔离机制,即同一时刻只能有一台服务器对外响应 --> <property> <name>dfs.ha.fencing.methods</name> <value>sshfence</value> </property> <!-- 使用隔离机制时需要ssh无秘钥登录--> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/home/jinghang/.ssh/id_rsa</value> </property> <!-- 声明journalnode服务器存储目录--> <property> <name>dfs.journalnode.edits.dir</name> <value>/opt/ha/hadoop-2.7.2/data/jn</value> </property> <!-- 关闭权限检查--> <property> <name>dfs.permissions.enable</name> <value>false</value> </property> <!-- 访问代理类:client,mycluster,active配置失败自动切换实现方式--> <property> <name>dfs.client.failover.proxy.provider.mycluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property> </configuration>
-
拷贝配置好的hadoop环境到其他节点
8.3.5 启动HDFS-HA集群
-
在各个JournalNode节点上,输入以下命令启动journalnode服务:sbin/hadoop-daemon.sh start journalnode
-
在[nn1]上,对其进行格式化,并启动:bin/hdfs namenode -format,sbin/hadoop-daemon.sh start namenode
-
在[nn2]上,同步nn1的元数据信息:bin/hdfs namenode -bootstrapStandby
-
启动[nn2]:sbin/hadoop-daemon.sh start namenode
-
查看web页面显示
-
在[nn1]上,启动所有datanode:sbin/hadoop-daemons.sh start datanode
-
将[nn1]切换为Active:bin/hdfs haadmin -transitionToActive nn1
-
查看是否Active:bin/hdfs haadmin -getServiceState nn1
8.3.6 配置HDFS-HA自动故障转移
-
具体配置
A. 在hdfs-site.xml中增加
<property> <name>dfs.ha.automatic-failover.enabled</name> <value>true</value> </property>
B. 在core-site.xml文件中增加
<property> <name>ha.zookeeper.quorum</name> <value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value> </property>
-
启动
A. 关闭所有HDFS服务:sbin/stop-dfs.sh
B. 启动Zookeeper集群:bin/zkServer.sh start
C. 初始化HA在Zookeeper中状态:bin/hdfs zkfc -formatZK
D. 启动HDFS服务:sbin/start-dfs.sh
-
验证
A. 将Active NameNode进程kill:kill -9 namenode的进程id
B. 将Active NameNode机器断开网络:service network stop
8.4 YARN-HA配置
8.4.1 YARN-HA工作机制
官方文档:http://hadoop.apache.org/docs/r2.7.2/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html
8.4.2 配置YARN-HA集群
-
环境准备
A. 修改IP
B. 修改主机名及主机名的IP地址映射
C. 关闭防火墙
D. ssh免密登录
E. 安装JDK,配置环境变量等
F. 配置zookeepre集群
-
规划集群
hadoop01 hadoop02 hadoop03 NameNode NameNode JournalNode JournalNode JournalNode DataNode DataNode DataNode ZK ZK ZK ResourceManager ResourceManager NodeManager NodeManager NodeManager -
具体配置
yarn-site.xml
<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <!--启用resourcemanager ha--> <property> <name>yarn.resourcemanager.ha.enabled</name> <value>true</value> </property> <!--声明两台resourcemanager的地址--> <property> <name>yarn.resourcemanager.cluster-id</name> <value>cluster-yarn1</value> </property> <property> <name>yarn.resourcemanager.ha.rm-ids</name> <value>rm1,rm2</value> </property> <property> <name>yarn.resourcemanager.hostname.rm1</name> <value>hadoop01</value> </property> <property> <name>yarn.resourcemanager.hostname.rm2</name> <value>hadoop02</value> </property> <!--指定zookeeper集群的地址--> <property> <name>yarn.resourcemanager.zk-address</name> <value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value> </property> <!--启用自动恢复--> <property> <name>yarn.resourcemanager.recovery.enabled</name> <value>true</value> </property> <!--指定resourcemanager的状态信息存储在zookeeper集群--> <property> <name>yarn.resourcemanager.store.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value> </property> </configuration>
同步更新其他节点的配置信息
-
启动HDFS
同12.3.5
-
启动YARN
A. 如果之前启动了HDFS服务,关闭所有HDFS服务:sbin/stop-dfs.sh
B. 再启动各台服务器中的Zookeeper集群:bin/zkServer.sh start
C. 在任意服务器初始化HA在Zookeeper中状态:bin/hdfs zkfc -formatZK
D. 在namenode所在的节点启动HDFS服务:sbin/start-dfs.sh
E. 在resourcemanager所在的服务器执行:sbin/start-yarn.sh
F. 确保两个resourcemanager都启动了,如果没有启动手动开启:sbin/yarn-daemon.sh start resourcemanager
G. 查看服务状态:bin/yarn rmadmin -getServiceState rm1