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的調用

 

 

 

 

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