Hadoop(6)
HDFS
文章目錄
HDFS
HDFS介紹
HDFS的定義
HDFS(Hadoop Distributed File System),即Hadoop分佈式文件系統
HDFS由多臺主機搭建服務器集羣來實現,集羣中的服務器分別負責不同的功能
HDFS通過目錄樹來定位文件
HDFS的優缺點
優點
- 採用多副本機制,如果一個副本丟失,可以自動恢復,容錯性高
- 適合處理大數據
- 可以構建在廉價的機器上,隨時航向擴展,通過多副本機制提高可靠性
缺點
- 不適合低延遲訪問數據
- 無法高效的對大量小文件進行存儲
- 存儲大量的小文件會佔用大量的NameNode內存
- 小文件的尋址時間會浪費大量的時間,從而降低效率(一般來說尋址時間<傳輸時間的 1%比較合適)
- 不支持併發寫入和文件的修改
- 一個文件只能單線程寫入,不允許多線程操作
- 僅支持數據的追加,不支持文件的修改
HDFS的應用場景
HDFS適合一次寫入,多次讀取,並且不支持文件的修改,適合做數據分析
HDFS的組成
HDFS由NameNode,DataNode,Client和SecondaryNameNode組成,在
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開發,所以操作不太一樣
雖然操作不同,但是配置的思路給大家列舉一下,如果大家不會配置,就根據下面的步驟百度一下:
- 在開發軟件中配置Maven
- 將Hadoop的軟件包(zip或者tar.gz)解壓到自己的磁盤中,不能有中文路徑
- 配置Hadoop的環境變量
- 配置完之後重啓一下電腦
HDFS的Shell命令
注意
1. 在執行命令時,使用bin/hadoop fs
和bin/hdfs dfs
的效果是一樣的,這是因爲dfs是fs的實現類,它們底層調用的jar包都是一樣的
2. HDFS的命令和Linux的命令很像,如果熟悉Linux指令,HDFS的Shell操作可以很快上手
3. 下面所有的命令演示,涉及到HDFS文件(夾)的變更,都可以通過瀏覽器訪問NameNode50070端口查看HDFS的文件系統詳情來查看命令執行的結果
- 查看fs的所有命令
hadoop fs
也可以通過下面的指令查看
hadoop fs --help
注意
1. 同樣的hadoop dfs
和hadoop dfs --help
也一樣,下面我們就不把fs
和dfs
一一做列舉了,我們統一使用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
其實moveFromLocal
與copyFromLocal
唯一的區別就是一個是剪切,一個是複製
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操作
開發軟件中開發環境的搭建
-
首先,新建一個Maven項目(不需要官方模板,直接新建簡單項目即可)
-
然後引入依賴
<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>
- 在
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測試
- 上傳一個文件到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
,說明上傳成功
- 下載也是一樣
@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();
}
- 重命名
@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();
}
- 刪除
@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();
}
- 查看文件(夾)信息
@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流程(寫流程)
- 成功上傳的流程
- 首先Client(客戶端)讀取要上傳的文件
- 然後Client獲取HDFS集羣的信息(Distributed File System)
- Client向NameNode發起上傳文件的請求
- NameNode檢查該請求是否合法,如是否存在相同路徑的文件,客戶端是否有上傳文件的權限,然後將檢查結果返回給Client
- Client收到NameNode的允許上傳的響應之後,將要上傳的文件進行邏輯切分(不是真正的切分),如果文件不需要切分,那就不切分
- Client開啓一個輸出流(FSDataOutputStream),請求上傳第一個Block(塊),然後NameNode返回給Client一個DataNode的List,即客戶端要把該Block上傳到這幾個DataNode中,設置的副本有幾個,List中的DataNode個數就有幾個
- 然後Client向List中的第一個DataNode發送建立通道的請求,第一個收到請求之後再向第二個DataNode發送請求,直到List的最後一個DataNode收到請求,然後返回響應給上一個DataNode,直到返回響應給第一個DataNode,最後返回響應給Client(即串聯請求和響應)
- 然後Client開始向LIst中的第一個DataNode發送Packet,即第一個切塊的數據,每個Packet大小64kb
- List中的第一個DataNode收到Packet後,一邊向磁盤中寫,一邊將該Packet發給第2個DataNode,以此類推,直到最後一個DataNode寫入磁盤成功,然後再串聯響應到Client.注意Packet不是一個一個的發送,而是一次發送一個隊列的Packet以提高效率
- 第1個Block發送成功之後,再發送第2個Block,(從第6步開始),注意每次上傳Block的DataNode可能不一樣,直到最後一個Block傳輸完畢,然後Client發送通知給NameNode,告知NameNode數據已經傳輸完畢
- NameNode收到傳輸完畢的數據之後,將本次傳輸記錄到元數據中,然後斷開數據流的連接
- 出現問題的解決
- 如果在Client和DataNode建立通道的過程出現問題,那麼本次上傳就失敗
- 如果在Client向List中第一個DataNode傳輸數據的過程中出現問題,那麼本次上傳失敗
- 如果List中第一個DataNode上傳成功但是在後續的備份過程中失敗(即第一個DataNode向第二個DataNode傳輸失敗),那麼文件上傳會繼續,但是在HDFS集羣中會觸發備份,從而將第一個DataNode中的Block備份到其他DataNode
說明
- NameNode是通過 **機架感知策略 **選取返回給Client的DataNode列表的,介紹如下:
- NameNode會選取離Client最近的一個DataNode(不是距離最近,而是在網絡拓撲中最近),如果有多個DataNode距離Client的網絡拓撲距離都一樣近,那就隨機選取一個,然後把選中的這個DataNode作爲List的第一個
- 選出節點中第一個DataNode之後,第二個DataNode選取相同機架上的其他一個節點
- 第三個DataNode選取不同機架上的一個節點
從HDFS下載文件的流程(讀流程)
- 成功下載的流程
- Client獲取HDFS集羣的信息(Distributed File System)
- Client向NameNode發起下載文件的請求
- NameNode檢查該請求是否合法,如HDFS中是否存在該文件路徑,Client是否有讀的權限等,然後將結果返回給Client
- Client收到NameNode的允許下載的響應之後,Client開啓一個輸入流(FSDataInputStream),然後NameNode返回存儲該文件第一個Block副本的幾個DataNode列表給Client
- Client向列表中的第一個DataNode發送建立通道的請求,然後下載文件,下載完第一個Block之後,Client再向NameNode請求下載第二個,直到下載完成
- 下載完成之後Client會通知NameNode下載完成,然後NameNode關閉流的連接
- 出現問題的解決
- 如果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加載到內存中
元數據的合併流程
- 第一次啓動NameNode格式化後,創建Fsimage和Edits文件。如果不是第一次啓動,直接加載編輯日誌和鏡像文件到內存
- Client(客戶端) 發送寫請求,當NameNode接收到寫請求之後,會先給這次操作分配一個全局事務id將該請求記錄到edits_inprogess文件中,如果記錄成功,則將該請求同步更新到內存中,修改內存中的元數據,內存修改完成之後會給客戶端返回一個ack表示成功
- 在觸發一定的條件之後,便會將新的元數據更新到fsimage文件中,條件如下,滿足其中的一個條件即可觸發fsimage的更新
- 空間閾值:當edits_inprogress文件達到指定大小的時候就會觸發更新(默認是64M),
大小可以由core-site.xml配置文件中的fs.checkpoint.size
屬性來指定,默認單位是字節 - 時間閾值:當距離上一次更新達到指定間隔(默認是1h)時候的時候就會觸發更新,大小
可以由fs.checkpoint.period
來指定,默認單位是秒 - 重啓更新:NameNode重啓之後,會自動的將edits_inprogress中的操作更新到
fsimage中 - 強制更新:使用
hadoop dfsadmin -rollEdits
命令來手動更新
-
更新fsimage時,如果集羣中存在.SecondaryNameNode節點,就會將edits和fsimage的合併工作在.SecondaryNameNode中進行,如果沒有,就會在NameNode本地進行
在更新的時候,會將edits_inprogress重命名爲edits_XXX-XXX(XXX-XXX是這個edits文件所記錄的全局事務id的範圍),同時產生一個新的edits_inprogress,然後將重命名之後的edits文件和fsimage文件發送到.SecondaryNameNode中,由SecondaryNameNode進行合併
-
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的工作流程
- 一個數據塊在DataNode上以文件形式存儲在磁盤上,包括兩個文件,一個是數據本身,一個是元數據包括數據塊的長度,塊數據的校驗和,以及時間戳
- DataNode啓動之後,如果是第一次加入集羣,會向NameNode註冊,通過註冊後,DataNode每隔一小時就向NameNode上報該DataNode上所有塊的信息
- 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接入集羣
配置
- 首先創建一個文件存儲黑名單的文件(名稱可以自定義),然後在裏面寫上黑名單的地址,直接把地址寫上就可以
- 然後在hdfs-site.xml配置文件中增加dfs.hosts.exclude屬性
<property>
<name>dfs.hosts.exclude</name>
<value><黑名單文件路徑></value>
</property>
- 刷新NameNode和ResourceManager
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes
注意
配置了黑名單的DataNode節點,仍舊可以連接集羣,只不過是NameNode不在爲其分配數據塊的存儲
白名單Decommission In Progress
介紹
白名單就是隻允許指定的DataNode連接集羣,可以有效防止其他節點混入,保證集羣的數據安全
配置
- 首先創建一個文件存儲黑名單的文件(名稱可以自定義),然後在裏面寫上黑名單的地址,直接把地址寫上就可以
- 然後在hdfs-site.xml配置文件中增加dfs.hosts屬性
<property>
<name>dfs.hosts</name>
<value><白名單文件路徑></value>
</property>
- 刷新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中只佔用一個文件的元數據,而且尋址和讀取也比較方便
- 首先啓動yarn進程
start-yarn.sh
- 將某個目錄裏的的所有文件打包成一個har包
<Hadoop安裝目錄>/bin/hadoop archive -archiveName <自定義包名>.har –p <打包之前的路徑> <打包後的har包路徑>
然後將har包上傳到HDFS就可以了,例如:
bin/hadoop archive -archiveName input.har –p ./input ./output
- 查看har包內容
hadoop fs -lsr <har包路徑>
- 解包
hadoop fs -cp har://<har包路徑> <解壓後的路徑>
taNode仍會與NameNode保持連接,只不過是不再分配資源了
在生產環境中,推薦使用黑名單的方式退役節點
- 設置白名單
配置一個白名單,然後白名單中不加上該節點的名字,刷新NameNode和ResourceManager,該節點就會被強制退出集羣,並且關閉DataNode進程
HDFS小文件處理
小文件在HDFS中可以說是噩夢般的存在,因爲每個小文件在HDFS中也佔用一個塊和一個元數據,而且多個小文件的元數據也會佔用大量的NameNode內存,尋址也很慢,所以HDFS中我們不建議存儲小文件
如果沒有辦法避免小文件,Hadoop也提供了相應的處理措施,就是把多個小文件打包成一個har包,這個包在HDFS中只佔用一個文件的元數據,而且尋址和讀取也比較方便
- 首先啓動yarn進程
start-yarn.sh
- 將某個目錄裏的的所有文件打包成一個har包
<Hadoop安裝目錄>/bin/hadoop archive -archiveName <自定義包名>.har –p <打包之前的路徑> <打包後的har包路徑>
然後將har包上傳到HDFS就可以了,例如:
bin/hadoop archive -archiveName input.har –p ./input /
- 查看har包內容
hadoop fs -lsr har:///<har包路徑>
- 解包
hadoop fs -cp har:///<har包路徑> <解壓後的路徑>