HDFS

HDFS詳解html

http://my.oschina.net/crxy/blog/348868node

hdfs工做原理併發

http://my.oschina.net/crxy/blog/385283app

HDFStcp

HDFS適合作:分佈式

  1. 存儲大文件。上G、T甚至P。函數

  2. 一次寫入,屢次讀取。而且每次做業都要讀取大部分的數據。oop

  3. 搭建在普通商業機羣上就能夠了。雖然會常常宕機,但HDFS有良好的容錯機制。spa

HDFS不適合作:.net

  1. 實時數據獲取。若是有這個需求能夠用HBase。

  2. 不少小文件。由於namenode要存儲HDFS的metadata(好比目錄的樹狀結構,每一個文件的文件名、ACL、長度、owner、文件內容存放的位置等等信息),因此HDFS上文件的數目受到namenode內存的限制。

  3. 併發環境下的寫入和修改。

Block

一個磁盤的block一般是512B,內核一次讀寫磁盤不能少於這個數目。在HDFS上一個Block的默認大小是64M,HDFS block的大小能夠經過ds.block.size來設置,不少工做站上把一個block調爲128M。之因此要把block設置得這麼大,是由於HDFS上的文件廣泛都是大文件,若是block很小,那一個文件就要存放在不少block上,而這些位置信息都要被namenode所記錄,一來浪費namenode的存儲空間,二來檢索一個文件的時候開銷也比較高。

當一個文件的長度小於一個block size時,它會單獨佔用一個block,但它佔用的磁盤空間仍然是其真實的長度。

Namenode和Datanode

namenode管理文件系統的namespace,而datanode負責存儲和檢索block。通常狀況下一個block會存放在多個不一樣的datanode上,以提升容錯性。datanode在讀寫HDFS文件時,都須要經過namenode來獲知讀寫的具體位置。

你可使用distcp命令在不一樣的datanode之間並行地複製大文件:

$ hadoop distcp hdfs://datanode1/foo hdfs://datanode2/bar

HDFS上的文件是使用URI來定位的,前綴都是hdfs://localhost:9000,你能夠把這個前綴賦給屬性fs.default.name(屬性能夠在配置文件中指定,也能夠在代碼中指定),這樣你就不用每次都寫這個前綴了,好比如下2個命令是等價的:

$ hadoop fs -ls /

$ hadoop fs -ls hsfs://localhost:9000/

本地文件系統的前綴是file://

複製代碼

orisun@zcypc:~$ hadoop fs -ls file:///Found 22 items
drwxr-xr-x   - root root       4096 2012-08-02 19:17 /home
dr-xr-xr-x   - root root          0 2012-08-20 22:14 /proc
drwxr-xr-x   - root root       4096 2010-04-23 18:11 /mnt
drwx------   - root root       4096 2012-08-18 10:46 /root
drwxr-xr-x   - root root       4096 2012-08-18 10:40 /sbin
……

複製代碼

HDFS默認的文件備份數量是3,這個能夠在dfs.replication屬性中設置,在僞分佈式模式中因爲datanode只有一個,因此要把該值設爲1。當你使用hadoop fs -ls命令時會獲得形如:

drwxr-xr-x     -   orisun   supergroup        0   2012-08-20 14:23   /tmp

-rw-------    1   orisun   supergroup   4   2012-08-20 14:23   /tmp/jobtracker.info

跟UNIX下的ls命令很像,其中第2列就是replication的數目,第5列是文件的長度,以B爲單位(文件夾的長度是0,而在UNIX文件系統中目錄的長度是512B的整倍數,由於目錄所佔的空間是以塊爲分配單位的,每塊爲512B)。

FSDataInputStream繼承自Java的DataInputStream並支持隨機讀寫。

public class FSDataInputStream extends DataInputStream implements Seekable, PositionedReadable {}
public interface Seekable {
  void seek(long pos) throws IOException;
  long getPos() throws IOException;
  boolean seekToNewSource(long targetPos) throws IOException;
}

FSDataInputStream還能夠從指定的位置讀取文件的一部分。

public interface PositionedReadable {    public int read(long position, byte[] buffer, int offset, int length) throws IOException;    public void readFully(long position, byte[] buffer, int offset, int length) throws IOException;    public void readFully(long position, byte[] buffer) throws IOException;
}

若是你想在HDFS上新建一文件可使用

public FSDataOutputStream create(Path f) throws IOException

使用create()函數時注意2點:文件必須以前不存在;它可附帶地建立任意多級的父目錄。

有時候你可能會須要用append(),在文件不存在時會建立它。

public FSDataOutputStream append(Path f) throws IOException

重命名文件

public void rename(String oldName,String newName)

固然你也能夠用mkdir來建立目錄

public boolean mkdirs(Path f) throws IOException

因爲create()能夠附帶地建立任意多級的父目錄,因此mkdir你並不會經常使用。

FileSystem的getFileStatus()方法能夠獲取文件和目錄的FileStatus。

Path file = new Path("/dir/file");
FileStatus stat = fs.getFileStatus(file);

而後你就能夠訪問:

複製代碼

stat.getPath()
stat.getLen()
stat.isLen()
stat.getMogificationTime()
stat.getReplication()
stat.getBlockSize()
stat.getOwner()
stat.getReplication()
stat.getBlockSize()
stat.getGroup()
stat.getPermission()

複製代碼

實際上上述信息都存儲在namenode中。

你還能夠獲取一個目錄下全部文件的FileStatus。

public FileStatus[] listStatus(Path f) throws IOExceptionpublic FileStatus[] listStatus(Path f, PathFilter filter) throws IOExceptionpublic FileStatus[] listStatus(Path[] files) throws IOExceptionpublic FileStatus[] listStatus(Path[] files, PathFilter filter) throws IOException

在指定文件時,hadoop一樣支持globbing,它支持的wildcard有:

*  0個或多個任意字符

?  任意單個字符

[ab]  [^ab]  [a-b]  [^a-b]

{exp1,exp2}    匹配exp1或exp2

\c  轉義

fs.listStatus(new Path("/2007/*/*"), new RegexExcludeFilter("^.*/2007/12/31$"))

將匹配2007年的全部文件,可是2007-12-31的文件將被filter掉。

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

刪除目錄時能夠選擇是否啓用遞歸模式。

 上面已經提到大量的小文件會極大消耗namenode的內存,因此在這種狀況下咱們須要使用Hadoop Archives(HAR)把文件歸檔爲一個大文件。

$ hadoop archive -archiveName orisun.har -p /user/orisun /user

把/user/orisun下的全部文件打包成orisun.tar放在/user目錄下。

你還能夠查看一個har文件中包含哪些文件:

複製代碼

orisun@zcypc:~$ hadoop fs -lsr har:///user/orisun.hardrwxr-xr-x   - orisun supergroup          0 2012-08-20 16:49 /user/orisun.har/mse-rw-r--r--   1 orisun supergroup          0 2012-08-20 16:49 /user/orisun.har/mse/list-rw-r--r--   1 orisun supergroup          0 2012-08-20 16:49 /user/orisun.har/book
orisun@zcypc:~$ hadoop fs -ls har:///user/orisun.har/mseFound 1 items-rw-r--r--   1 orisun supergroup          0 2012-08-20 16:49 /user/orisun.har/mse/list

複製代碼

HAR也是一個文件系統,一個Har URI的完整模式是har://<scheme>-<host>/<path>

orisun@zcypc:~$ hadoop fs -lsr har://hdfs-localhost:9000/user/orisun.har/mse-rw-r--r--   1 orisun supergroup          0 2012-08-20 16:49 /user/orisun.har/mse/list

刪除har文件必須使用rmr命令,用rm是不行的。

$ hadoop fs -rmr /user/orisun.har

 使用HAR的一些限制:

  1. 會產生原始文件的完整備份,佔用磁盤空間。固然你能夠以在建好har文件後把原文件刪掉。

  2. HAR只是把多個文件打包成一個文件並無採用任何的壓縮策略。

  3. HAR文件是不可變,如何你想增長或從har中刪除一個文件,你只能從新歸檔。

  4. InputFormat不理會har的存在,這意味着har文件對於MapReduce來講仍然會產生多個InputSlit,不會提升效率。要解決「小文件不少致使map task不少」的問題,能夠採用CombineFileInputFormat。

相關文章
相關標籤/搜索