HDFS基础知识、集群搭建及JavaAPI使用

HDFS基础知识、集群搭建及JavaAPI使用

  • 基础知识
  1. 1简介

全称Hadoop Distributed File System,是Hadoop的两大核心技术之一。

  1. 2分布式文件系统结构

主节点承担起数据目录、元数据服务,从节点承担具体存储的任务。

HDFS基础知识、集群搭建及JavaAPI使用

  1. 3HDFS实现目标

          兼容廉价的硬件设备

          实现流数据读写

          支持大数据集

          支持简单的文件模型

          强大的跨平台兼容性

  1. 4HDFS的局限性

          不适合低延迟的数据访问(HBase可以满足实时处理需求)

          无法高效存储大量小文件(如果小文件过多,HDFS的索引结构将会相当庞大,搜索效率会越来越低)

          不支持多用户写入及任意修改文件(只允许追加不允许修改)

  1. 5HDFS的相关概念

          块:目的是为了分摊磁盘读写开销,也就是在大量数据间分摊磁盘寻址开销。HDFS的一个块要比普通文件系统的块大很多,普通一块为64MB也可以设置成128MB,这样设计的目的是支持面向大规模数据存储,降低分布式节点的寻址开销。

 

HDFS两大组件:

名称节点:是整个HDFS集群的管家,负责整个系统元数据的管理,记录信息,相当于数据目录。

数据节点(DateNode):存储实际数据。

HDFS基础知识、集群搭建及JavaAPI使用

名称节点中保存的元数据:

里面包含以下信息:

         文件是什么

         文件被分成多少块

         每个块和文件是怎么映射的

         每个块被存储在哪个服务器上

HDFS基础知识、集群搭建及JavaAPI使用

HDFS基础知识、集群搭建及JavaAPI使用

 

  1. 6HDFS存储原理

HDFS基础知识、集群搭建及JavaAPI使用

冗余数据存储的好处:加快数据传输速度,很容易检查数据错误(有参照),保证了数据可靠性

HDFS会选择空间比较大,不太忙的数据节点存放副本

 

数据读取(就近选择)

HDFS提供了一个API可以确定一个数据节点所属的机架ID,客户端可以调用API来获取自己所属机架的ID

当客户端读取数据时,从名称节点获得数据库不同副本的存放位置列表,列表中包含了副本所在的数据节点,可以调用API来确定客户端和这些数据节点所属的机架ID,当发现某个数据块副本对应的机架ID和客户端对应的机架ID相同时就优先选择该副本读取数据,如果没有发现,就随机选择一个副本读取数据。

 

数据的错误与恢复

名称节点出错:暂停服务一段时间,从第二名称节点恢复数据(HDFS2.0是热备份,不需要暂停服务时间)

数据节点: 数据节点每个一段时间会给名称节点发送心跳信息,如果一段时间名称节点没有收到心跳信息,则认为数据节点出现故障。则复制备份信息。

  1. 7HDFS读数据过程

HDFS基础知识、集群搭建及JavaAPI使用

第一步:打开文件

第二步:获取数据块信息(通过ClientProtocal.getBlockLocations()查找下一个数据块)

第三步:读取请求(选择距离客户端最近的数据节点读数据)

第四步:读取数据

第五步:获取数据块信息(通过ClientProtocal.getBlockLocations()查找下一个数据块)

第六步:读取数据

第七步:关闭文件

  1. 8HDFS写数据过程

HDFS基础知识、集群搭建及JavaAPI使用

  • Shell命令访问文件系统

HDFS基础知识、集群搭建及JavaAPI使用

HDFS基础知识、集群搭建及JavaAPI使用

HDFS基础知识、集群搭建及JavaAPI使用

  • HDFS集群搭建

第一步:搭建虚拟机

首先,准备3台虚拟机,其中 1 台虚拟机作为NameNode,2台虚拟机作为DataNode,执行命令:vim /etc/hosts。

HDFS基础知识、集群搭建及JavaAPI使用

第二步:配置Hadoop环境

在linux上配置Hadoop环境

配置完环境后输入source /etc/profile命令,使环境变量生效。

第三步:设置SSH免密登录

设置 SSH 免密码登录,由于master机器将成为Hadoop 集群的NameNode节点,因此配置其可以免密登录集群中其它的slave机器。

执行命令:ssh-****** -t rsa

执行命令后,出现提示可以不予理会,直接按几次回车键就可以了。当出现以下界面时,则说明生成私钥id_rsa和公钥id_rsa.pub成功:

HDFS基础知识、集群搭建及JavaAPI使用

接下来,把生成的公钥id发送到slave1、slave2。

执行命令:ssh-copy-id slave1

slave1会要求你输入slave1这台机器上的密码,密码输入正确后,它已经添加了**。输入 SSH 命令测试 slave1 的免密登陆。

执行命令:ssh slave1

出现下图说明免密登录成功。

HDFS基础知识、集群搭建及JavaAPI使用

第四步:配置HDFS

在所有机器上的/hadoop-2.7.3/etc/hadoop目录中,修改core-site.xml和hdfs-site.xml文件,以完成 HDFS 的配置。

具体配置可参见:https://www.cnblogs.com/yjt1993/p/9505145.html

第五步:格式化 NameNode 以及启动 HDFS 系统

在master这台机器上,输入命令 HDFS 格式化命令。

执行命令:hdfs namenode –format

格式化完成之后,输入 HDFS 系统启动命令。

执行命令:start-dfs.sh

接下来,检查 HDFS 是否启动成功。在游览器中输入如:http://192.168.56.101:50070/,默认为NameNode的IP + 50070端口,当见到以下界面的时候,就说明集群已经起来了。

HDFS基础知识、集群搭建及JavaAPI使用

  • 利用Java API与HDFS进行交互

Pom依赖:

  1. <!--hadoop相关依赖 -->  
  2.         <dependency>  
  3.             <groupId>org.apache.hadoop</groupId>  
  4.             <artifactId>hadoop-client</artifactId>  
  5.             <version>2.6.0</version>  
  6.         </dependency>  
  7.         <dependency>  
  8.             <groupId>org.apache.hadoop</groupId>  
  9.             <artifactId>hadoop-hdfs</artifactId>  
  10.             <version>2.6.0</version>  
  11.         </dependency>  
  12.         <dependency>  
  13.             <groupId>org.apache.hadoop</groupId>  
  14.             <artifactId>hadoop-common</artifactId>  
  15.             <version>2.6.0</version>  
  16.         </dependency>  

JavaAPI:

  1. /**
  2. 静态代码块,设置HDFS访问路径
  3. */
  4. static{  
  5.         conf.set("fs.defaultFS", HDFS_PATH);  
  6.     }  
  7. /** 
  8.  * 查看目录下所有文件 
  9.  * @author zhouyuhuai 
  10.  * @param filepath为目录路径
  11.  */  
  12. public static FileStatus[] getFilesList(String filePath) {  
  13.     try {  
  14.         FileSystem fs = FileSystem.get(conf);  
  15.         FileStatus[] fileStatus = fs.listStatus(new Path(filePath));  
  16.         fs.close();  
  17.         return fileStatus;  
  18.     } catch (Exception e){  
  19.         e.printStackTrace();  
  20.         return null;  
  21.     }  
  22. }  
  23.   
  24. /** 
  25.  * 上传本地文件 
  26.  * @author zhouyuhuai 
  27.  * @param src 本地文件路径 
  28.  */  
  29. public static List uploadFile(String src) throws IOException{  
  30.     FileSystem fs = FileSystem.get(conf);  
  31.     List filePath = new ArrayList();  
  32.     //本地上传文件路径  
  33.     Path srcPath = new Path(src);  
  34.     //HDFS目标路径  
  35.     Path dstPath = new Path(dst);  
  36.     if(!fs.exists(dstPath)){  
  37.         fs.mkdirs(dstPath);  
  38.     }  
  39.     fs.copyFromLocalFile(srcPath, dstPath);  
  40.     //返回文件路径  
  41.     FileStatus [] fileStatus = fs.listStatus(dstPath);  
  42.     for (FileStatus file : fileStatus)  
  43.     {  
  44.         filePath.add(file.getPath());  
  45.     }  
  46.     fs.close();  
  47.     return filePath;  
  48. }  
  49.   
  50. /** 
  51.  * 下载文件至本地 
  52.  * @author zhouyuhuai 
  53.  * @param dst HDFS文件路径
  54.  * @param src 下载目标位置路径
  55.  * */  
  56. public static void downloadFromHdfs(String dst,String src) throws IOException{  
  57.     FileSystem fs = FileSystem.get(conf);  
  58.     Path path=new Path(dst);  
  59.     InputStream in = fs.open(path);  
  60.     OutputStream out = new FileOutputStream(src);  
  61.     IOUtils.copyBytes(in, out, 4096true);  
  62. }  
  63.   
  64. /** 
  65.  * 删除文件 
  66.  * @author zhouyuhuai 
  67.  * @param dst HDFS文件路径 
  68.  * */  
  69. public static boolean delete(String dst){  
  70.     try{  
  71.         FileSystem fs = FileSystem.get(conf);  
  72.         Path path = new Path(dst);  
  73.         boolean isok = fs.deleteOnExit(path);  
  74.         fs.close();  
  75.         return isok;  
  76.     }catch (Exception e){  
  77.         e.printStackTrace();  
  78.     }  
  79.     return false;  
  80. /** 
  81.  * 通过浏览器上传文件 
  82.  * @param in 
  83.  * @param hdfsPath 
  84.  */  
  85. public static boolean uploadFromBrowser(InputStream in, String hdfsPath) {  
  86.     FileSystem fs = null;  
  87.     try {  
  88.         fs = FileSystem.get(conf);  
  89.     } catch (IOException e) {  
  90.         e.printStackTrace();  
  91.         return false;  
  92.     }  
  93.     FSDataOutputStream out = null;  
  94.     try {  
  95.         out = fs.create(new Path(hdfsPath));  
  96.     } catch (IOException e) {  
  97.         e.printStackTrace();  
  98.         return false;  
  99.     }  
  100.     try {  
  101.         IOUtils.copyBytes(in, out, conf);  
  102.     } catch (IOException e) {  
  103.         e.printStackTrace();  
  104.     }  
  105.     return true;  
  106. }  
  107.   
  108. /** 
  109.  * 通过浏览器下载 
  110.  * @param path 下载文件路径 
  111.  * @param response 
  112.  * @return 
  113.  */  
  114. public static boolean downLoadFromBrowser(String path, HttpServletResponse response){  
  115.     FileSystem fs = null;  
  116.     try {  
  117.         fs = FileSystem.get(conf);  
  118.         InputStream in = fs.open(new Path(path));  
  119.         String name = path.substring(path.lastIndexOf("/")+1);  
  120.         //设置content-disposition响应头控制浏览器以下载的形式打开文件  
  121.         response.setHeader("content-disposition""attachment;filename=" + name);  
  122.         byte[] buffer = new byte[1024];  
  123.         //通过response对象获取OutputStream  
  124.         OutputStream out = response.getOutputStream();  
  125.         int len = 0;  
  126.         //FileInputStream流写入到buffer缓冲区  
  127.         while ((len = in.read(buffer)) > 0) {  
  128.             //使用OutputStream将缓冲区的数据输出到客户端浏览器  
  129.             out.write(buffer, 0, len);  
  130.         }  
  131.         in.close();  
  132.     } catch (IOException e) {  
  133.         e.printStackTrace();  
  134.         return false;  
  135.     }  
  136.     return true;  

 

本文参考:https://www.jianshu.com/p/58b39974abb7