HDFS--Hadoop分佈式文件系統


HDFS是什麼


HDFS設計特性和概念


HDFS,全稱是Hadoop Distributed Filesystem,是一個分佈式的文件系統,以流式數據訪問模式來存儲超大文件(一次寫入、屢次讀取)。java

HDFS具備例如如下設計特性:node

(1)處理超大文件,指的是GB、TB、PB級別的文件。百度、淘寶都有PB級別的HDFS,百度應該有國內最大規模的HDFS。幾十PB。apache

(2)流式數據訪問。一次寫入,屢次讀取,所處理的場景中,讀取整個數據的延遲比讀取第一條記錄的時間延遲重要。緩存

(3)執行在普通商用PC就能夠,比方3萬級別的普通PCserver(16-32G ECC內存,8-16核CPU)。tcp

(4)是爲高數據吞吐量優化的,以高時間延遲爲代價。分佈式

(5)推薦處理大量小文件。由於namenode將文件系統的元數據存儲在內存中,故文件總數受制於namenode節點內存。依據經驗。一個文件/文件夾/block大約佔用150本身,因此億級別文件還可以,10億級別內存就不夠了。工具

(6)對於寫入。僅僅能有一個寫入操做,也僅僅能把內容加入在文件的末尾。oop

概念:佈局

(1)數據塊(block)。默認64M,通常用128M,相對於文件系統塊(幾K字節大小)、磁盤塊(通常512畢節),HDFS的塊設計明顯大的多。這是爲了最小爲尋址開銷(尋址佔傳輸的百分比,比方:尋址10S。傳輸100MB/S。則尋址時間僅佔傳輸時間的1%)。性能

(2)名稱節點(namenode),是管理者,維護整個HDFS的文件系統樹及樹內所有的文件和文件夾。

(3)數據節點(datanode)。是文件系統工做節點,依據namenode調度,存儲並檢索數據塊,按期向namenode發送它所存儲的塊列表。

namenode單點風險的2種解決的方法:

(1)備份那些組成文件系統元數據持久狀態的文件,比方。持久狀態寫入本地磁盤的同一時候,寫入一個遠程的文件系統。

(2)執行一個輔助namecode,由於輔助namecode的滯後性,因此namecode損壞時,不免會丟失部分數據。


Hadoop抽象文件系統


Hadoop有一個抽象文件系統,由org.apache.hadoop.fs.FileSystem定義,HDSF僅僅是當中的一個實現。

Hadoop所實現的文件系統列表。大體例如如下圖所看到的:


Hadoop對文件系統提供了不少接口,它通常使用URI方案來選取合適的文件系統實例進行交互。。比方例如如下代碼:

String uri = "hdfs:///test/input/t/temperature.txt";
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), conf);

即時依據hdsfs://來推斷,使用hdfs.DistributedFileSystem。假設改爲file://,則使用fs.LocalFileSystem。


HDFS命令行接口


查看所有命令:

hadoop fs -help

hdfs fsck -help

也可以經過Web界面瀏覽文件系統:http://192.168.1.10:50070/


HDFS JAVA API


從Hadoop URL中讀取數據


import java.io.InputStream;
import java.net.URL;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.zookeeper.common.IOUtils;

public class URLCat {
	static {
		URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
	}

	public static void main(String[] args) throws Exception {
		InputStream in = null;
		try {
			in = new URL("hdfs:///test/input/t/temperature.txt").openStream();
			IOUtils.copyBytes(in, System.out, 4096, false);
		} finally {
			IOUtils.closeStream(in);
		}
	}
}

把hdfs換成file,則可以直接處理當前本地文件系統。

以上的方法是很是easy的,利用的java.net.URL對象打開數據流。從中讀取數據。但是這種方法有個限制,Java虛擬機僅僅能調用這個set方法一次,這個限制意味着假設有其它不受控制的第三方組件(已經聲明瞭URLStreamHandlerFactory實例),則咱們沒法再使用這樣的方法讀取數據。於是,不推薦使用。


經過FileSystem API讀取數據


import java.io.InputStream;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.zookeeper.common.IOUtils;

public class FileSystemCat {
	public static void main(String[] args) throws Exception {
		String uri = "hdfs:///test/input/t/temperature.txt";
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(URI.create(uri), conf);
		InputStream in = null;
		try {
			in = fs.open(new Path(uri));
			IOUtils.copyBytes(in, System.out, 4096, false);
		} finally {
			IOUtils.closeStream(in);
		}
	}
}
實際上,open方法返回的是FSDataInputStream對象,是繼承java.io.DataInputStream的一個特殊類。支持隨機訪問,由此可以從流的任何位置讀取數據。比方,咱們把try段的代碼變成:

			in = fs.open(new Path(uri));
			IOUtils.copyBytes(in, System.out, 4096, false);
			((FSDataInputStream) in).seek(0);	//go back to the start of the file
			IOUtils.copyBytes(in, System.out, 4096, false)
則,會顯示兩遍文件temperature.txt文件的內容。


將本地文件拷貝到Hadoop文件系統


import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;


public class FileCopyWithProgress {

	public static void main(String[] args) throws Exception
	{
		String localSrc = "/home/hadoop/temperature.txt";
		String dst = "hdfs:///test/input/t/temperature2.txt";
		InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(URI.create(dst),conf);
		OutputStream out = fs.create(new Path(dst),new Progressable(){
			public void progress(){
				System.out.println(".");
			}
		});
		IOUtils.copyBytes(in,out,4096,true);
	}
}

每次Hadoop調用progress()方法時。也就是每次講64KB數據包寫入datanode後。

列出文件


import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;

public class ListStatus {

	public static void main(String[] args) throws Exception {
		String uri = "hdfs:///test/input/t/";
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(URI.create(uri), conf);
		// 顯示一組路徑的文件夾列表的並集
		/*
		 * Path[] paths = new Path[] { new Path("hdfs:///test/input/t/"), new
		 * Path("hdfs:///test/input/wc") }; FileStatus[] status =
		 * fs.listStatus(paths);
		 */
		// 通配方式
		FileStatus[] status = fs.globStatus(new Path(
				"hdfs:///test/input/wc/*02.txt"));

		Path[] listedPaths = FileUtil.stat2Paths(status);
		for (Path p : listedPaths) {
			System.out.println(p);
		}
	}
}

文件元數據FileStatus,封裝了文件系統中文件和文件夾的元數據,包含文件長度、塊大小、備份、改動時間、所有者以及權限信息。


刪除數據


使用FileSystem的delete()方法可以永久性刪除文件或文件夾。

public boolean delete(Path f,boolean recursive) throws IOException

假設f是一個文件或空文件夾,那麼recursive的值就會被忽略。

假設f是一個非空文件夾,則僅僅有recursive爲true才幹刪除。不然會拋出IOException。


Hadoop數據流


文件讀取剖析




文件寫入剖析




複本的佈局策略(以3個爲例):一、執行client的節點,二、離架節點,三、2所在機架的隨機節點。


一致模型


文件系統的一致模型,描寫敘述了對文件讀/寫的數據可見性。HDFS爲性能犧牲了一些POSIX要求,所以一些操做與你指望的不一樣。

		Path p = new Path("p");
		Fs.create(p);

		Path p = new Path("p");
		OutputStream out = fs.create(p);
		out.write("content".getBytes("UTF-8"));
		out.flush();

以上兩段代碼都不能這個文件在文件系統立刻可見。除非在out.flush();後面添加一行out.sync()。目的是強制所有的緩存與數據節點同步,另外,在HDFS中關閉文件out.close(0事實上隱含運行了sync()方法。

這個一致模型相應用設計的重要性:

假設不調用sync(),可能因client故障而丟失數據。而經常調用sync()也會有額外性能開銷,因此需要在數據健壯性和吞吐量直接有所取捨,這與詳細的應用有關,經過設置不一樣的調用sync()的頻率來衡量應用的性能。終於找到一個合適的頻率。


經過distcp進行並行複製


前面介紹的都是單線程的HDFS訪問模型,distcp是一個分佈式的複製程序。典型應用是在兩個HDFS直接傳輸 數據,假設兩個集羣執行一樣版本號的Hadoop,則可以例如如下:

hadoop distcp hdfs://集羣1的某節點/foo hdfs://集羣2的某節點/foo

可以經過-overrite,指定覆蓋現有的文件;經過-update指定僅更新改動過的文件。

假設兩個集羣版本號不同,可以例如如下這樣:

hadoop distcp hftp://集羣1的某節點:50070/foo hdfs://集羣2的某節點/foo 

默認狀況下。每個集羣節點(tasktracker)。最多分配20個map任務,假設複製1000G數據到100個節點的集羣,一共會有2000個map任務,每個map任務平均分配512M數據。可以指定-m參數,下降map任務數,比方-m 1000,將分配1000個map任務,平均每個複製1GB數據;但是通常不推薦這麼作,可能致使集羣不平衡。


Hadoop存檔


Hadoop存檔文件(HAR文件),是一個高效的文件存檔工具,它將文件存入HDFS塊。下降namenode內存使用的同一時候,依舊贊成對文件進行透明的訪問(即Hadoop文檔可以做爲MapReduce的輸入)。

命令演演示樣例如如下:

hadoop fs -ls -R /test/input

hadoop archive -archiveName files.har -p /test input /test/file

hadoop fs -ls /test/file

hadoop fs -ls /test/file/files.har

hadoop fs -ls -R har:///test/file/files.har

hadoop fs -rm -r /test/file

har文件的不足:

(1)建立一個存檔文件會建立原始文件的一個複本。所以需要額外的和原始文件同樣大小的磁盤空間。固然,建立了存檔文件。可以刪除原始文件。

har是不壓縮的,很相似於tar文件

(2)一旦建立,存檔文件不能改動。其實。通常不會改動存檔文件,因爲它們是按期成批存檔的,比方每日或每週。

(3)Har文件做爲mapreduce輸入時,InputFormat類並不知道文件已經存檔,雖然該類可以將多個文件打包成一個MapReduce分片。因此即便在har文件裏處理不少小文件,依舊和原來同樣低效。

相關文章
相關標籤/搜索