HDFS(全稱:Hadoop Distribute File System)分散式檔案系統,是Hadoop核心組成。
分塊儲存
HDFS中的檔案在物理上是分塊儲存的,塊的大小可以通過設定引數來規定;Hadoop2.x版本預設的block大小是128M
名稱空間
HDFS支援傳統的層次性檔案組織結構。使用者或者應用程式可以建立目錄,然後將檔案儲存在這些目錄裡。檔案系統名稱空間的層次結構和大多數現有的檔案系統類似:使用者可以建立、刪除、移動或重新命名這些檔案。
NameNode負責維護檔案系統的名稱空間,任何對檔案系統名稱空間或屬性的修改都被NameNode記錄下來。
NameNode後設資料
我們把目錄結構及檔案分塊位置資訊叫做後設資料。NameNode的後設資料記錄每一個檔案對應的block資訊。
DataNode資料儲存
檔案的各個block的具體儲存管理由DataNode負責。一個block會有多個DataNode來儲存,DataNode會定時向NameNode來彙報自己持有的block資訊。
副本機制
為了容錯,檔案的所有block都會有副本。每隔檔案的block大小和副本數都是可設定的。副本數預設是3個。
一次寫入,多次讀出
HDFS是設計成適應一次寫入,多次讀出的場景,且不支援檔案的隨機修改。正因為如此,HDFS適合用來做巨量資料分析的底層儲存服務,而不適合做網路硬碟等應用。(修改不方便,延遲大)
NameNode:Hdfs叢集的管理者
DataNode:NameNode下達命令,DataNode執行實際操作
Client:使用者端
寫資料流程:
hadoop fs
#檢視rm的幫助資訊
hadoop fs -help rm
hadoop fs -ls /
hadoop fs -mkdir -p /test/data
hadoop fs -moveFromLocal ./word.txt /test/data
hadoop fs -appendToFile test.txt /test/data/word.txt
hadoop fs -cat /test/data/word.txt
hadoop fs -chmod 666 /test/data/word.txt
hadoop fs -chown root:root /test/data/word.txt
hadoop fs -copyFromLocal test.txt /test
hadoop fs -copyToLocal /test/data/word.txt /opt
hadoop fs -cp /test/data/word.txt /test/input/t.txt
hadoop fs -mv /test/input/t.txt /
hadoop fs -get /t.txt ./
hadoop fs -put ./yarn.txt /user/root/test/
hadoop fs -tail /t.txt
hadoop fs -rm /t.txt
hadoop fs -rmdir /test
hadoop fs -du -s -h /test
hadoop fs -du -h /test
hadoop fs -setrep 10 /lagou/bigdata/hadoop.txt
注意:這裡設定的副本數只是記錄在NameNode的後設資料中,是否真的會有這麼多副本,還得看DataNode的數量。因為目前只有3臺裝置,最多也就3個副本,只有節點數的增加到10臺時,副本數才能達到10.
環境準備
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>${hadoop-version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop-version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>${hadoop-version}</version>
</dependency>
將hdfs-site.xml(內容如下)拷貝到專案的resources下
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
引數優先順序排序:(1)程式碼中設定的值 >(2)使用者自定義組態檔 >(3)伺服器的預設設定
HDFS Java API
@Test
public void testCopyFromLocalFile() throws Exception{
Configuration conf = new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.56.103:9000"),conf,"root");
fs.copyFromLocalFile(new Path("e://aa.txt"),new Path("/cc.txt"));
fs.close();
}
為了方便,下面的範例就隱藏構建FileSystem的過程
@Test
public void testCopyToLocalFile() throws Exception{
fs.copyToLocalFile(false,new Path("/aa.txt"),new Path("e://cd.txt"),true);
}
@Test
public void testDelete() throws Exception{
fs.delete(new Path("/aa.txt"),true);
}
public void testList() throws IOException {
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
while (listFiles.hasNext()){
LocatedFileStatus status = listFiles.next();
//檔名稱
System.out.println(status.getPath().getName());
System.out.println(status.getLen());
System.out.println(status.getPermission());
System.out.println(status.getGroup());
BlockLocation[] blockLocations = status.getBlockLocations();
Stream.of(blockLocations).forEach(
block->{
String[] hosts = new String[0];
try {
hosts = block.getHosts();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(Arrays.asList(hosts));
}
);
System.out.println("-----------華麗的分割線----------");
}
}
@Test
public void testListStatus() throws IOException {
FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
Stream.of(fileStatuses).forEach(fileStatus -> {
String name = fileStatus.isFile() ? "檔案:" + fileStatus.getPath().getName() : "資料夾:"+fileStatus.getPath().getName();
System.out.println(name);
});
}
@Test
public void testIOUpload() throws IOException {
FileInputStream fis = new FileInputStream(new File("e://11.txt"));
FSDataOutputStream fos = fs.create(new Path("/io_upload.txt"));
IOUtils.copyBytes(fis,fos,new Configuration());
IOUtils.closeStream(fis);
IOUtils.closeStream(fos);
}
@Test
public void testDownload() throws IOException{
FSDataInputStream fis = fs.open(new Path("/io_upload.txt"));
FileOutputStream fos = new FileOutputStream(new File("e://11_copy.txt"));
IOUtils.copyBytes(fis,fos,new Configuration());
IOUtils.closeStream(fis);
IOUtils.closeStream(fos);
}
@Test
public void readFileSeek() throws IOException{
FSDataInputStream fis = fs.open(new Path("/io_upload.txt"));
IOUtils.copyBytes(fis,System.out,1024,false);
//從頭再次讀取
fis.seek(0);
IOUtils.copyBytes(fis,System.out,1024,false);
IOUtils.closeStream(fis);
}
HDFS檔案許可權問題
HDFS的檔案許可權和linux系統的檔案許可權機制類似。如果在linux系統中root使用者使用hadoop命令建立了一個檔案,那麼該檔案的owner就是root。
當出現許可權問題時,解決方法有如下幾種:
#新增如下屬性
<property>
<name>dfs.permissions</name>
<value>true</value>
</property>
hadoop fs -chmod -R 777 /