Hadoop(6) HDFS


Hadoop(6)
HDFS

HDFS


HDFS介紹

HDFS的定義

HDFS(Hadoop Distributed File System),即Hadoop分佈式文件系統

HDFS由多臺主機搭建服務器集羣來實現,集羣中的服務器分別負責不同的功能

HDFS通過目錄樹來定位文件

HDFS的優缺點

優點

  1. 採用多副本機制,如果一個副本丟失,可以自動恢復,容錯性高
  2. 適合處理大數據
  3. 可以構建在廉價的機器上,隨時航向擴展,通過多副本機制提高可靠性

缺點

  1. 不適合低延遲訪問數據
  2. 無法高效的對大量小文件進行存儲
    1. 存儲大量的小文件會佔用大量的NameNode內存
    2. 小文件的尋址時間會浪費大量的時間,從而降低效率(一般來說尋址時間<傳輸時間的 1%比較合適)
  3. 不支持併發寫入和文件的修改
    1. 一個文件只能單線程寫入,不允許多線程操作
    2. 僅支持數據的追加,不支持文件的修改

HDFS的應用場景

HDFS適合一次寫入,多次讀取,並且不支持文件的修改,適合做數據分析


HDFS的組成

在這裏插入圖片描述

HDFS由NameNode,DataNode,ClientSecondaryNameNode組成,在
HDFS中,文件以切塊的形式存在,即一個大文件分成多個部分來存儲,每個塊大小爲128MB(1.x版本中是64MB)

一個塊(block)如果太小,會增加尋址時間,如果一個block太大,會導致MapReduce處理這塊數據時會非常慢

注意

HDFS的塊大小主要取決與磁盤的傳輸速率

  • NameNode 可以理解爲結羣的主管
    • 管理HDFS的名稱空間
    • 配置副本策略
    • 管理數據塊的信息(不是數據塊)
    • 處理客戶端的讀寫請求(只是處理請求,不處理讀寫過程)
  • DataNode 負責具體的任務執行
    • 存儲實際的數據塊
    • 執行數據塊的讀寫操作
  • Client 客戶端
    • 與NameNode交互,獲取數據塊信息
    • 與DataNode交互,負責向DataNode讀寫數據
    • 上傳文件時負責文件的切塊
    • 通過指令管理和操作HDFS
  • .SecondaryNameNode
    • 只是對NameNode起輔助作用,注意不是NameNode的熱備


配置Hadoop開發環境

由於加使用的操作系統,開發軟件可能都不一樣,就比如我使用的是基於Linux的Deepin15.11桌面版,開發軟件使用的是idea,相比大多數人使用的是Windows系統下Eclipse開發,所以操作不太一樣

雖然操作不同,但是配置的思路給大家列舉一下,如果大家不會配置,就根據下面的步驟百度一下:

  1. 在開發軟件中配置Maven
  2. 將Hadoop的軟件包(zip或者tar.gz)解壓到自己的磁盤中,不能有中文路徑
  3. 配置Hadoop的環境變量
  4. 配置完之後重啓一下電腦

HDFS的Shell命令

注意

1. 在執行命令時,使用bin/hadoop fsbin/hdfs dfs的效果是一樣的,這是因爲dfs是fs的實現類,它們底層調用的jar包都是一樣的

2. HDFS的命令和Linux的命令很像,如果熟悉Linux指令,HDFS的Shell操作可以很快上手

3. 下面所有的命令演示,涉及到HDFS文件(夾)的變更,都可以通過瀏覽器訪問NameNode50070端口查看HDFS的文件系統詳情來查看命令執行的結果

  • 查看fs的所有命令
hadoop fs

也可以通過下面的指令查看

hadoop fs --help

注意

1. 同樣的hadoop dfshadoop dfs --help也一樣,下面我們就不把fsdfs一一做列舉了,我們統一使用fs

2. 通過以上指令可以查看HDFS的所有指令,下面我們只列舉最常用的幾個指令,如果大家感興趣可以把HDFS所有的命令自己測試一遍

HDFS操作

  • 查看指定目錄的內容
hadoop fs -ls <目錄路徑>
  • 查看文本文件內容
hadoop fs -cat <文件路徑>
  • 複製
hadoop fs -cp <文件(夾)路徑> <拷貝後的文件夾路徑>
  • 刪除
hadoop fs -rm -r <要刪除的文件夾路徑>
  • 查看分區情況
Hadoop fs -df [選項]

選項:

選項 說明
-h 存儲單位以比較友好的方式展現,說白了就是把單位轉換成GB,MB等
  • 查看文件夾的使用情況
hadoop fs -du [選項] <路徑>

選項:

選項 說明
-h 同df,存儲單位以比較友好的方式展現,說白了就是把單位轉換成GB,MB等
  • 設置文件副本數量
hadoop fs -setrep <副本數量n> <HDFS中文件路徑>

注意

設置的數量一定要小於DataNode的數量,否則只能創建DataNode個數的副本

HDFS上傳操作

  • 上傳文件到HDFS(複製本地文件到HDFS)
hadoop fs -copyFromLocal <本地文件路徑> <HDFS文件路徑>

或者

hadoop fs -put <本地文件路徑> <HDFS文件路徑> 

注意

-copyFromLocal-put的作用是一樣的,在底層copyFromLocal其實是put的一個子類,但是這個子類什麼其他的功能都沒有實現,只是換了一個名字而已

  • 剪切本地的文件到HDFS

其實moveFromLocalcopyFromLocal唯一的區別就是一個是剪切,一個是複製

hadoop fs -moveFromLocal <本地文件路徑> <HDFS文件路徑>
  • 追加內容到HDFS中的文件中
hadoop -appendToFile <本地文件路徑> <要追加到的文件路徑>

HDFS下載操作

  • 下載文件(複製HDFS文件到本地)

下載同上傳一樣,有兩個方法

hadoop fs -copyToLocal <HDFS中的文件路徑> <下載到本地的文件路徑>

或者

hadoop fs -get <HDFS中的文件路徑> <下載到本地的文件路徑>
  • 下載多個文件到本地,並合併成一個文件
hadoop fs -getmerge <HDFS中的文件路徑1> <HDFS中的文件路徑2> ... <HDFS中的文件路徑n> <本地合併後的文件路徑>

HDFS的API操作

開發軟件中開發環境的搭建

  1. 首先,新建一個Maven項目(不需要官方模板,直接新建簡單項目即可)

  2. 然後引入依賴

<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.7</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-client</artifactId>
			<version>2.7.7</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-hdfs</artifactId>
			<version>2.7.7</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>
  1. 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

API測試

  1. 上傳一個文件到HDFS
//注意:導入的包都是org.apache.hadoop中的
@Test
public void put() throws IOException, InterruptedException {
	//獲取文件系統,參數: ①URI,②配置(其實就是獲取了Hadoop中的core-site.xml文件中的信息),③雲主機中的用戶名
    FileSystem fileSystem = FileSystem.get(URI.create("hdfs://<NameNode主機地址>:9000"),new Configuration(),"<Hadoop主機上的用戶名>");
    //上傳文件, 參數: ①本地的文件路徑,②Hadoop中存儲的路徑
    fileSystem.copyFromLocalFile(new Path("<本機上的文件路徑>"), new Path("/"));
    //關流
    fileSystem.close();
}

如果執行結果返回的是0,說明上傳成功

  1. 下載也是一樣
@Test
public void put() throws IOException, InterruptedException {
	//獲取文件系統,參數: ①URI,②配置(其實就是獲取了Hadoop中的core-site.xml文件中的信息),③雲主機中的用戶名
    FileSystem fileSystem = FileSystem.get(URI.create("hdfs://<NameNode主機地址>:9000"),new Configuration(),"<Hadoop主機上的用戶名>");
    //上傳文件, 參數: ①本地的文件路徑,②Hadoop中存儲的路徑
    fileSystem.copyFromLocalFile(new Path("/1.txt"),new Path("<本機上的文件路徑>"));
    //關流
    fileSystem.close();
}
  1. 重命名
@Test
public void rename() throws IOException, InterruptedException {
    FileSystem fileSystem = FileSystem.get(URI.create("hdfs://<NameNode主機地址>:9000"), new Configuration(), "<Hadoop主機上的用戶名>");
    fileSystem.rename(new Path("<要重命名的文件路徑>"), new Path("<重命名之後文件路徑>"));
    fileSystem.close();
}
  1. 刪除
@Test
public void del() throws IOException, InterruptedException {
    FileSystem fileSystem = FileSystem.get(URI.create("hdfs://<NameNode主機地址>:9000"), new Configuration(), "<Hadoop主機上的用戶名>");
    //delete方法返回一個boolean值表示是否刪除成功, 參數: ①HDFS中的文件路徑,②是否遞歸刪除
    boolean delete = fileSystem.delete(new Path("<HDFS中文件路徑>"), true);
    if (delete) {
    	System.out.println("刪除成功");
    } else {
    	System.out.println("刪除失敗");
    }
    fileSystem.close();
}
  1. 查看文件(夾)信息
@Test
public void read() throws IOException, InterruptedException {
    FileSystem fileSystem = FileSystem.get(URI.create("hdfs://<NameNode主機地址>:9000"), new Configuration(), "<Hadoop主機上的用戶名>");
    FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
    for (FileStatus fileStatus:fileStatuses) {
        //判斷是否是一個文件
            if (fileStatus.isFile()) {
                //獲取文件路徑
                System.out.print("文件路徑"+fileStatus.getPath()+"\t");
                //獲取文件長度
                System.out.println("文件長度"+fileStatus.getLen());
            } else {
                System.out.println("這是一個文件夾,路徑:"+fileStatus.getPath());
            }
    }
}

總之可以獲取各種各樣的文件信息,輸入fileStatus.,後面會自動提示很多方法,大家可以自己去試一下,這裏就不一一舉例了

除此之外,如果只是想獲取指定HDFS目錄下的文件內容(可以選擇是否遞歸),可以使用listFiles方法,該方法返回一個迭代器,可以通過hadNext方法判斷是否有下一個文件,然後處理每個文件,使用listFiles還可以查看每個文件所在塊的信息

@Test
public void getFiles() throws IOException, InterruptedException {
    FileSystem fileSystem = FileSystem.get(URI.create("hdfs://192.168.8.101:9000"), new Configuration(), "alasky");
    //創建一個迭代器,接收HDFS指定目錄下的所有文件,參數:①HDFS文件路徑,②是否遞歸
    RemoteIterator<LocatedFileStatus> locatedFileStatusRemoteIterator = fileSystem.listFiles(new Path("/"), true);
    //查看迭代器中是否還有下一個內容
    while (locatedFileStatusRemoteIterator.hasNext()) {
        System.out.print("文件信息: ");
        //接收迭代器中的當前文件
        LocatedFileStatus locatedFileStatus = locatedFileStatusRemoteIterator.next();
        System.out.println(locatedFileStatus.getPath());
        System.out.println("塊信息:");
        //創建一個BlockLocation數組,接收這給文件存儲的塊信息
        BlockLocation[] blockLocations=locatedFileStatus.getBlockLocations();
        for (BlockLocation blockLocation : blockLocations) {
            //獲取每個塊所在的主機
            String[] hosts = blockLocation.getHosts();
            for (String host : hosts) {
            	System.out.println(host);
            }
        }
    }
    fileSystem.close();
}

說明 爲什麼使用listStatus()方法獲取的FileStatus沒有塊信息,而使用listFiles()方法獲取的BlockLocation有塊信息?

因爲使用listStatus獲取的內容不止有文件,還有文件夾(目錄),但是目錄並沒有塊(block)的概念,只有文件纔有,如果獲取文件夾的塊信息會出錯,所以FileStatus並沒有獲取塊信息的方法

這裏說明一下,其實空文件也沒有佔用block的,但是Hadoop的API裏面默認所有的文件都有block


HDFS上傳和下載的流程

客戶端上傳文件到HDFS流程(寫流程)

在這裏插入圖片描述

  • 成功上傳的流程
  1. 首先Client(客戶端)讀取要上傳的文件
  2. 然後Client獲取HDFS集羣的信息(Distributed File System)
  3. Client向NameNode發起上傳文件的請求
  4. NameNode檢查該請求是否合法,如是否存在相同路徑的文件,客戶端是否有上傳文件的權限,然後將檢查結果返回給Client
  5. Client收到NameNode的允許上傳的響應之後,將要上傳的文件進行邏輯切分(不是真正的切分),如果文件不需要切分,那就不切分
  6. Client開啓一個輸出流(FSDataOutputStream),請求上傳第一個Block(塊),然後NameNode返回給Client一個DataNode的List,即客戶端要把該Block上傳到這幾個DataNode中,設置的副本有幾個,List中的DataNode個數就有幾個
  7. 然後Client向List中的第一個DataNode發送建立通道的請求,第一個收到請求之後再向第二個DataNode發送請求,直到List的最後一個DataNode收到請求,然後返回響應給上一個DataNode,直到返回響應給第一個DataNode,最後返回響應給Client(即串聯請求和響應)
  8. 然後Client開始向LIst中的第一個DataNode發送Packet,即第一個切塊的數據,每個Packet大小64kb
  9. List中的第一個DataNode收到Packet後,一邊向磁盤中寫,一邊將該Packet發給第2個DataNode,以此類推,直到最後一個DataNode寫入磁盤成功,然後再串聯響應到Client.注意Packet不是一個一個的發送,而是一次發送一個隊列的Packet以提高效率
  10. 第1個Block發送成功之後,再發送第2個Block,(從第6步開始),注意每次上傳Block的DataNode可能不一樣,直到最後一個Block傳輸完畢,然後Client發送通知給NameNode,告知NameNode數據已經傳輸完畢
  11. NameNode收到傳輸完畢的數據之後,將本次傳輸記錄到元數據中,然後斷開數據流的連接
  • 出現問題的解決
  1. 如果在Client和DataNode建立通道的過程出現問題,那麼本次上傳就失敗
  2. 如果在Client向List中第一個DataNode傳輸數據的過程中出現問題,那麼本次上傳失敗
  3. 如果List中第一個DataNode上傳成功但是在後續的備份過程中失敗(即第一個DataNode向第二個DataNode傳輸失敗),那麼文件上傳會繼續,但是在HDFS集羣中會觸發備份,從而將第一個DataNode中的Block備份到其他DataNode

說明

  1. NameNode是通過 **機架感知策略 **選取返回給Client的DataNode列表的,介紹如下:
    1. NameNode會選取離Client最近的一個DataNode(不是距離最近,而是在網絡拓撲中最近),如果有多個DataNode距離Client的網絡拓撲距離都一樣近,那就隨機選取一個,然後把選中的這個DataNode作爲List的第一個
    2. 選出節點中第一個DataNode之後,第二個DataNode選取相同機架上的其他一個節點
    3. 第三個DataNode選取不同機架上的一個節點

從HDFS下載文件的流程(讀流程)

在這裏插入圖片描述

  • 成功下載的流程
  1. Client獲取HDFS集羣的信息(Distributed File System)
  2. Client向NameNode發起下載文件的請求
  3. NameNode檢查該請求是否合法,如HDFS中是否存在該文件路徑,Client是否有讀的權限等,然後將結果返回給Client
  4. Client收到NameNode的允許下載的響應之後,Client開啓一個輸入流(FSDataInputStream),然後NameNode返回存儲該文件第一個Block副本的幾個DataNode列表給Client
  5. Client向列表中的第一個DataNode發送建立通道的請求,然後下載文件,下載完第一個Block之後,Client再向NameNode請求下載第二個,直到下載完成
  6. 下載完成之後Client會通知NameNode下載完成,然後NameNode關閉流的連接
  • 出現問題的解決
  1. 如果Client向List中的第一個DataNode建立請求失敗,那麼就會再向第二個發送建立連接的請求,如果List中的所有DataNode全部建立連接失敗,那麼本次下載就失敗

元數據

元數據介紹

在HDFS中的每個塊的信息,都會被NameNode記錄到元數據中,而且上面說過的讀寫操作,Client都會先從NameNode獲取塊的信息,這些信息就存儲在元數據當中.

元數據會分別存儲在內存和磁盤中,存在內存中的元數據是爲了快速讀取信息,而存儲在磁盤中是爲了備份,方便恢復

在磁盤中的元數據是以fsimage的文件存在,但是如果每次操作都在fsimage中更新,就會極大的降低效率,但是如果隔一段時間才更新一次,如果更新之前NameNode出現宕機,那麼最後一次更新之後的元數據有沒法保存,所以NameNode除了fsimage之外,還會將每次增刪改操作以日誌的形式記錄在edits文件中,edits文件只做追加操作(append),不做修改,所以效率很高,然後每隔一段時間,就將edits文件中的新內容合併到fsimage中

如果出現宕機,NameNode會結合fsimage文件和edits文件來獲取到全部的元數據,然後重新加載到內存中,以保證元數據的完整性

總結一下,元數據會存儲在內存中和磁盤中,磁盤中的元數據存在fsimage文件裏,每次寫操作都會記錄日誌,存在edits文件裏

注意

由於fsimage文件每隔一段時間纔會更新一次,所以fsimage文件中的元數據和內存中的元數據不是實時同步的

元數據存儲的內容

  • 數據塊的虛擬存儲路徑(注意不是真實路徑)
  • 文件的切塊數量
  • 數據塊的複本數量
  • 文件權限

說明

可以看到fsimage中沒有存儲數據塊的實際物理存儲路徑,這是因爲在HDFS啓動之後,DataNode每隔一段時間(默認1h)之後會向NameNode上報該DataNode存儲的塊信息,然後由NameNode加載到內存中

元數據的合併流程

在這裏插入圖片描述

  1. 第一次啓動NameNode格式化後,創建Fsimage和Edits文件。如果不是第一次啓動,直接加載編輯日誌和鏡像文件到內存
  2. Client(客戶端) 發送寫請求,當NameNode接收到寫請求之後,會先給這次操作分配一個全局事務id將該請求記錄到edits_inprogess文件中,如果記錄成功,則將該請求同步更新到內存中,修改內存中的元數據,內存修改完成之後會給客戶端返回一個ack表示成功
  3. 在觸發一定的條件之後,便會將新的元數據更新到fsimage文件中,條件如下,滿足其中的一個條件即可觸發fsimage的更新
  • 空間閾值:當edits_inprogress文件達到指定大小的時候就會觸發更新(默認是64M),
    大小可以由core-site.xml配置文件中的fs.checkpoint.size屬性來指定,默認單位是字節
  • 時間閾值:當距離上一次更新達到指定間隔(默認是1h)時候的時候就會觸發更新,大小
    可以由fs.checkpoint.period來指定,默認單位是秒
  • 重啓更新:NameNode重啓之後,會自動的將edits_inprogress中的操作更新到
    fsimage中
  • 強制更新:使用hadoop dfsadmin -rollEdits命令來手動更新
  1. 更新fsimage時,如果集羣中存在.SecondaryNameNode節點,就會將edits和fsimage的合併工作在.SecondaryNameNode中進行,如果沒有,就會在NameNode本地進行

    在更新的時候,會將edits_inprogress重命名爲edits_XXX-XXX(XXX-XXX是這個edits文件所記錄的全局事務id的範圍),同時產生一個新的edits_inprogress,然後將重命名之後的edits文件和fsimage文件發送到.SecondaryNameNode中,由SecondaryNameNode進行合併

  2. SecondaryNameNode合併完成之後,將新的fsimage文件發回到NameNode

注意

爲了數據的可靠性和完整性,在NameNode中會保存2個fsimage文件,一個是最新的fsimage文件,一個是上一個fsimage文件,當SecondaryNameNode將新的fsimage文件發送過來時,NameNode會自動刪除最舊的那個fsimage文件

查看元數據內容

  • 查看fsimage
hdfs oiv -p <文件格式> -i <fsimage文件路徑> -o <轉換文件格式之後輸出到的路徑>

然後查看輸出的文件即可

一般將fsimage轉換爲xml格式文件

舉例

hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/hadoop-2.7.7/fsimage.xml
  • 查看edits
hdfs oev -p <文件格式> -i <edits日誌文件的路徑> -o <轉換文件格式之後輸出到的路徑>

DataNode

DataNode的工作流程

在這裏插入圖片描述

  1. 一個數據塊在DataNode上以文件形式存儲在磁盤上,包括兩個文件,一個是數據本身,一個是元數據包括數據塊的長度,塊數據的校驗和,以及時間戳
  2. DataNode啓動之後,如果是第一次加入集羣,會向NameNode註冊,通過註冊後,DataNode每隔一小時就向NameNode上報該DataNode上所有塊的信息
  3. DataNode每隔3秒向NameNode發送一次心跳,以通知NameNode自己還存活,如果NameNode超過10分鐘沒有收到某個DataNode的心跳,就任務該DataNode宕機,就會把該節點上的數據再備份一份到其他節點

DataNode多目錄配置

如果有一天我們在某個DataNode節點上新添加了一塊硬盤,想要也將數據存儲到這塊硬盤中,那麼可以再從hdfs-site.xml配置文件中添加多個DataNode的存儲路徑,配置如下

<property>
    <name>dfs.datanode.data.dir</name>
	<value>file:///${hadoop.tmp.dir}<路徑1>,file:///${hadoop.tmp.dir}<路徑2></value>
</property>

黑名單和白名單

黑名單

介紹

顧名思義,黑名單就是不允許指定的DataNode接入集羣

配置

  1. 首先創建一個文件存儲黑名單的文件(名稱可以自定義),然後在裏面寫上黑名單的地址,直接把地址寫上就可以
  2. 然後在hdfs-site.xml配置文件中增加dfs.hosts.exclude屬性
<property>
	<name>dfs.hosts.exclude</name>
    <value><黑名單文件路徑></value>
</property>
  1. 刷新NameNode和ResourceManager
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes

注意

配置了黑名單的DataNode節點,仍舊可以連接集羣,只不過是NameNode不在爲其分配數據塊的存儲

白名單Decommission In Progress

介紹

白名單就是隻允許指定的DataNode連接集羣,可以有效防止其他節點混入,保證集羣的數據安全

配置

  1. 首先創建一個文件存儲黑名單的文件(名稱可以自定義),然後在裏面寫上黑名單的地址,直接把地址寫上就可以
  2. 然後在hdfs-site.xml配置文件中增加dfs.hosts屬性
<property>
	<name>dfs.hosts</name>
	<value><白名單文件路徑></value>
</property>
  1. 刷新NameNode和ResourceManager
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes

節點的擴展和退役

節點擴展

擴展新的DataNode節點很容易,只需要配置好分佈式的那些配置(尤其是指定好NameNode),DataNode就會自動向NameNode發送註冊請求,然後加入集羣

注意

不需要在配置中配置slave就可以添加新的節點,但是爲了下次可以直接從NameNode啓動新的DataNode節點,還是建議在slave裏添加該新DataNode節點

節點退役

如果想要是某個DataNode節點退出集羣,有多種方式可以選擇

  • 直接關閉連接

直接將要退出的DataNode節點關機或者斷開與NameNode的連接,一關時間之後NameNode會認爲該節點宕機,然後就會自動剔除該節點

但是這種方法需要額外的等NameNode檢測(10分鐘),而且不能重新啓動該DataNode節點,一旦重新啓動或者恢復連接,就會重新加入集羣

  • 設置黑名單

配置一個黑名單,把該節點的地址寫進去,然後刷新NameNode和ResourceManager,該DataNode就會自動將自身的文件塊備份到其他節點,然後退出集羣,但是就像剛剛黑名單介紹的,此時DataNode仍會與NameNode保持連接,只不過是不再分配資源了

在生產環境中,推薦使用黑名單的方式退役節點

  • 設置白名單

配置一個白名單,然後白名單中不加上該節點的名字,刷新NameNode和ResourceManager,該節點就會被強制退出集羣,並且關閉DataNode進程


HDFS小文件處理

小文件在HDFS中可以說是噩夢般的存在,因爲每個小文件在HDFS中也佔用一個塊和一個元數據,而且多個小文件的元數據也會佔用大量的NameNode內存,尋址也很慢,所以HDFS中我們不建議存儲小文件

如果沒有辦法避免小文件,Hadoop也提供了相應的處理措施,就是把多個小文件打包成一個har包,這個包在HDFS中只佔用一個文件的元數據,而且尋址和讀取也比較方便

  1. 首先啓動yarn進程
start-yarn.sh
  1. 將某個目錄裏的的所有文件打包成一個har包
<Hadoop安裝目錄>/bin/hadoop archive -archiveName <自定義包名>.har –p  <打包之前的路徑> <打包後的har包路徑>

然後將har包上傳到HDFS就可以了,例如:

bin/hadoop archive -archiveName input.har –p  ./input   ./output
  1. 查看har包內容
hadoop fs -lsr <har包路徑>
  1. 解包
hadoop fs -cp har://<har包路徑> <解壓後的路徑>

taNode仍會與NameNode保持連接,只不過是不再分配資源了

在生產環境中,推薦使用黑名單的方式退役節點

  • 設置白名單

配置一個白名單,然後白名單中不加上該節點的名字,刷新NameNode和ResourceManager,該節點就會被強制退出集羣,並且關閉DataNode進程


HDFS小文件處理

小文件在HDFS中可以說是噩夢般的存在,因爲每個小文件在HDFS中也佔用一個塊和一個元數據,而且多個小文件的元數據也會佔用大量的NameNode內存,尋址也很慢,所以HDFS中我們不建議存儲小文件

如果沒有辦法避免小文件,Hadoop也提供了相應的處理措施,就是把多個小文件打包成一個har包,這個包在HDFS中只佔用一個文件的元數據,而且尋址和讀取也比較方便

  1. 首先啓動yarn進程
start-yarn.sh
  1. 將某個目錄裏的的所有文件打包成一個har包
<Hadoop安裝目錄>/bin/hadoop archive -archiveName <自定義包名>.har –p  <打包之前的路徑> <打包後的har包路徑>

然後將har包上傳到HDFS就可以了,例如:

bin/hadoop archive -archiveName input.har –p  ./input   /
  1. 查看har包內容
hadoop fs -lsr har:///<har包路徑>
  1. 解包
hadoop fs -cp har:///<har包路徑> <解壓後的路徑>
發佈了29 篇原創文章 · 獲贊 3 · 訪問量 1892
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章