第二章 HDFS 实现分布式存储

版权声明:如需转载,请注明出处! https://blog.csdn.net/qq_41172416/article/details/87914520

1、HDFS的体系结构

HDFS的优势:

  1. 存储超大文件
  2. 标准流式访问:“一次写入,多次读取”
  3. 运行在廉价的商用机器集群上

HDFS的缺点:

  1. 不能满足低延迟的数据访问
  2. 无法高效存储大量小文件
  3. 暂时不支持多用户写入及随意修改文件

HDFS体系结构:

                                                    (图2.1) HDFS体系结构

1.1  基本概念

  1.  文件块

           hdfs中的文件被分成 进行存储,如图2.1 中 DataNode 中的以数字编号的方块。它是文件存储处理的最小逻辑单元,默认块大小为 64MB,使用文件块的好处是:

  1. 文件的所有块并不需要存储在同一个磁盘上,可以利用集群上的任意一个磁盘进行存储。
  2. 对分布式系统来说,由于块的大小是固定的,因此计算单个磁盘能存储多少个块就相对容易,可简化存储管理。
  3. 在数据冗余备份时,将每个块复制到少数几台独立的机器上(默认为三台),可以确保在块、磁盘或机器发生故障后数据不会丢失。如果发现一个块不可用,系统会从其他地方读取另一个副本,这个过程对用户是透明的。
#显示块信息
hdfs fsck / -files -blocks

 注意:fsck 命令将列出文件系统中根目录 “/” 下各个文件由哪些块构成。fsck 命令只是从NameNode 获取信息,并不与任何 DataNode 交互,因此并不真正获取数据。

      2. NameNode和DataNode节点

        《 NameNode 和 DataNode 属于 HDFS集群的两类节点 》

  1. NameNode 负责管理文件系统的命名空间,属于管理者角色。
  2. DataNode 根据需要存储、检索数据块,并定期向 NameNode 发送存储的块的列表,属于工作者。

注意:DataNode 负责管理文件系统客户端的文件读写请求,并在 NameNode 的统一调度下进行数据块的创建、删除和复制工作。如果在 NameNode 上的数据损坏,HDFS 中所有的文件都不能被访问,由此可见 NameNode 节点的重要性。为了保证 NameNode 的高可用性,Hadoop 对 NameNode 进行了补充,即 Secondary NameNode 节点。

      3. Secondary NameNode节点

       系统会同步一个 Secondary NameNode,也称二级 NameNode.相当于 NameNode 的快照,能够周期性地备份 NameNode,记录 NameNode 中的元数据等,也可以用来恢复 NameNode,但 Secondary NameNode 中的备份会滞后于 NameNode ,所以会带来一定的数据损失。为了防止宕机,通常是将 Secondary NameNode 和 NameNode 设置为不同的主机。使用 hdfs-site.xml 中配置的dfs.namenode.secondary.http-address 属性值可以通过浏览器查看 Secondary NameNode 的运行状态。

1.2  Master / Slave 架构

 一个 HDFS 集群由一个 NameNode 和多个 DataNode 组成,属于典型的 Master / Slave 模式。

读写流程如下:

  1. 数据读流程:由客户端向 NameNode 请求访问某个文件,NameNode返回该文件所在位置即在哪个 DataNode 上,然后由客户端从该 DataNode 读取数据。
  2. 数据写流程:由客户端向 NameNode 发出文件写请求,NameNode 告诉客户该向哪个 DataNode写入该文件,然后由客户将文件写入该DataNode 节点,随后该DataNode 将该文件自动复制到其他 DataNode 节点上,默认三份备份。

1.节点添加

可扩展性是HDFS 的一个重要特性,向 HDFS 集群中添加节点很容易实现,添加一个新的 DataNode 节点的步骤如下:

  1. 对新节点进行系统配置,包括 hostname、hosts 文件、JDK 环境、防火墙等。
  2. 在新加节点上安装好 Hadoop,要和 NameNode 使用相同的配置,可以直接从 NameNode 复制。
  3. 在NameNode 上修改 $HADOOP_HOME/etc/hadoop/Slaves 文件,加入新加节点主机名。
  4. 运行启动命令:
bin/start-all.sh

2.负载均衡

HDFS 的数据在各个 DataNode 中的分布可能很不均匀,尤其是在 DataNode 节点出现故障或新增 DataNode 节点时。使用如下命令可重新平衡 DataNode 上的数据块的分布:

sbin/start-balancer.sh

  3.安全机制

Master/Slave 架构通过 NameNode 来统一调度,没有NameNode,文件系统将无法使用。Hadoop采用两种机制来确保NameNode的安全。

  1. 第一种是将NameNode 上存储的元数据文件转移到其他文件系统中
  2. 第二种就是使用Secondary NameNode 同步备份

2、Hadoop FS Shell 命令

语法:hadoop fs <args>

其中 “hadoop” 命令位于 $HADOOP_HOME/bin 目录下,“fs” 为其参数,表示 FileSystem Shell , "<args>" 是 fs 的子命令,包括:

  1. 创建目录:mkdir
  2. 列表文件:ls
  3. 查看文件:cat
  4. 转移文件:put、get、mv、cp
  5. 删除文件:rm、rmr
  6. 管理命令:test、du、expunge

1、 创建目录:mkdir

语法:

hadoop fs -mkdir <paths>

示例:

# 在 HDFS 中创建 “/user”目录
hadoop fs -mkdir /user


# 在 HDFS 中创建 “/user/hadoop” 目录
hadoop fs -mkdir /user/hadoop


# 同时创建多个目录
hadoop fs -mkdir /user/hadoop/dir1  /user/hadoop/dir2

2、 列表文件:ls

语法:

hadoop fs -ls <args>

3、 查看文件:cat

语法:

hadoop fs -cat URL

示例:

# 查看 HDFS 文件file1.txt 和 file2.txt
hadoop fs -cat /input2/file1.txt /input2/file2.txt

# 查看本地文件 file3.txt
hadoop fs -cat file:///home/hduser/file3.txt

4、 转移文件:put、get、mv、cp

put命令:

语法:

hadoop fs -put <localsrc> . . .  <dst>

示例:

# 将本地文件复制到 HDFS 目录 “/input2”
hadoop fs -put /home/hduser/file/file1.txt  /input2


# 将本地多个文件复制到 HDFS 目录 “/input2”
hadoop fs -put /home/hduser/file/file1.txt  /home/hduser/file/file2.txt  /input2

get命令:

语法:

hadoop fs -get <src>  <localdst>

示例:

# 将HDFS 文件 “/input2/file1” 复制到本地文件系统 “$HOME/file”中
hadoop fs -get /input2/file1  $HOME/file

mv命令:

语法:

hadoop fs -mv URL [URI...]  <dest>

注意:不允许在不同的文件系统间移动文件,也就是说所有路径都必须是同一文件系统 URI 格式。

示例:

# 将HDFS上的file1.txt、file2.txt 移动到 dir1 中
hadoop fs -mv /input2/file1.txt /input2/file2.txt  /user/hadoop/dir1

cp命令:

语法:

hadoop fs -cp URI [URI ...]  <dest>

注意:将文件从源路径复制到目标路径,允许多个源路径,目标路径必须是一个目录。不协调子不同的文件系统间复制文件。

示例:

# HDFS 中复制多个文件到 “/user/hadoop/dir1”
hadoop fs -cp /input2/file1.txt  /input2/file2.txt  /user/hadoop/dir1


# 在本地文件系统中复制多个文件到目录 “file:///tmp”
hadoop fs -cp file:///file1.txt  file:///file2.txt  file:///tmp

5、 删除文件:rm、rmr

rm命令:

语法:

hadoop fs -rm URI  [URI...]

注意:删除指定的文件,只删除非空目录和文件。

示例:

# 删除非空文件
hadoop fs -rm /input2/file1.txt

rmr命令:

语法:

hadoop fs -rmr URI  [URI...]

注意:rm的递归版本,整个文件夹及子文件夹将全部删除。

示例:

# 递归删除
hadoop fs -rmr /user/hadoop/dir1

6、 管理命令:test、du、expunge

test命令:

语法:

hadoop fs -test -[选项]  URI

选项:

-e:检查文件是否存在。如果存在则返回0.

-z:检查文件是否0字节。如果是则返回0.

-d:检查路径是否为目

du 命令:

语法:

hadoop fs -du  URI  [URI ...]

注意:显示目录中所有文件的大小

示例:

# 显示文件的大小,如果是目录则列出所有文件及其大小
hadoop fs -du  /input2


# 显示文件的大小,如果是目录则统计总大小
hadoop fs -du  -s  /input2/file1.txt

expunge命令:

语法:

# 清空回收站
hadoop fs -expunge

3、HDFS Java API

创建一个Map/Reduce Project 项目,在src目录下,导入core-site.xml文件

core-site.xml:https://pan.baidu.com/s/11mQQiWpvm7CE3b0ObwWA-A 
提取码:luwy 

项目结构图:

 1  创建文件

package hdfs;

import java.io.IOException;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileSystemCreate {
	
	public static void main(String[] args) throws IOException {
		String uri=args[0];//如:hdfs://node1:9000/input2/file2.txt
		Configuration conf = new Configuration();		
		FileSystem fs = FileSystem.get(conf);
		Path f=new Path(uri);
		FSDataOutputStream outputStream=fs.create(f);		
		IOUtils.write("Hello!Hadoop HDFS!", outputStream);
	}

}

  2  复制文件

package hdfs;

import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileSystemCopy {

	public static void main(String[] args) throws IOException {
		String srcFile=args[0];//必须是本地文件,如:/home/hduser/file/file2.txt
		String dstFile=args[1];//必须是HDFS文件,如:hdfs://node1:9000/input2/file2.txt
		Configuration conf = new Configuration();		
		FileSystem fs = FileSystem.get(conf);
		Path srcPath=new Path(srcFile);
		Path dstPath=new Path(dstFile);		
		fs.copyFromLocalFile(srcPath, dstPath);
	}

}

   3  删除文件

package hdfs;

import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileSystemDelete {

	public static void main(String[] args) throws IOException {
		String uri=args[0];//如:hdfs://node1:9000/input3
		Configuration conf = new Configuration();		
		FileSystem fs = FileSystem.get(conf);
		Path f=new Path(uri);	
		fs.delete(f,true);
	}

}

    4  重命名文件

package hdfs;

import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileSystemRename {

	public static void main(String[] args) throws IOException {
		String fromFile=args[0];//如:hdfs://node1:9000/input2/file2.txt
		String toFile=args[1];//如:hdfs://node1:9000/input2/file2new.txt
		Configuration conf = new Configuration();		
		FileSystem fs = FileSystem.get(conf);
		Path fromPath=new Path(fromFile);
		Path toPath=new Path(toFile);		
		fs.rename(fromPath, toPath);
	}

}

    5  文件查询

package hdfs;

import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileSystemGetStatus {

	public static void main(String[] args) throws IOException {
		String uri=args[0];//如:/input2/file1.txt
		Configuration conf = new Configuration();		
		FileSystem fs = FileSystem.get(conf);
		Path f=new Path(uri);
		FileStatus stat=fs.getFileStatus(f);
		System.out.println("文件路径:"+stat.getPath());				
		System.out.println("文件块大小:"+stat.getBlockSize());
		System.out.println("文件大小:"+stat.getLen());
		System.out.println("副本数量:"+stat.getReplication());
		System.out.println("用户:"+stat.getOwner());
		System.out.println("用户组:"+stat.getGroup());
		System.out.println("权限:"+stat.getPermission().toString());
	}

}

 有时我们并不知道文件的具体名称,此时便可使用 listStatus() 方法列出目录内容。

package hdfs;

import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileSystemListStatus {

	public static void main(String[] args) throws IOException {
		String uri=args[0];//如:/input2
		Configuration conf = new Configuration();		
		FileSystem fs = FileSystem.get(conf);
		Path f=new Path(uri);
		FileStatus[] stats=fs.listStatus(f);
		for(FileStatus stat : stats)
			System.out.println(String.format("%s\t%s\t%s\t",
					stat.getPermission().toString(),stat.getOwner(),stat.getPath()));
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41172416/article/details/87914520
今日推荐