HDFS体系结构

HDFS体系结构

★ 分布式文件系统

一种可以管理分布在不同机器上的文件的操作系统。因为,单一的一台机器上的存储已经不能满足需要。不同主机上的文件可以通过网络进行分享。也叫网络操作系统,即NFS。通过网络访问的文件,对用户和程序来说,如同本地一样。其中HDFS就是其中一种分布式操作系统。适合一次写入,多次读写的情况。

★ HDFS 常用shell操作

在Hadoop中通过shell命令访问HDFS文件系统中文件的命令方法是hadoop fs 开头或hadoop dfs。

完整的命令应该格式是: hadoop fs schema://authority/path

完整的命令示例如:hadoop fs hdfs://hadooptest:9000/

hdfs://hadooptest:9000是conf/core-site.xml配置文件中fs.default.name对应的值。

下面介绍详细命令:(下面的命令写的是简写)

命令一:hadoop fs -help

[root@hadooptest ~]# hadoop fs -help

Warning: $HADOOP_HOME is deprecated.

 

hadoop fs is the command to execute fscommands. The full syntax is:

 

hadoop fs [-fs <local | file systemURI>] [-conf <configuration file>]

       [-D <property=value>] [-ls <path>] [-lsr <path>] [-du<path>]

       [-dus <path>] [-mv <src> <dst>] [-cp <src><dst>] [-rm [-skipTrash] <src>]

       [-rmr [-skipTrash] <src>] [-put <localsrc> ... <dst>][-copyFromLocal <localsrc> ... <dst>]

       [-moveFromLocal <localsrc> ... <dst>] [-get [-ignoreCrc][-crc] <src> <localdst>

       [-getmerge <src> <localdst> [addnl]] [-cat <src>]

       [-copyToLocal [-ignoreCrc] [-crc] <src> <localdst>][-moveToLocal <src> <localdst>]

       [-mkdir <path>] [-report] [-setrep [-R] [-w] <rep> <path/file>]

       [-touchz <path>] [-test -[ezd] <path>] [-stat [format]<path>]

       [-tail [-f] <path>] [-text <path>]

       [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]

       [-chown [-R] [OWNER][:[GROUP]] PATH...]

       [-chgrp [-R] GROUP PATH...]

       [-count[-q] <path>]

       [-help [cmd]]

 

-fs [local | <file system URI>]:        Specify the file system to use.

...........................

ps : 用于显示命令的帮助文档

 

命令二:hadoop fs -ls(r) <path>    //显示当前目录下所有文件

显示列表中,列表的显示,类似Linux下ls -l 列出来的类似

d表示是文件夹   -表示是文件

再接着的9位表示的是权限,权限分组类似linux

再接着的是表示的是所属的用户和组

再接着的是文件的大小

再接着的是日期

 

命令三:hadoop fs -du(s) <path>  //显示目录中所有文件大小

[root@hadooptest ~]# hadoop fs -dus /txt

Warning: $HADOOP_HOME is deprecated.

 

hdfs://hadooptest:9000/txt      36

[root@hadooptest ~]# hadoop fs -du /txt

Warning: $HADOOP_HOME is deprecated.

 

Found 2 items

15         hdfs://hadooptest:9000/txt/wealon.txt

21         hdfs://hadooptest:9000/txt/wealonxt.txt

 

命令四:hadoop fs -count[-q] <path>    //显示目录中文件数量

[root@hadooptest ~]# hadoop fs -count /txt

Warning: $HADOOP_HOME is deprecated.

 

          1            2                 36hdfs://hadooptest:9000/txt

分别显示了目录数,文件数,文件大小及所计算的路径

 

命令五:hadoop fs -mv <src> <dst>       //移动多个文件到目标目录

移动文件从HDFS的src到dst路径

 

命令六:hadoop fs -cp <src> <dst>        //复制多个文件到目标目录

移动文件从HDFS的src到dst路径

 

命令七:hadoop fs -rm(r)                //删除文件(夹)

要删除文件夹,必须用rmr参数

 

命令八:hadoop fs -put <localsrc> <dst>       //本地文件复制到hdfs

ps:localsrc表示的是本地路径

 

命令九:hadoop fs -copyFromLocal       //同put

 

命令十:hadoop fs -moveFromLocal      //从本地文件移动到hdfs

 

命令十一:hadoop fs -get [-ignoreCrc] <src> <localdst>       //复制文件到本地,可以忽略crc校验

 

命令十二:hadoop fs -getmerge <src> <localdst>                  //将源目录中的所有文件排序合并到一个文件中

PS:用于合并文件,把零散的小文件合并成一个大文件

 

命令十三:hadoop fs -cat <src>    //在终端显示文件内容

PS:查看

命令十四:hadoop fs -text <src>  //在终端显示文件内容

同-cat

命令十五:hadoop fs -copyToLocal [-ignoreCrc] <src> <localdst>         //复制到本地

PS:From 与 To

命令十六:hadoop fs -moveToLocal <src> <localdst>

PS:From 与 To

命令十七:hadoop fs -mkdir <path>      //创建文件夹

 

命令十八:hadoop fs -touchz <path>    //创建一个空文件

 

PS:HDFS的命令,与linux的命令可以关联起来,比较类似。

 

▲ 文件的副本数

对于在conf/hdfs-site.xml中配置的dfs.replication参数的值,表示的是HDFS中某个文件或block的副本数。默认是3

如之前设置的副本数是2,则上传的所有文件的副本数都将是2个

如果在上传了一部分文件后,更改了dfs.replication的值为3

则,在修改之后上传的文件或block的副本数为3,而修改之前上传的文件的副本数仍旧为2.

如果要使修改之前上传的文件的副本数从2变为3,只需要执行如下的命令。

 

hadoop fs -setrep -R 3 /

 

命令:hadoop fsck -locations 用来查看副本情况

 

在一个dataNode中只保存一个副本,所以,如果一个集群有3台机器,而设置的副本数为4,则,该参数的设置是不会生效的。

★ HDFS体系结构

两个核心:NameNode 和 DataNode

▲ NameNode功能:

接收用户的操作请求

是整个文件系统的管理节点

维护整个文件系统的文件目录树

维护文件或目录的元信息及每个文件对应的数据块列表

 

那么它是怎么实现如上功能的呢?

由以下fsimage、edits、fstime这三个文件来实现。

以上三个文件的位置是在core-site.xml文件中的属性为hadoop.tmp.dir的值来指定的,如/usr/local/hadoop1/tmp

在上述目录下的dfs/name/current目录下有如下四个文件:

edits fsimage  fstime   VERSION

其中:fsimage是元数据镜像文件,存储的是某一时间段NameNode内存的元数据信息

edits保存的是操作日志文件

fstime 保存的是最近一次checkpoint的时间

那么VERSION呢?

 

▲ SecondaryNameNode的功能

用来合并fsimage和edits成新的fsimage,合并后edits清空

edits的合并有一定的条件:

条件一,达到一定的周期,默认是3600秒,即1小时。

条件二,达到一定的大小,默认是67108864,也即64M,如果大小已经达到了这个大小,则触发合并的操作,而不管周期是否已经到3600秒。(见源文件)

 

默认SecondaryNameNode是跟NameNode安装在同一个节点上的,这样是不好的,因为SecondaryNameNode和NameNode都是单节点的,所以,如果出现节点故障,SecondaryNameNode和NameNode都会受到影响。所以,最好是把Name和SecondaryNameNode在集群环境下分别安装在不同的节点中。

▲ DataNode的功能

它提供的是真实文件数据的存储服务。

文件块:它是文件的最基本的存储单位。把一个大的文件划分成小的block,默认的Block大小是64M。

在HDFS文件系统中,如果一个文件的大小小于一个Block块的大小,则该文件并不占用整个数据块的存储空间。

在linux文件系统中,如果一个文件的大小小于一个Block块的大小,则该文件占用的是该块Block的大小。

 

▲ HDFS的权限

文件的权限都设计成与其它常用平台类似,像Linux。当前,安全性仅限于简单权限。谁启动的NameNode,谁就被当成HDFS的超级用户。

★ 用JAVA操作HDFS

用javaAPI操作HDFS,用到的Hadoop核心类有:

FileSystem  表示的是文件系统,对HDFS的操作的方法均来自于该类,这是一个抽象类。

Configuration  表示配置对象

URL  表示 表示路径,在用URL的时候,路径一定要加上schema,不支持简写

FileStatus 文件状态,从该对象中可以获取到文件的名称、文件的权限、等等信息

Path  表示路径,可以用它来描述一个文件或文件夹

FSDataInputStream  在用FileSystem读取文件的时候,是把文件读取到该流中,从而根据流的对接,可以把文件输出到输出流中。

IOUtils 一个IO工具类,用于处理IO操作,简化了IO操作。

以下是测试的例子,不全,基本操作全在了。

▲ 初始化变量

   private static String url = null;

   private static Configuration conf = null;

   private static FileSystem fs = null;

   // 初始化url Configuration FileSystem

   static {

      try {

         url = "hdfs://192.168.75.245:9000";

         conf = new Configuration();

         fs = FileSystem.get(URI.create(url), conf, "root");

      }catch(Exception e) {

         e.printStackTrace();

      }

   }

▲ 例子一:检测HDFS中某个文件是否存在

   /** 测试文件夹是否存在 **/

   @Test

   public void testFolderExist() throws Exception {

      //路径相当于:hdfs://hadooptest:9000/wealon

      boolean exist = this.isFolderExist("/wealon");

      System.out.println(exist);

   } 

   /**

    * 检查某个文件夹是否存在

    *

    * @throws Exception

    */

   private boolean isFolderExist(String path) throws Exception {

      return fs.exists(new Path(path));

   }

 

▲ 例子二:测试创建文件夹

   /** 测试创建文件夹 **/

   @Test

   public void testCreateFolder() throws Exception {

      // 创建文件夹

      this.createFolder("/path");

   }

   /**

    * 根据传入的字符串创建文件夹

    *

    * @param folderName

    */

   private void createFolder(String folderName) throws Exception {

      fs.mkdirs(new Path(folderName));

   }

▲ 例子三:创建文件

   /** 测试创建文件 **/

   @Test

   public void testCreateFile() throws Exception {

      // 创建空文件

      this.createFile("/path/test.txt");

   }

   /**

    * 根据字符串创建文件

    *

    * @param fileName

    */

   private void createFile(String fileName) throws Exception {

      fs.create(new Path(fileName));

   }

▲ 例子四:测试读取文件二

   /** 测试读取文件二 **/

   @Test

   public void tesReadFile2() throws Exception {

      // 读取文件  方法二

      this.readFile2("HDFS://hadooptest:9000/core-site.xml");

   }

   /**

    * 读取文件方法

    *

    * @param fileName

    */

   private void readFile2(StringpathName) throwsException {

      //设置让程序识别HDFS协议

      URL.setURLStreamHandlerFactory(newFsUrlStreamHandlerFactory());

      URLurl = newURL(pathName);

      InputStreamis = url.openStream();

      IOUtils.copyBytes(is,System.out,1024, true);

   }

▲ 例子五:测试读取文件一

   /** 测试读取文件 **/

   @Test

   public void tesReadFile() throws Exception {

      // 读取文件方法

      this.readFile("/core-site.xml");

   }

   /**

    * 读取文件方法

    *

    * @param fileName

    */

   private void readFile(String pathName) throws Exception {

      if (this.isFolderExist(pathName)){

         FSDataInputStreamis = fs.open(new Path(pathName));

         IOUtils.copyBytes(is,System.out,1024, false);

         IOUtils.closeStream(is);

      }else{

         System.err.println("文件不存在……");

      }

   }

▲ 例子六:上传文件

   /** 测试上传 **/

   @Test

   public void testPutFile() throws Exception {

      // 上传

      this.putFile("d://mail.txt","");

   }

   /**

    * put 上传文件

    *

    * @param fileName

    */

   private void putFile(StringsrcPath,String destPath) throws Exception {

      StringfileName = getFileName(srcPath);

      if (!this.isFolderExist(destPath+ "/"+ fileName)) {

         fs.copyFromLocalFile(new Path(srcPath), new Path(destPath==""?"/":destPath));

      }else{

         System.err.println("文件已经存在……");

      }

   }

   /**

    * 根据上传的本地路径,得到文件名

    * @param srcPath

    * @return

    */

   private StringgetFileName(String srcPath) {

      String[]arr = srcPath.split("//");

      return arr[arr.length-1];

   }

▲ 例子七:删除文件或文件夹

   /** 测试删除文件或文件夹 **/

   @Test

   public void testDeleteFile() throws Exception {

      // 删除

      this.deleteFile("/path");

   }

   /**

    * 删除文件

    * @param fileName

    */

   private void deleteFile(String filePath) throws Exception {

      if (this.isFolderExist(filePath)){

         boolean isDir = fs.getFileStatus(newPath(filePath)).isDir();

         if(isDir){

            System.out.println("正在删除文件夹");

            fs.delete(new Path(filePath), true);

         }else{

            System.out.println("正在删除文件");

            fs.delete(new Path(filePath), false);

         }

      }else{

         System.err.println("文件不存在……");

      }

   }

例子八:测试获取所有的文件夹或文件

   /** 测试获取所有的文件或文件夹 **/

   @Test

   public void testgetAllFiles() throws Exception {

      this.getAllHDFSFiles(new Path("/"));

   }

   /**

    * 得到所有的文件

    */

   private void getAllHDFSFiles(Path path) throws Exception{

      FileStatus[]fileStatus = fs.listStatus(path);

      for(FileStatus fs :fileStatus){

         //String name = fs.getPath().getName();

         Stringtype = fs.isDir()?"目录:":"文件:";

         if(fs.isDir()){

            System.out.println(type +fs.getPath());

            this.getAllHDFSFiles(fs.getPath());

         }else{

            System.out.println(type +fs.getPath());

         }

      }

   }

 

注:还可以测试修改文件的副本数,获取文件的大小等。

 

 

★ RPC原理

RPC,即Remote ProcedureCall,即远程过程调用。它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议存在,如TCP UDP

RPC采用客户机/服务机模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。

首先,客户机调用进程发送一个有进程参数的调用信息到服务器进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用的信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息。然后等待焉个调用信息。

Hadoop的体系结构就是构建在RPC机制上的,如在启动Hadoop的时候,start-all.sh会启动所有的服务器端进程。也就是启动RPC的服务器端。当我们用命令云访问HDFS或跪一个JOB的时候,其实就是客户端在向服务器端发送请求。如果是访问HDFS,则请求到达NameNode,NameNode再把请求分配到对应的DataNode。如果是一个MR的计算请求,则请求到达JobTracker,JobTracker会处理该请求,把任务分配到对应的TaskTracker。

 

下面是一个RPC的简单原理实现。

▲ 1.定义一个接口

package com.broader.rpc;

 

import org.apache.hadoop.ipc.VersionedProtocol;

 

public interfaceMyBean extendsVersionedProtocol {

   public abstract Stringhello(String name) ;

}

注:该接口继承自VersionedProtocol,

该类的几个子类:

ClientProtocol 它是客户端FileSystem与NameNode通信和接口

DataNodeProtocol 它是DataNode与NameNode通信的的接口

NamenodeProtocol 它是SecondaryNameNode与NameNode通信的接口

 

该类结构如下:

                                 

▲ 2.定义上述接口的实现类

package com.broader.rpc;

 

import java.io.IOException;

 

public classMyBeanImpl implementsMyBean{

 

   public static long VERSION = 2343555L;

  

   @Override//被调用的方法

   public String hello(Stringname) {

      System.out.println("MyBeanImpl.hello method is called");

      return "hello "+ name;

   }

 

   @Override

   public longgetProtocolVersion(String protocol, long clientVersion)

         throws IOException {

     

      return VERSION;

   }

 

}

▲ 3.定义服务器端

package com.broader.rpc;

 

import java.io.IOException;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.ipc.RPC;

import org.apache.hadoop.ipc.Server;

 

public classMyServer {

 

   public static final int PORT = 12345;

   public static final String SERVER_ADDRESS= "localhost";

 

   public static void main(String[] args) throws IOException {

      //创建一个Server

      final Server server = RPC.getServer(new MyBeanImpl(), SERVER_ADDRESS,PORT,

            new Configuration());

      //启动Server    一直监听12345端口

      server.start();

   }

}

▲ 4.定义客户端

package com.broader.rpc;

 

import java.net.InetSocketAddress;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.ipc.RPC;

 

public classMyClient {

 

  

   public static void main(String[] args) throws Exception{

      //用接口来接收一个代理对象

      final MyBean proxy =(MyBean)RPC.getProxy(

            MyBean.class,

            MyBeanImpl.VERSION,

            newInetSocketAddress(MyServer.SERVER_ADDRESS,MyServer.PORT),

            new Configuration());

      //通过代理对象调用接口中定义的方法

      StringreturnVal = proxy.hello("liuzhixiang");

      System.out.println(returnVal);

      //停止代理对象

      RPC.stopProxy(proxy);

   }

 

}

 

注:

先运行Myserver,启动服务器端程序

再运行MyClient客户端,则它会得到从服务器返回的信息。

RPC的调用类似于Socket的调用、也类似于WebService的调用

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章