本文主要是介绍HDFS的体系结构和常用操作,涉及到的知识点如下:

* HDFS的体系结构
* 数据上传
* 数据下载
HDFS的体系结构

Hadoop的生态圈,包括HDFS、Yarn、HBase都是主从结构。对于HDFS来说,它的
主节点是NameNode,从节点是DataNode,还有一个更新最新状态的SecondaryNameNode,下面我们对这几个结点做详细的解释。

*
NameNode:名称节点

(1)职责:

* 管理、维护HDFS;
* 接收客户端的请求:上传、下载、创建目录等;
* 维护两个非常重要的文件:edits文件 –> 记录了操作日志;fsimage文件 –> 记录HDFS元信息
(2)HDFS操作日志:edits文件

位置:find . -name edits* (在当前目录下查找以edits打头的文件)

​ 最新的操作日志以edits_inprogress***开头

记录:Edits文件保存了自最后一次检查点之后所有针对HDFS文件系统的操作,比如:增加文件、重命名文件、删除目录等等

都是二进制

HDFS提供了一个工具:edits viewer 日志查看器,可以将操作日志转化为XML格式来查看。命令如下:
hdfs oev 命令将日志(二进制)输出为XML文件 -i表示输入,-o表示输出 hdfs oev -i
edits_inprogress_0000000000000000208 -o ~/a.xml
(3)HDFS的元信息:fsimage文件

位置:和edits文件在一起


记录:fsimage是HDFS文件系统存于硬盘中的元数据检查点,里面记录了自最后一次检查点之前HDFS文件系统中所有目录和文件的序列化信息(数据块的位置、冗余信息)

也是二进制

HDFS提供了一个工具:image viewer查看器,可以将操作日志转化为文本或者XML格式来查看
hdfs oiv 命令将日志(二进制)输出为文本文件 -i表示输入,-o表示输出 hdfs oiv -i
fsimage_0000000000000000207 -o ~/b.txt (文本) hdfs oiv -i
fsimage_0000000000000000207 -o ~/c.xml -p XML(xml文件)
*
DataNode:数据结点

数据块大小:

* 1.x版本 64M
* 2.x笨笨 128M
位置:find . -name blk*(blk是block的简写)

一般原则:数据块的冗余度一般跟数据结点个数一致,最大不要超过3。在生产环境下,至少2个数据结点

blk_*表示数据块

blk_*.meta表示数据块的元信息

*
SecondaryNameNode:第二名称结点

作用:把edits中最新的状态信息合并到fsimage文件中,即日志合并。合并原理图如下。




NameNode和SecondaryNameNode在一起的原因是为了效率问题,因为两者在一起,SecondaryNameNode在合并最新的edits到fsimage中时,只需要执行cp操作即可;在合并后,把最新的fsimage上传回NameNode下的fsimage

什么时候合并?当HDFS发出检查点(checkpoint)的时候。默认会在两种情况下发出检查点:

​ (1)每隔60分钟。可通过修改参数,改变时间

​ (2)当edits文件达到64M。可通过修改参数,改变阈值

补充:Oracle数据库中也有检查点,如果发生检查点,会以最高优先级唤醒数据库写进程(DBWn)把内存中的脏数据写到数据文件上(持久化)

注意:NameNode和SecondaryNameNode名字看起来差不多,但是两者并没有什么关系

*
HDFS存在的问题:

(1)NameNode单点故障,即一旦出现问题整个系统就瘫痪

​ 解决方案:Hadoop1.0中,没有解决方案。

​ Hadoop2.0中,使用Zooker实现Name的HA(高可用性,后面会讲到)功能。

(2)NameNode压力过大,且内存受限,影响系统扩展

​ 解决方案:Hadoop1.0中,没有解决方案

​ Hadoop2.0中,使用NameNode的联盟实现其水平扩展

HDFS上传

先来一张HDFS文件上传的流程图:



看完流程图就是具体的上传了,有两种方式:

(1)命令行:
-put 上传数据 hdfs dfs -put data.txt /input -copyFromLocal 上传数据 hdfs dfs
-copyFromLocal data.txt /input -moveFromLocal 上传数据(相当于 ctrl+x 剪切)

(2)JavaApi:以下是通过javaApi进行文件上传的代码块,以Window下的FinancialWorkStationEdu.exe文件为例(141M):
//使用自己写流的方式来实现 @Test public void testUpload1() throws Exception {
//设置当前用户为root用户(不设置可能出现权限异常) //System.setProperty("HADOOP_USER_NAME","root");
//构造一个输入流 FileInputStream in = new FileInputStream(
"D:\\download\\chromeDownload\\FinancialWorkStationEdu.exe");
//配置NameNode地址(在上一边环境变量的配置时,我们配置过它的key和value,直接复制过来即可) Configuration conf = new
Configuration(); conf.set("fs.defaultFS","hdfs://192.168.171.113:9000"); //客户端
FileSystem client = FileSystem.get(conf); //得到一个输出流 FSDataOutputStream out =
client.create(new Path("/input/a.exe")); //构造缓冲区 byte[] buffer = new byte[1024];
int len = 0; while((len = in.read(buffer)) > 0){ //将读到的数据写入 out.write(buffer,0
,len); }out.flush(); out.close(); in.close(); } //使用Hadoop提供的工具类来实现 @Test public
void testUpload2() throws Exception { //设置当前用户为root用户(不设置可能出现权限异常)
//System.setProperty("HADOOP_USER_NAME","root"); //构造一个输入流 FileInputStream in =
new FileInputStream("D:\\download\\chromeDownload\\FinancialWorkStationEdu.exe"
);//配置NameNode地址(在上一边环境变量的配置时,我们配置过它的key和value,直接复制过来即可) Configuration conf =
new Configuration(); conf.set("fs.defaultFS","hdfs://192.168.171.113:9000");
//客户端 FileSystem client = FileSystem.get(conf); //得到一个输出流 FSDataOutputStream out
= client.create(new Path("/input/b.exe")); //使用Hadoop提供的工具类来实现
IOUtils.copyBytes(in,out,1024); }
在运行上面的代码之前有两个问题要注意:

*
我们使用到的这些API有些是Hadoop提供的,我们需要到hadoop里面把这些jar包拷贝下来,放到项目的lib目录。我们先看下Hadoop的目录结构:



然后我们需要把common下的lib包和hdfs下的lib拷贝下来即可。

*
权限配置,如果没有配置权限的话,会抛出以下异常:

Caused by:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException):
Permission denied: user=cpMark, access=WRITE,
inode=”/user/cpMark/input/a.exe”:root:supergroup:drwxr-xr-x

即当前用户没有w权限

处理这个异常,有以下几种方式:

(1)关闭HDFS的权限检查。这个在hdfs-site.xml中我们是配置过为false,不过被我们注释没有打开,如下:

![HDFS权限配置](https://img-blog.csdn.net/20180505160012706?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NwX01hcms=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
这里我们打开就可以正常运行了。运行结果如下:



(2)设置一个属性。把自己设置为root用户,具体方式为在我们的JavaApi前面设置用户名(上面代码注释打开即可):
//设置当前用户为root用户 System.setProperty("HADOOP_USER_NAME","root");
(3) -D的使用,通过-D获取命令行上的参数。比如:-Dname=Tom
-Dgender=Male,那么我们在程序中就可以取到name参数和gender参数,具体如下:
String name = System.getProperty("name"); String gender = System.getProperty(
"gender"); System.out.println(name+"\t"+gender);
具体操作如下,新建一个带有main入口函数的类,copy以上代码,然后使用javac编译,编译成功之后,使用java命令执行,java -Dname=Tom
-Dgender=Male XXX(编译出来的class文件)即可

(4)改变input目录的权限
hdfs dfs -chmod 777 /input
这样就可以执行了。

HDFS下载

下载的话,和上传一样,先来张流程图,然后是代码:



看完流程图就是具体的上传了,有两种方式:

(1)命令行:
-copyToLocal 下载数据 -get 下载数据
(2)JavaApi:以下是通过javaApi进行文件下载的代码块,以hdfs /input目录下的a.exe,为例:
@Test public void testDownload1() throws Exception { //设置当前用户为root用户
System.setProperty("HADOOP_USER_NAME", "root");
//配置NameNode地址(在上一边环境变量的配置时,我们配置过它的key和value,直接复制过来即可) Configuration conf = new
Configuration(); conf.set("fs.defaultFS", "hdfs://192.168.171.113:9000");
//构造客户端 FileSystem client = FileSystem.get(conf); //构造一个输入流 FSDataInputStream in
= client.open(new Path("/input/a.exe")); //构造一个输出流 ----> D:\temp\a.exe
OutputStreamout = new FileOutputStream("D:\\temp\\a.exe"); //构造一个缓冲区 byte[]
buffer =new byte[1024]; int len = 0; while ((len = in.read(buffer)) > 0) {
//读取到了数据 out.write(buffer, 0, len); } out.flush(); out.close(); in.close(); }
@Testpublic void testDownload2() throws Exception { //设置当前用户为root用户
System.setProperty("HADOOP_USER_NAME", "root");
//配置NameNode地址(在上一边环境变量的配置时,我们配置过它的key和value,直接复制过来即可) Configuration conf = new
Configuration(); conf.set("fs.defaultFS", "hdfs://192.168.171.113:9000");
//构造客户端 FileSystem client = FileSystem.get(conf); //构造一个输入流 FSDataInputStream in
= client.open(new Path("/input/a.exe")); //构造一个输出流 ----> D:\temp\a.exe
OutputStreamout = new FileOutputStream("D:\\temp\\b.exe"); //使用工具类简化程序
IOUtils.copyBytes(in, out, 1024); }

以上就是HDFS常见功能的介绍,一些其它的API,比如创建目录、查看目录及文件信息、查找某个文件在HDFS集群的位置等,只是API不同而已,大家可以自己去熟悉。

下一篇我会介绍HDFS的高级功能:回收站、快照、配额等。




友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信