HDFS分布式文件存储系统
一、HDFS概述
(一)HDFS产生背景
随着数据量越来越大,在一个文件系统下无法存储海量数据,普通硬件支持的操作系统即使扩展磁盘也会遇到瓶颈,迫切需要水平横向扩展来解决数据存储问题,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种,其它的比如TFS、fastdfs、tachyon。
(二)HDFS的定义
Hadoop分布式文件系统(HDFS)是指被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统(Distributed File System)。
(三)优缺点
知道优缺点,方便进行技术选型。
1、优点
(1)高容错
- 数据自动保存多个副本。它通过增加副本的形式,提高容错性;
- 某一个副本丢失以后,其它副本有备份,能够自动恢复。
(2)块存储
当我们向hdfs存储文件的时候,hdfs会将文件物理上切块存储,例如存储一个200M的文件,hdfs将该文件切分为两块:128M、72M,将这两块进行存储,而不是将该文件作为一个整体进行存储。
a.最佳传输损耗原理
当读取一个文件的时候,所需要的时间分为两部分:寻址时间、传输时间。根据目前的技术水平,机械磁盘的寻址时间普遍在10ms左右,而传输时间取决于要读取文件的大小,读取的文件越大,所需要的传输时间越长,那么,一次读取多少文件效率最高呢?根据经验寻址时间占传输时间1%的时候,是传输一个文件效率最高的。
b.128M设计初心
根据上述原理,寻址时间占传输时间1%的时候,传输一个文件效率最高,而寻址时间相对固定,也就是10ms,如果要满足寻址时间/传输时=1%这个公式,那么传输时间即为1000ms=1s。换句话说,我们在读取一个文件时,传输时间用1s,此时读取效率最高。
那么1s能传输多少文件呢?这个要取决于磁盘的传输速度,而目前机械磁盘传输速度大约为100M/S,所以这1s所能传输的文件大小=1s*100M/s=100m。即每次读取一个100M的文件,效率最高,另外计算机在存储时,是以是2的n次方进行的,所以hadoop2.x和hadoop3.x默认块的大小为128M。
(3)适合处理大数据集
- 数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据。
- 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
(4)可靠性
因为具备高容错性,所以集群可以部署在廉价的PC机上,并能够保证数据不易丢失。
2、缺点
(1)不适合低延迟的数据访问
访问hdfs数据的速度相对较慢,比如像mysql那样毫秒级的读写数据,hdfs是做不到的
(2)不适合存储大量小文件
- 在读取小文件时,寻址时间会超过传输时间,不符合最佳传输损耗原理,效率太低,因此不会采用hdfs存储大量小文件。
- 存储大量小文件的话,它会占用NameNode更多的内存来存储文件的元数据。这样是不可取的,因为NameNode的内存总是有限的。在hdfs里面,每个block的元数据会占用150字节的内存空间。例如同样存储10M的内容,采取副本数为3的备份机制,这10M放在一个文件中,所用到的元数据占用的内存为150*3=450字节,如果把这10M放到10个文件中,则占用150*10*3=4500字节,很明显,存储相同的内容,第二种方式占用的内存更多。
(3)不支持并发写入以及随机修改
- 一个文件只能有一个用户写,不允许多个线程同时写;
- 仅支持数据append(追加),不支持文件的随机修改。
二、HDFS的实操
既然HDFS是存取数据的分布式文件系统,那么对HDFS的操作,就是文件系统的基本操作,比如文件的创建、修改、删除、修改权限等,文件夹的创建、删除、重命名等。HDFS 文件操作有两种方式:一种是命令行方式,Hadoop 提供了一套与 Linux 文件命令类似的命令行工具;另一种是 Java API,即利用 Hadoop 的 Java 库,采用编程的方式操作 HDFS 的文件。
(一)HDFS的shell客户端操作
1、命令概述
安装好hadoop环境之后,可以执行hdfs shell命令对hdfs 的空间进行操作。我们通过命令行和HDFS打交道,进一步增加对HDFS的认识,HDFS命令行接口是一种最直接,也比较简单的一种方式。
2、命令格式
调用文件系统(FS)Shell命令应使用bin/hadoop fs 的形式。也可以使用其他形式。
常用的三种格式区别
hadoop fs {args}:FS relates to a generic file system which can point to any file systems like local, HDFS etc. So this can be used when you are dealing with different file systems such as Local FS, HFTP FS, S3 FS, and others.该命令可以用于其他文件系统,不止是hdfs文件系统内,也就是说该命令的使用范围更广
hadoop dfs {args}:dfs is very specific to HDFS. would work for operation relates to HDFS. This has been deprecated and we should use hdfs dfs instead. 该命令专门针对hdfs分布式文件系统
hdfs dfs {args}:same as 2nd i.e would work for all the operations related to HDFS and is the recommended command instead of hadoop dfs. 该命令和上面第二种命令作用相同,且更为推荐,并且当使用hadoop dfs时内部会被转为hdfs dfs命令。
总结:So even if you use Hadoop dfs , it will look locate hdfs and delegate that command to hdfs dfs
3、命令分类及实操
(1)admin command(管理员命令)
-help :查看管理员命令帮助文档
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop dfsadmin -help
-report:查看文件系统的基本信息和统计信息。
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop dfsadmin -report
(2)client commands(客户端命令)
a) hadoop fs -help
输出这个命令参数
格式:hadoop fs -help+选项+参数
案例演示:显示rm命令的帮助信息
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -help rm
b) hadoop fs -ls
显示目录信息
格式:hadoop fs -ls+选项+参数
案例演示:显示hdfs/目录的内容
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -ls /
c) hadoop fs -mkdir
在HDFS上创建目录
格式:hadoop fs -mkdir+选项+参数
案例演示:连续创建多级目录
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -mkdir -p /offcn/bigdata
d) hadoop fs -moveFromLocal
从本地剪切粘贴到HDFS
格式:hadoop fs -moveFromLocal +选项+参数
案例演示:在本地创建空文件aa.txt,并将该文件剪切到hdfs的/offcn/bigdata目录
[offcn@bd-offcn-01 hadoop-3.1.3]$ touch aa.txt
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -moveFromLocal aa.txt /offcn/bigdata
e) hadoop fs -appendToFile
追加一个文件到已经存在的文件末尾
格式:hadoop fs -appendToFile+选项+参数
案例演示:将README.txt 文件的内容,追加到aa.txt文件
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -appendToFile README.txt /offcn/bigdata/aa.txt
f) hadoop fs -cat
显示文件内容
格式:hadoop fs -cat+选项+参数
案例演示:查看/offcn/bigdata/aa.txt文件的内容
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -cat /offcn/bigdata/aa.txt
g) hadoop fs -chmod
修改文件所属权限
格式:hadoop fs -chmod +选项+参数
案例演示:修改/offcn/bigdata/aa.txt的权限为666
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -chmod 666 /offcn/bigdata/aa.txt
h) hadoop fs -chgrp
修改文件所属组
格式:hadoop fs -chgrp+选项+参数
案例演示:修改/offcn/bigdata/aa.txt文件的所属组为offcn
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -chgrp offcn /offcn/bigdata/aa.txt
i) hadoop fs -copyFromLocal
从本地文件系统中拷贝文件到HDFS路径去
格式:hadoop fs -copyFromLocal +选项+参数
案例演示:把本地的README.txt文件拷贝到hdfs目录/offcn/bigdata
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -copyFromLocal README.txt /offcn/bigdata
j) hadoop fs -copyToLocal
从HDFS拷贝到本地
格式:hadoop fs -copyToLocal +选项+参数
案例演示:把hdfs的/offcn/bigdata/README.txt拷贝到本地/tmp目录
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -copyToLocal /offcn/bigdata/README.txt /tmp
k) hadoop fs -cp
从HDFS的一个路径拷贝到HDFS的另一个路径
格式:hadoop fs -cp+选项+参数
案例演示:把hdfs的/offcn/bigdata/README.txt文件拷贝到hdfs的/目录
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -cp /offcn/bigdata/README.txt /
l) hadoop fs -mv
在HDFS目录中移动文件
格式:hadoop fs -mv+选项+参数
案例演示:把hdfs的/offcn/bigdata/aa.txt文件移动到hdfs的/目录
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -mv /offcn/bigdata/aa.txt /
m.) hadoop fs -get
等同于copyToLocal,就是从HDFS下载文件到本地
格式:hadoop fs -get+选项+参数
案例演示:把hdfs的/offcn/bigdata/README.txt下载到本地/home/offcn目录
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -get /offcn/bigdata/README.txt /home/offcn
n.) hadoop fs -getmerge
合并下载多个文件
格式:hadoop fs -getmerge+选项+参数
案例演示:将/aa.txt和/offcn/bigdata/README.txt合并下载到本地当前目录,并重命名为two.txt
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -getmerge /aa.txt /offcn/bigdata/README.txt ./two.txt
o.) hadoop fs -put
等同于copyFromLocal
格式:hadoop fs -put+选项+参数
案例演示:把NOTICE.txt上传到hdfs/offcn/bigdata目录
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -put NOTICE.txt /offcn/bigdata
p) hadoop fs -tail
显示一个文件的末尾
格式:hadoop fs -tail +选项+参数
案例演示:查看hdfs的/offcn/bigdata/NOTICE.txt文件的尾部几行
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -tail /offcn/bigdata/NOTICE.txt
q.) hadoop fs -rm
删除文件或文件夹
格式:hadoop fs -rm +选项+参数
案例演示:删除hdfs的/offcn/bigdata/README.txt文件
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -rmr /offcn/bigdata/README.txt
r) hadoop fs -rmdir
删除空目录
格式:hadoop fs -rmdir+选项+参数
案例演示:创建hdfs的/offcn/aa目录,并删除
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -mkdir -p /offcn/bigdata/aa
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -rmdir /offcn/bigdata/aa
s.) hadoop fs -du
统计文件夹的大小信息
格式:hadoop fs -du +选项+参数
案例演示:查看hdfs目录/offcn/bigdata的大小信息
[offcn@bd-offcn-01 ~]$ hadoop fs -help du
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -du -s -h /offcn/bigdata
t)hadoop fs -setrep
设置HDFS中文件的副本数量
格式:hadoop fs -setrep+选项+参数
案例演示:设置hdfs的/offcn/bigdata/NOTICE.txt文件的副本数量为2
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -setrep 2 /offcn/bigdata/NOTICE.txt
u) hadoop fs -test
回答关于路径的不同问题
格式:hadoop fs -test+选项+参数
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -help test
-test -[defsz] <path> :
Answer various questions about <path>, with result via exit status.
-d return 0 if <path> is a directory.
-e return 0 if <path> exists.
-f return 0 if <path> is a file.
-s return 0 if file <path> is greater than zero bytes in size.
-z return 0 if file <path> is zero bytes in size, else return 1.
例如:下面通过-d判断/offcn/bigdata路径是个目录还是个文件。-d表示判断路径是不是一个目录,返回0代表是个目录,
[offcn@bd-offcn-01 hadoop-3.1.3]$ hadoop fs -test -d /offcn/bigdata
[offcn@bd-offcn-01 hadoop-3.1.3]$ echo $?
0
(三)HDFS的javaApi
1、windows下Hadoop的配置
(1)编译
要想在windows环境下进行hadoop开发,必须先将hadoop的源码下载下来进行编译,然后配置到环境变量里面,这里我们已经提前编译好了。
问题
在windows上做HDFS客户端应用开发,需要设置Hadoop环境,而且要求是windows平台编译的Hadoop,不然会报以下的错误:
缺少winutils.exe Could not locate executable null \bin\winutils.exe in the hadoop binaries 缺少hadoop.dll Unable to load native-hadoop library for your platform… using builtin-Java classes where applicable |
(2)搭建步骤
- 将已经编译好的Windows版本Hadoop解压到到一个没有中文没有空格的路径下面
- 在windows上面配置hadoop的环境变量: HADOOP_HOME,并将%HADOOP_HOME%\bin添加到path中
配置HADOOP_HOME
配置PATH目录
3、把hadoop3.2.1文件夹中bin目录下的hadoop.dll文件放到系统盘: C:\Windows\System32 目录
2、创建maven工程导入pom文件
创建一个Maven工程myhdfs
导入相应的依赖坐标+日志添加
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<configuration>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>jar-with-dependencies</shadedClassifierName>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass></mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入
# 控制台输出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %p [%c] - %m%n
# 指定日志的输出级别与输出端
log4j.rootLogger=DEBUG,Console
日志级别:
OFF FATAL ERROR WARN INFO DEBUG TRACE ALL
ERROR>WARN>INFO>DEBUG
日志工具的简单使用:
package com.offcn.hdfs;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
public class MyLogger {
public static void main(String[] args) {
// Logger myloger = LogManager.getLogger("logname");
Logger myloger = LogManager.getLogger(MyLogger.class);
myloger.error("error");
myloger.warn("warn");
myloger.info("info");
myloger.debug("debug");
}
}
3、编写代码实现
创建一个包com.offcn.hdfs,并创建MyHdfsClient类。
(1)HDFS创建目录
@Test
public void testMkdirs() throws IOException, InterruptedException, URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), configuration, "offcn");
// 2 创建目录
boolean mkdirs = fs.mkdirs(new Path("/bigdata/0309"));
System.out.println("是否创建目录成功:"+mkdirs);
// 3 关闭资源
fs.close();
}
(2)HDFS文件上传并测试参数优先级
@Test
public void testUploadFile() throws Exception {
// 1 准备一个Configuration配置对象
Configuration conf = new Configuration();
// 优先级: 代码>项目>自定义服务器默认>服务器默认
conf.set("dfs.replication","2");
// 2 利用配置对象获取操作hdfs的文件系统对象
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), conf, "offcn");
// 3 调用该对象的方法
fs.copyFromLocalFile(new Path("D:/test/test.jpg"),new Path("/0826/test3.jpg"));
System.out.println("上传成功");
// 4 关闭资源
fs.close();
}
在项目的根目录下创建hdfs-site.xml文件并输入以下内容
<?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)ClassPath下的用户自定义配置文件 >(3)然后是服务器的默认配置
(2)HDFS文件下载
@Test
public void testDownloadFile() throws Exception {
// 1 准备一个Configuration配置对象
Configuration conf = new Configuration();
// 2 利用配置对象获取操作hdfs的文件系统对象
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), conf, "offcn");
// 3 调用该对象的方法
// 参数1:是否删除源文件
// 参数2:文件下载源
// 参数3:文件下载目的地
// 参数4:是否开启文件校验
fs.copyToLocalFile(false,new Path("/0826/test3.jpg"),new Path("D:/test/test0706.jpg"),true);
System.out.println("下载成功");
// 4 关闭资源
fs.close();
}
(3)HDFS文件夹删除
@Test
public void testDelete() throws IOException, InterruptedException, URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), configuration, "offcn");
// 2 执行删除
//参数1:要删除的路径
//参数2:是否递归删除,如果删除的是个目录,则需要置为true
fs.delete(new Path("/bigdata/0310"),true);
System.out.println("删除成功");
// 3 关闭资源
fs.close();
}
(4)HDFS文件名更改
@Test
public void testRename() throws IOException, InterruptedException, URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), configuration, "offcn");
// 2 重命名目录
boolean rename = fs.rename(new Path("/bigdata/0309/test.jpg"), new Path("/bigdata/0309/newtest.jpg"));
System.out.println("是否重命名成功:"+rename);
// 3 关闭资源
fs.close();
}
(5)HDFS文件详情查看
@Test
public void testShowDetail() throws IOException, InterruptedException, URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), configuration, "offcn");
// 2 操作
RemoteIterator<LocatedFileStatus> it = fs.listFiles(new Path("/0825"),true);
while(it.hasNext()){
LocatedFileStatus next = it.next();
String name = next.getPath().getName();
String owner = next.getOwner();
String group = next.getGroup();
long len = next.getLen();
long accessTime = next.getAccessTime();
BlockLocation[] blockLocations = next.getBlockLocations();
System.out.println(name+"\t"+owner+"\t"+group+"\t"+len+"\t"+accessTime);
System.out.println(Arrays.toString(blockLocations));
for (BlockLocation blockLocation : blockLocations) {
String[] hosts = blockLocation.getHosts();
for (String host : hosts) {
System.out.println("host:"+host);
}
}
System.out.println("-----------------------------------------------");
}
// 3 关闭资源
fs.close();
}
}
(6)HDFS文件和文件夹判断
@Test
public void testJudge() throws IOException, InterruptedException, URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), configuration, "offcn");
// 2 操作
FileStatus[] fileStatuses = fs.listStatus(new Path("/0826"));
for (FileStatus fileStatus : fileStatuses) {
if(fileStatus.isDirectory()){
System.out.println(fileStatus.getPath()+" 是目录");
}else{
System.out.println(fileStatus.getPath()+" 不是目录");
}
}
boolean directory = fs.isDirectory(new Path("/0826"));
System.out.println(directory);
// 3 关闭资源
fs.close();
}
(7)通过IO流操作HDFS
a.通过IO流上传文件
@Test
public void testIOUpload() throws IOException, InterruptedException, URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bd-offcn-01:8020"), configuration, "offcn");
// 2 创建输入流,读取本地磁盘的文件到内存
FileInputStream fis = new FileInputStream("D:/test/test.jpg");
// 3 创建输出流,将内存中的数据写出到hdfs
FSDataOutputStream fsdos = fs.create(new Path("/0826/03/testio.jpg"));
// 4 流对接,边读边写
IOUtils.copyBytes(fis,fsdos,configuration);
// 4 关闭资源
IOUtils.closeStream(fis);
IOUtils.closeStream(fsdos);
fs.close();
}
问题:
HDFS提供了Java Native API,客户端应用程序使用它可以高效的访问HDFS。但是如果客户端应用程序位于HDFS集群之外怎么办?必须安装个Hadoop库和Java库?所以,为了解决这个问题,前赴后续的出现了一批项目,例如:Yahoo的HFTP和HdfsProxy V3,Cloudera的Hoop。但是大浪淘沙,目前胜出的就是HortonWorks开发的WebHDFS和Clouera开发的HttpFS。
它们的目标其实完全是一致的:就是让身处HDFS集群之外的应用程序,不但不用安装Hadoop和Java库,并且可以通过流行的REST风格的接口去访问HDFS集群,还有HttpFS与WebHDFS的HTTP REST API完全兼容。这样一来,不管是使用C++、Python或其它语言的外部程序,都可以以一种统一的方式访问HDFS
(四)WebHDFS
WebHDFS 是HortonWorks开发的,后捐给了Apache。WebHDFS 提供了访问HDFS的RESTful接口,内置组件,默认开启。
WebHDFS 使得集群外的客户端可以不用安装HADOOP和JAVA环境就可以对HDFS进行访问,且客户端不受语言限制。
当客户端请求某文件时,WebHDFS会将其重定向到该资源所在的datanode。
2、OP的操作指南:
3、列表展示目录下的文件:
hadoop fs -ls /javaAPI其实相当于
hadoop fs -ls hdfs://bd-offcn-01:8020/javaAPI
提前安装好Postwoman测试工具。也可以直接在浏览器地址栏中输入测试。
相当于请求URL:http://bd-offcn-01:9870/webhdfs/v1/javaAPI?op=LISTSTATUS
4、读取指定文件的内容:
http://bd-offcn-01:9870/webhdfs/v1/bigdata/README.txt?op=OPEN&noredirect=false
其中noredirect参数用于指定是否重定向到一个datanode,在该节点可以读取文件数据。如果不重定向设置为true则返回数据所在datanode的具体位置。http://bd-offcn-01:9870/webhdfs/v1/bigdata/README.txt?op=OPEN&noredirect=true
5、创建文件并写入数据
(1)创建文件
在/javaAPI/目录中创建一个名字为test03.txt文件,并写入内容。
使用postwoman创建一个请求,设置请求方式为PUT,请求url为:
HTTP会响应一个用于上传数据的URL链接:
{
"Location": "http://node-3:9864/webhdfs/v1/javaAPI/test03.txt?op=CREATE&namenoderpcaddress=bd-offcn-01:8020&createflag=&createparent=true&overwrite=true&replication=2"
}
(2)写入数据
使用Location标头中的URL提交另一个HTTP PUT请求(如果指定了noredirect,则返回返回的响应),并写入要写入的文件数据。
客户端接收到一个201创建的响应,该响应的内容长度为零,位置头中文件的WebHDFS URI为:
General:
Request URL: http://node-2:9864/webhdfs/v1/javaAPI/test03.txt?op=CREATE&namenoderpcaddress=bd-offcn-01:8020&createflag=&createparent=true&overwrite=true&replication=2
Request Method: PUT
Status Code: 201
Response Headers:
access-control-allow-origin: *
connection: close
content-length: 0
location: hdfs://bd-offcn-01:8020/javaAPI/test03.txt
(五)HttpFS
HttpFS是独立于HDFS的一个服务。对HDFS文件的读写,将会通过它进行中转,它能限制带宽占用。HttpFS是一个独立于HadoopNameNode的服务,它本身就是Java JettyWeb应用程序。端口为14000
1、修改配置core-site.xml
指定offcn用户代理所有主机的所有组的所有用户
<property>
<name>hadoop.proxyuser.offcn.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.offcn.groups</name>
<value>*</value>
</property>
2、启动服务
hdfs --daemon start httpfs
3、访问首页即可:
http://bd-offcn-01:14000/static/index.html
4、查看目录下所有文件
http://bd-offcn-01:14000/webhdfs/v1?op=LISTSTATUS
httpFS的访问需要执行当前用户身份
http://bd-offcn-01:14000/webhdfs/v1?user.name=offcn&op=LISTSTATUS
5、查看文件内容:
http://bd-offcn-01:14000/webhdfs/v1/javaAPI/test03.txt?user.name=offcn&op=OPEN
三、HDFS的读写流程
HDFS和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用,这得益于它优秀的架构设计。
(一)架构设计
HDFS组成架构如图所示:
架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary NameNode。下面我们分别介绍这四个组成部分。
1、Client
client就是客户端,它负责
a)文件切分。文件上传HDFS的时候,并不是把一个大文件原封不动的上传上去,而而是由Client先将文件切分成一个一个的block,然后按照block进行存储
b)与NameNode交互,获取文件的位置信息,客户端要想传输数据,必须先于namenode通信,获取相应的datanode的地址。
c)与DataNode交互,读取或者写入数据,datanode是实际负责存储文件的。
d)Client提供一些命令来管理HDFS,比如启动或者关闭HDFS;
e)Client可以通过一些命令来访问HDFS。
2、NameNode
namenode是Master,它是一个主管、管理者,类似于会计,管账的。
a)管理HDFS的名称空间;namespace
b)管理数据块(Block)映射信息;
c)配置副本策略(默认)3
d)处理客户端读写请求。
3、DataNode
datanode是Slave,干活的,类似于出纳,管钱。NameNode下达命令,DataNode执行实际的操作,datanode是进程,它在接收到用户传递过来的数据后,将数据存储到本地的文件系统。
a)存储实际的数据块;
b)执行数据块的读/写操作。
4、SecondaryNameNode
并非NameNode的热备。所谓的热备指的是,当namenode挂了之后,secondarynamenode马上就成承担namenode的任务。而实际上,当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
a)辅助NameNode,分担其工作量;
b)定期合并fsimage和Edits,并推送给NameNode;
c)在紧急情况下,可辅助恢复NameNode。
(二)HDFS上传(写)流程
HDFS写数据流程,如图所示:
(1)客户端向hdfs上传文件,首先向NameNode请求上传文件,NameNode会做一些验证,比如检查目标文件是否已存在,父目录是否存在。
(2)NameNode经过验证后,向客户端返回是否可以上传。
(3)如果客户端收到可以上传的回复,则会向namenode请求第一个 block上传到哪几个datanode服务器上。
(4)NameNode返回客户端可用的3个datanode的节点地址,分别为datanode1、datanode2、datanode3。
(5)客户端通过FSDataOutputStream模块请求datanode1上传数据,datanode1收到请求会继续调用datanode2,然后datanode2调用datanode3,将这个通信管道建立完成。
(6)datanode1、datanode2、datanode3逐级应答客户端。
(7)客户端开始往datanode1上传第一个block,以packet为单位,datanode1收到一个packet不仅后存储到本地磁盘还会将该packet复制一份传给datanode2,datanode2传给datanode3;
当一个block传输完成之后,客户端再次请求NameNode上传第二个block的服务器。(重复执行3-7步)。
(三)网络拓扑-节点距离计算
在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和。
Distance(/d1/r1/n0, /d1/r1/n0)=0(同一节点上的进程)
Distance(/d1/r1/n1, /d1/r1/n2)=2(同一机架上的不同节点)
Distance(/d1/r2/n0, /d1/r3/n2)=4(同一数据中心不同机架上的节点)
Distance(/d1/r2/n1, /d2/r4/n1)=6(不同数据中心的节点)
例如,假设有数据中心d1机架r1中的节点n1。该节点可以表示为/d1/r1/n1。利用这种标记,这里给出四种距离描述,如图所示。
可以算一算每两个节点之间的距离,如图所示,例如5和9的节点距离为3。
(四)副本机制(机架感知)
机架感知说明
For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode in the same rack as that of the writer, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack.
副本选择策略:
第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。
第二个副本在另一个机架的随机一个节点。
第三个副本在第二个副本所在机架的随机节点。
源码说明
Crtl+n查找BlockPlacementPolicyDefault
(五)HDFS下载(读)流程
HDFS的读数据流程,如图所示:
(1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以packet为单位来做校验)。
(4)客户端以packet为单位接收,先在本地缓存,然后写入目标文件。
(5)客户端将所有的块下载下来之后,在本地将所有的块拼接成一个文件。
四、HDFS的各角色工作流程
(一)NameNode执行流程
思考:NameNode中的元数据是存储在哪里的?
首先,我们做个假设,如果存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并。
(二)SecondaryNameNode工作流程
1、详细执行流程
- Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
- Secondary NameNode请求执行CheckPoint。
- NameNode滚动正在写的Edits日志。
- 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
- Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
- 生成新的镜像文件fsimage.chkpoint。
- 拷贝fsimage.chkpoint到NameNode。
- NameNode将fsimage.chkpoint重新命名成fsimage。
2、Fsimage和Edits解析
(1)概念
namenode被格式化之后,将在/home/offcn/data/dfs/name/current目录中产生类似如下文件:
fsimage_0000000000000000000
fsimage_0000000000000000000.md5
seen_txid
VERSION
(1)fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件的序列化信息。
(2)edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。
(3)seen_txid文件保存的是一个数字,就是最后一个edits_的数字
每次NameNode启动的时候都会将fsimage文件读入内存,并执行edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将fsimage和edits文件进行了合并。
(2)oiv查看fsimage文件
a.查看oiv和oev命令
[offcn@bd-offcn-01 current]$ hdfs
oiv apply the offline fsimage viewer to an fsimage
oev apply the offline edits viewer to an edits file
b.基本语法
hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
c.案例实操
[offcn@bd-offcn-01 current]$ pwd
/home/offcn/data/dfs/name/current
[offcn@bd-offcn-01 current]$ hdfs oiv -p XML -i fsimage_0000000000000000025 -o /home/offcn/apps/hadoop-3.2.1/fsimage.xml
[offcn@bd-offcn-01 current]$ cat /home/offcn/apps/hadoop-3.2.1/fsimage.xml
将显示的xml文件内容拷贝到Idea中创建的xml文件中,并格式化。部分显示结果如下。Xml参数必须大写。
<inode>
<id>16386</id>
<type>DIRECTORY</type>
<name>user</name>
<mtime>1512722284477</mtime>
<permission>offcn:supergroup:rwxr-xr-x</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16387</id>
<type>DIRECTORY</type>
<name>root</name>
<mtime>1512790549080</mtime>
<permission>offcn:supergroup:rwxr-xr-x</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16389</id>
<type>FILE</type>
<name>wc.input</name>
<replication>3</replication>
<mtime>1512722322219</mtime>
<atime>1512722321610</atime>
<perferredBlockSize>134217728</perferredBlockSize>
<permission>offcn:supergroup:rw-r--r--</permission>
<blocks>
<block>
<id>1073741825</id>
<genstamp>1001</genstamp>
<numBytes>59</numBytes>
</block>
</blocks>
</inode >
(3)oev查看edits文件
a.基本语法
hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
b.案例实操
[offcn@bd-offcn-01 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /home/offcn/apps/hadoop-3.2.1/edits.xml
[offcn@bd-offcn-01 current]$ cat /home/offcn/apps/hadoop-3.2.1/edits.xml
将显示的xml文件内容拷贝到Idea中创建的xml文件中,并格式化。显示结果如下。
<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
<EDITS_VERSION>-63</EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>129</TXID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD</OPCODE>
<DATA>
<TXID>130</TXID>
<LENGTH>0</LENGTH>
<INODEID>16407</INODEID>
<PATH>/hello7.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1512943607866</MTIME>
<ATIME>1512943607866</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_-1544295051_1</CLIENT_NAME>
<CLIENT_MACHINE>192.168.1.5</CLIENT_MACHINE>
<OVERWRITE>true</OVERWRITE>
<PERMISSION_STATUS>
<USERNAME>root</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
<RPC_CLIENTID>908eafd4-9aec-4288-96f1-e8011d181561</RPC_CLIENTID>
<RPC_CALLID>0</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
<DATA>
<TXID>131</TXID>
<BLOCK_ID>1073741839</BLOCK_ID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
<DATA>
<TXID>132</TXID>
<GENSTAMPV2>1016</GENSTAMPV2>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD_BLOCK</OPCODE>
<DATA>
<TXID>133</TXID>
<PATH>/hello7.txt</PATH>
<BLOCK>
<BLOCK_ID>1073741839</BLOCK_ID>
<NUM_BYTES>0</NUM_BYTES>
<GENSTAMP>1016</GENSTAMP>
</BLOCK>
<RPC_CLIENTID></RPC_CLIENTID>
<RPC_CALLID>-2</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_CLOSE</OPCODE>
<DATA>
<TXID>134</TXID>
<LENGTH>0</LENGTH>
<INODEID>0</INODEID>
<PATH>/hello7.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1512943608761</MTIME>
<ATIME>1512943607866</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME></CLIENT_NAME>
<CLIENT_MACHINE></CLIENT_MACHINE>
<OVERWRITE>false</OVERWRITE>
<BLOCK>
<BLOCK_ID>1073741839</BLOCK_ID>
<NUM_BYTES>25</NUM_BYTES>
<GENSTAMP>1016</GENSTAMP>
</BLOCK>
<PERMISSION_STATUS>
<USERNAME>root</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
</DATA>
</RECORD>
</EDITS >
3、CheckPoint触发时机
(1)通常情况下,SecondaryNameNode每隔一小时执行一次。如果修改,在hdfs-site中修改。
默认值在[hdfs-default.xml] hadoop-3.2.1-src\hadoop-hdfs-project\hadoop-hdfs\src\main\resources
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
(2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>操作动作次数</description>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description>1分钟检查一次操作次数</description>
</property >
(三)DataNode工作流程
1、详细工作流程
当我们上传文件或者下载文件时,要首先找namenode获取块的位置信息,但是在fsimage,edits文件并没有发现块的位置信息,那么namenode中块的位置信息在哪里存着呢?
(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的块信息,通过dfs.blockreport.intervalMsec(hdfs-site.xml)参数配置。
(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
(4)集群运行中可以安全加入和退出一些机器。
2、安全模式
NameNode启动时,首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项操作。同时,NameNode开始监听DataNode请求,因为hdfs的文件是以块列表的形式存储在DataNode中的,datanode要向namenode汇报它们所维护的块信息,这样namenode才能知道这些块信息,才能够对外正常提供服务。此刻,NameNode运行在安全模式,即NameNode的文件系统对于客户端来说是只读的。在安全模式下,各个DataNode会向NameNode发送最新的块列表信息,NameNode了解到足够多的块位置信息之后,才可对外正常提供服务。
也就是说namenode在刚启动的时候,没有收集到足够多的块信息,还不能对外提供服务,需要在安全模式下做好准备,那么什么时候才认为是收集了足够多的块信息了呢?
如果满足“最小副本条件”,NameNode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.namenode.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以NameNode不会进入安全模式。
(1)检查副本率
副本率=存活副本/总副本
(2)退出安全模式条件
dfs.namenode.safemode.min.datanodes:最小可用 datanode 数量,默认 0,必须大于该值。
dfs.namenode.safemode.threshold-pct:副本数达到最小要求的block 占系统总 block 数的百分比,默认 0.999f,也就是说99.9%的块都拥有dfs.namenode.replication.min个副本。
dfs.namenode.safemode.extension:稳定时间,默认值 30000 毫秒,即 30 秒,达到上述标准后稳定30s。
(3)安全模式命令
集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。
(1)bin/hdfs dfsadmin -safemode get
(2)bin/hdfs dfsadmin -safemode enter
(3)bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态)
(4)bin/hdfs dfsadmin -safemode wait
练习答疑
模拟等待安全模式
(1)先进入安全模式
[offcn@bd-offcn-01 hadoop-2.7.2]$ bin/hdfs dfsadmin -safemode enter
(2)执行下面的脚本
编辑一个脚本,并加执行权限
#!/bin/bash
bin/hdfs dfsadmin -safemode wait
bin/hdfs dfs -put ./hello.txt /bigdata
(3)再打开一个窗口,执行
[offcn@bd-offcn-01 hadoop-2.7.2]$ bin/hdfs dfsadmin -safemode leave
五、动态上线下
(一)节点服役
(1)需求
随着公司业务的增长,数据量越来越大,原有的数据节点的容量已经不能满足存储数据的需求,需要在原有集群基础上动态添加新的数据节点。
(2)环境准备
(1)在bd-offcn-01主机上再克隆一台bd-offcn-04主机
(2)修改IP地址和主机名称
修改hosts文件,添加映射,为了方便,我们将4台机器的hosts文件都一块改了。
sudo vim /etc/hosts
192.168.254.114 bd-offcn-04
192.168.254.115 bd-offcn-05
(3)删除克隆后的主机中原来的HDFS文件系统留存的文件(/home/offcn/logs/hadoop-3.2.1和/home/offcn/data目录下所有内容)
(4)source一下配置文件
[offcn@bd-offcn-04 hadoop-3.2.1]$ source /etc/profile
(5)ssh免密登录(bd-offcn-01、bd-offcn-02免密登录到bd-offcn-04)
(二)节点退役
在namenode机器的hdfs-site.xml配置文件中需要提前配置dfs.hosts.exclude属性,该属性指向的文件就是所谓的黑名单列表,会被namenode排除在集群之外。如果文件内容为空,则意味着不禁止任何机器。
(1)添加白名单
白名单:表示在白名单的主机IP地址可以,用来存储数据,而不在白名单中的datanode虽然可以作为客户端向hdfs上传数据,但是hdfs不会把数据存储到不在白名单的机器,即使不在白名单的机器的进程都在。
企业中:配置白名单,可以尽量防止黑客恶意访问攻击。
配置白名单的具体步骤如下:
1)在NameNode的/home/offcn/apps/hadoop-3.2.1/etc/hadoop目录下创建whitelist和blacklist文件
[offcn@bd-offcn-01 hadoop]$ pwd
/home/offcn/apps/hadoop-3.2.1/etc/hadoop
创建白名单
[offcn@bd-offcn-01 hadoop]$ vi whitelist
添加如下主机名称(不添加bd-offcn-03和bd-offcn-04)
bd-offcn-01
bd-offcn-02
创建黑名单,保持为空即可
[offcn@bd-offcn-01 hadoop]$ touch blacklist
2)在NameNode的hdfs-site.xml配置文件中增加dfs.hosts和dfs.hosts.exclude属性
<!--白名单-->
<property>
<name>dfs.hosts</name>
<value>/home/offcn/apps/hadoop-3.2.1/etc/hadoop/whitelist</value>
</property>
<!--黑名单-->
<property>
<name>dfs.hosts.exclude</name>
<value>/home/offcn/apps/hadoop-3.2.1/etc/hadoop/blacklist</value>
</property>
3)配置文件分发到4台机器
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/hdfs-site.xml bd-offcn-02:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/hdfs-site.xml bd-offcn-03:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/hdfs-site.xml bd-offcn-04:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/whitelist bd-offcn-02:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/whitelist bd-offcn-03:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/whitelist bd-offcn-04:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/blacklist bd-offcn-02:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/blacklist bd-offcn-03:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/blacklist bd-offcn-04:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
4)重启集群
无论是使用白名单还是黑名单,第一次配置必须重启集群,后续可以修改黑白名单内容后,无需重启,刷新即可。
[offcn@bd-offcn-01 hadoop-3.2.1]$ sbin/stop-dfs.sh
[offcn@bd-offcn-01 hadoop-3.2.1]$ sbin/start-dfs.sh
[offcn@bd-offcn-02 hadoop-3.2.1]$ sbin/stop-yarn.sh
[offcn@bd-offcn-02 hadoop-3.2.1]$ sbin/start-yarn.sh
5)测试
查看hdfs的datanode节点,发现只有白名单中的datanode。
http://bd-offcn-01:9870/dfshealth.html#tab-datanode
在bd-offcn-03上传文件,发现虽然bd-offcn-03作为客户端能上传文件,但是在hdfs的web页面观察副本,hdfs并没有使用bd-offcn-03来存储数据,即使bd-offcn-03的datanode进程存在。
[offcn@bd-offcn-03 hadoop-3.2.1]$ hadoop fs -put NOTICE.txt /
修改白名单,添加bd-offcn-03和bd-offcn-04机器,然后将白名单分发到其他机器
[offcn@bd-offcn-01 hadoop]$ vi whitelist
bd-offcn-01
bd-offcn-02
bd-offcn-03
bd-offcn-04
分发:
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/whitelist bd-offcn-02:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/whitelist bd-offcn-03:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/whitelist bd-offcn-04:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
刷新NameNode
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -refreshNodes
这时,在bd-offcn-03上传文件,发现hdfs会将数据存储在bd-offcn-03上。
[offcn@bd-offcn-03 hadoop-3.2.1]$ hadoop fs -put README.txt /
6)如果数据不均衡,可以用命令实现集群的再平衡
[offcn@bd-offcn-01 hadoop-3.2.1]$ sbin/start-balancer.sh
(三)黑名单退役
黑名单:表示在黑名单的主机IP地址不可以,用来存储数据。
企业中:配置黑名单,用来退役服务器。
1)编辑/opt/module/hadoop-3.2.1/etc/hadoop目录下的blacklist文件
[offcn@bd-offcn-01 hadoop]$ vim blacklist
添加如下主机名称(要退役的节点)
bd-offcn-04
2)分发黑名单
[offcn@bd-offcn-01 hadoop]$ blacklist
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/blacklist bd-offcn-02:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/blacklist bd-offcn-03:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/blacklist bd-offcn-04:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
3)如果是第一次添加黑名单,需要重启集群,否则只需要刷新namenode
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -refreshNodes
4)查看web页面(可能需要过一会儿了才能看到效果,多刷新几次),发现正在执行退役,退役节点的状态为Decommissioning(退役中),说明退役节点正在复制块到其他节点,复制完毕后,就会显示Decommissioned(退役的)
5)等待退役节点状态为decommissioned(所有块已经复制完成),手动停止该节点及节点资源管理器进程。注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役
[offcn@bd-offcn-04 hadoop-3.2.1]$ hdfs --daemon stop datanode
[offcn@bd-offcn-04 hadoop-3.2.1]$ yarn --daemon stop nodemanager
6)如果数据不均衡,可以用命令实现集群的再平衡
[offcn@bd-offcn-01 hadoop-3.2.1]$ sbin/start-balancer.sh
注意:不允许白名单和黑名单中同时出现同一个主机名称。
若想让退役的服务器再服役,只需要把它从黑名单清空,黑名单分发,再刷新namenode,启动datanode、nodemanager进程即可。
六、HDFS限额
hdfs文件的限额配置允许我们以文件大小或者文件个数来限制某个目录下上传的文件数量或者文件内容总量,以便达到我们类似百度网盘网盘等限制每个用户允许上传的最大的文件的量
(一)案例配置演示
1、数量限额
可以限制某个目录下上传文件的数量。
创建一个目录
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -mkdir -p /test/quota
设置该目录下限额为2,即最多只能上传1个文件。
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -setQuota 2 /test/quota
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put README.txt /test/quota
2021-03-15 22:02:51,829 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
再上传第2个文件时,发现无法上传。
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put LICENSE.txt /test/quota
put: The NameSpace quota (directories and files) of directory /test/quota is exceeded: quota=2 file count=3
问题:为什么设置的是2只能上传1个文件,提示却是文件有3个?
清除限额设置后,发现又可以上传了
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -clrQuota /test/quota
[offcn@bd-offcn-01 hadoop-3.2.1]$
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put LICENSE.txt /test/quota
2、空间大小限额
限制hdfs空间大小4KB
hdfs dfsadmin -setSpaceQuota 4k /test/quota
上传超过4Kb的文件大小上去提示文件超过限额
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put NOTICE.txt /test/quota
put: The DiskSpace quota of /test/quota is exceeded: quota = 4096 B = 4 KB but diskspace consumed = 402653184 B = 384 MB
清除空间限额后,重新上传成功
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -clrSpaceQuota /test/quota
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put NOTICE.txt /test/quota
七、HDFS的垃圾桶机制
任何一个文件系统,基本上都会有垃圾桶机制,也就是删除的文件,不会直接彻底清掉,我们一把都是将文件放置到垃圾桶当中去,过一段时间之后,自动清空垃圾桶当中的文件,这样对于文件的安全删除比较有保证,避免我们一些误操作,导致误删除文件或者数据
(一)案例配置演示
1、回收站设置
这些配置位于core-site.xml
默认值fs.trash.interval=0,0表示禁用回收站,可以设置删除文件的存活时间。
默认值fs.trash.checkpoint.interval=0,检查回收站的间隔时间,看是否到了删除回收站数据的时候了,如果设置为0,那么该参数的值与fs.trash.interval的值相同。
要求fs.trash.checkpoint.interval<=fs.trash.interval。
2、启用回收站
修改core-site.xml,配置垃圾回收时间为1分钟,到了1分钟就会被删除
<property>
<name>fs.trash.interval</name>
<value>1</value>
</property>
文件分发并重启hdfs
[offcn@bd-offcn-01 ~]$ scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/core-site.xml bd-offcn-02:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
[offcn@bd-offcn-01 ~]$ scp /home/offcn/apps/hadoop-3.2.1/etc/hadoop/core-site.xml bd-offcn-03:/home/offcn/apps/hadoop-3.2.1/etc/hadoop/
注意:网页上删除的文件不走回收站
<!-- 配置 HDFS 网页登录使用的静态用户为 -->
<property>
<name>hadoop.http.staticuser.user</name>
<value>offcn</value>
</property>
3、查看回收站
回收站在集群中的;路径:/user/offcn/.Trash/….
4、启用回收站后,上传并删除文件测试
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put README.txt /user/offcn
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -rm -r /user/offcn/README.txt
2021-03-16 21:58:26,868 INFO fs.TrashPolicyDefault: Moved: 'hdfs://bd-offcn-01:8020/user/offcn/README.txt' to trash at: hdfs://bd-offcn-01:8020/user/offcn/.Trash/Current/user/offcn/README.txt
发现文件删除后,hdfs并不是真正的物理删除,而是把文件移动到了/user/offcn/.Trash/Current/user/offcn/README.txt
5、恢复回收站数据
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -mv /user/offcn/.Trash/Current/user/offcn/README.txt /user/offcn
6、跳过垃圾桶
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -rm -skipTrash /bigdata/README.txt
7、清空回收站
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfs -expunge
注意该命令不会清空回收站,只是将被删除的文件放到类似/user/offcn/.Trash/210316222937这样的目录,到达时间后会自动删除,如果要彻底删除的话,可以手动执行删除该目录。
八、HDFS归档机制
每个文件均按块存储,每个块的元数据存储在namenode的内存中,因此hadoop存储小文件会非常低效。因为大量的小文件会耗尽namenode中的大部分内存。但注意,存储小文件所需要的磁盘容量和存储这些文件原始内容所需要的磁盘空间相比也不会增多。例如,一个1MB的文件以大小为128MB的块存储,使用的是1MB的磁盘空间,而不是128MB。
Hadoop存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少namenode内存使用的同时,允许对文件进行透明的访问。同时,Hadoop存档文件可以用作MapReduce的输入。
小文件合并,大小无改变,只是将打包,底层执行的mr程序
(1)需要启动yarn进程
start-yarn.sh
(2)归档文件
创建一个测试目录,并向该目录下上传多个小文件。
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -mkdir -p /user/offcn/hartest
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put README.txt LICENSE.txt NOTICE.txt /user/offcn/hartest
归档成一个叫做xxx.har的文件夹,该文件夹下有相应的数据文件。Xx.har目录是一个整体,该目录看成是一个归档文件即可。
将/user/offcn/hartest下的所有文件归档成myhar.har放到/user目录下。
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop archive -archiveName myhar.har -p /user/offcn/hartest /user
(3)查看归档
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -ls -r /user/myhar.har
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -ls -r har:///user/myhar.har
(4)解归档文件
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -cp har:///user/myhar.har/* /user
九、快照机制
Hadoop从2.1.0版开始提供了HDFS SnapShot的功能。一个snapshot(快照)是一个全部文件系统、或者某个目录在某一时刻的镜像。快照在下面场景下是非常有用:
防止用户的错误操作:
管理员可以通过以滚动的方式周期性设置一个只读的快照,这样就可以在文件系统上有若干份只读快照。如果用户意外地删除了一个文件,就可以使用包含该文件的最新只读快照来进行回复。
备份:
管理员可以根据需求来备份整个文件系统,一个目录或者单一一个文件。管理员设置一个只读快照,并使用这个快照作为整个全量备份的开始点。增量备份可以通过比较两个快照的差异来产生。
试验/测试:
一个用户当想要在数据集上测试一个应用程序。一般情况下,如果不做该数据集的全量拷贝,测试应用程序会覆盖/损坏原来的生产数据集,这是非常危险的。管理员可以为用户设置一个生产数据集的快照(Read write)用于用户测试使用。在快照上的改变不会影响原有数据集。灾难恢复:只读快照可以被用于创建一个一致的时间点镜像用于拷贝到远程站点作灾备冗余。
通过下面命令对某一个路径(根目录/,某一目录或者文件)开启快照功能,那么该目录就成为了一个snapshottable的目录。snapshottable下存储的snapshots 最多为65535个,保存在该目录的.snapshot下。
1、基本语法
(1)hdfs dfsadmin -allowSnapshot 路径 (功能描述:开启指定目录的快照功能)
(2)hdfs dfsadmin -disallowSnapshot 路径 (功能描述:禁用指定目录的快照功能,默认是禁用)
(3)hdfs dfs -createSnapshot 路径 (功能描述:对目录创建快照)
(4)hdfs dfs -createSnapshot 路径 名称 (功能描述:指定名称创建快照)
(5)hdfs dfs -renameSnapshot 路径 旧名称 新名称 (功能描述:重命名快照)
(6)hdfs lsSnapshottableDir (功能描述:列出当前用户所有可快照目录)
(7)hdfs snapshotDiff 路径1 路径2 (功能描述:比较两个快照目录的不同之处)
(8)hdfs dfs -deleteSnapshot <path> <snapshotName> (功能描述:删除快照)
2、案例实操
准备测试目录,并上传两个文件。
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -mkdir -p /user/offcn/snaptest
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put LICENSE.txt README.txt /user/offcn/snaptest
(1)开启/禁用指定目录的快照功能
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -allowSnapshot /user/offcn/snaptest
Allowing snapshot on /user/offcn/snaptest succeeded
[offcn@bd-offcn-01 hadoop-3.2.1]$
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -disallowSnapshot /user/offcn/snaptest
Disallowing snapshot on /user/offcn/snaptest succeeded
[offcn@bd-offcn-01 hadoop-3.2.1]$
(2)对目录创建快照
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfsadmin -allowSnapshot /user/offcn/snaptest
Allowing snapshot on /user/offcn/snaptest succeeded
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfs -createSnapshot /user/offcn/snaptest
Created snapshot /user/offcn/snaptest/.snapshot/s20210317-194233.925
如果不指定快照名称的话,会自动生成快照名称。
通过web访问如下地址,查看快照
http://bd-offcn-01:9870/explorer.html#/user/offcn/snaptest/.snapshot
(3)指定名称创建快照
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfs -createSnapshot /user/offcn/snaptest hahaha
Created snapshot /user/offcn/snaptest/.snapshot/hahaha
(4)重命名快照
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfs -renameSnapshot /user/offcn/snaptest s20210624-113206.301 mysnapshot
(5)列出当前用户所有可快照目录
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs lsSnapshottableDir
drwxr-xr-x 0 offcn supergroup 0 2021-03-17 19:42 1 65536 /user/offcn/snaptest
(6)比较两个快照目录的不同之处
在对测试目录创建完快照后,我们向测试目录上传一个新文件,并删除原来一个文件,查看测试目录当下与快照时的不同。
结果发现:快照时的目录比现在的目录少一个NOTICE.txt文件,多一个LICENSE.txt文件。
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -put NOTICE.txt /user/offcn/snaptest
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -rm -r /user/offcn/snaptest/LICENSE.txt
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs snapshotDiff /user/offcn/snaptest . mysnapshot
Difference between current directory and snapshot mysnapshot under directory /user/offcn/snaptest:
M .
- ./NOTICE.txt
+ ./LICENSE.txt
(7)恢复快照
[offcn@bd-offcn-01 hadoop-3.2.1]$ hadoop fs -cp /user/offcn/snaptest/.snapshot/mysnapshot /user
(8)删除快照
[offcn@bd-offcn-01 hadoop-3.2.1]$ hdfs dfs -deleteSnapshot /user/offcn/snaptest mysnapshot
十、擦除编码(纠删码)机制
为了提供容错能力,HDFS会根据replication factor(复制因子)在不同的DataNode上复制文件块。
默认复制因子为3(注意这里的3指的是1+2=3,不是额外3个),则原始块除外,还将有额外两个副本。每个副本使用100%的存储开销,因此导致200%的存储开销。这些副本也消耗其他资源,例如网络带宽。
在复制因子为N时,存在N-1个容错能力,但存储效率仅为1/N。
纠删码操作相关的命令:
[offcn@bd-offcn-01 ~]$ hdfs ec
Usage: bin/hdfs ec [COMMAND]
[-listPolicies]
[-addPolicies -policyFile <file>]
[-getPolicy -path <path>]
[-removePolicy -policy <policy>]
[-setPolicy -path <path> [-policy <policy>] [-replicate]]
[-unsetPolicy -path <path>]
[-listCodecs]
[-enablePolicy -policy <policy>]
[-disablePolicy -policy <policy>]
[-help <command-name>]
列出所有支持的策略或者说算法
[offcn@bd-offcn-01 ~]$ hdfs ec -listPolicies
Erasure Coding Policies:
ErasureCodingPolicy=[Name=RS-10-4-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=10, numParityUnits=4]], CellSize=1048576, Id=5], State=DISABLED
ErasureCodingPolicy=[Name=RS-3-2-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=3, numParityUnits=2]], CellSize=1048576, Id=2], State=DISABLED
ErasureCodingPolicy=[Name=RS-6-3-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=1], State=ENABLED
ErasureCodingPolicy=[Name=RS-LEGACY-6-3-1024k, Schema=[ECSchema=[Codec=rs-legacy, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=3], State=DISABLED
ErasureCodingPolicy=[Name=XOR-2-1-1024k, Schema=[ECSchema=[Codec=xor, numDataUnits=2, numParityUnits=1]], CellSize=1048576, Id=4], State=DISABLED
纠删码策略解释:
RS-3-2-1024k:使用RS编码,每3个数据单元,生成2个校验单元,共5个单元,也就是说:这5个单元中,只要有任意的3个单元存在(不管是数据单元还是校验单元,只要总数=3),就可以得到原始数据。每个单元的大小是1024k=1024*1024=1048576。
RS-10-4-1024k:使用RS编码,每10个数据单元(cell),生成4个校验单元,共14个单元,也就是说:这14个单元中,只要有任意的10个单元存在(不管是数据单元还是校验单元,只要总数=10),就可以得到原始数据。每个单元的大小是1024k=1024*1024=1048576。
RS-6-3-1024k:使用RS编码,每6个数据单元,生成3个校验单元,共9个单元,也就是说:这9个单元中,只要有任意的6个单元存在(不管是数据单元还是校验单元,只要总数=6),就可以得到原始数据。每个单元的大小是1024k=1024*1024=1048576。
RS-LEGACY-6-3-1024k:策略和上面的RS-6-3-1024k一样,只是编码的算法用的是rslegacy。
XOR-2-1-1024k:使用XOR编码(速度比RS编码快),每2个数据单元,生成1个校验单元,共3个单元,也就是说:这3个单元中,只要有任意的2个单元存在(不管是数据单元还是校验单元,只要总数=2),就可以得到原始数据。每个单元的大小是1024k=1024*1024=1048576。
(一)案例配置演示
纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。
默认只开启对RS-6-3-1024k策略的支持,如要使用别的策略需要提前启用。
需求:将/user/offcn/testrs目录设置为RS-3-2-1024k策略
1)开启对RS-3-2-1024k策略的支持
[offcn@bd-offcn-01 ~]$ hdfs ec -enablePolicy -policy RS-3-2-1024k
Erasure coding policy RS-3-2-1024k is enabled
[offcn@bd-offcn-01 ~]$ hdfs ec -listPolicies
Erasure Coding Policies:
ErasureCodingPolicy=[Name=RS-10-4-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=10, numParityUnits=4]], CellSize=1048576, Id=5], State=DISABLED
ErasureCodingPolicy=[Name=RS-3-2-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=3, numParityUnits=2]], CellSize=1048576, Id=2], State=ENABLED
ErasureCodingPolicy=[Name=RS-6-3-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=1], State=ENABLED
ErasureCodingPolicy=[Name=RS-LEGACY-6-3-1024k, Schema=[ECSchema=[Codec=rs-legacy, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=3], State=DISABLED
ErasureCodingPolicy=[Name=XOR-2-1-1024k, Schema=[ECSchema=[Codec=xor, numDataUnits=2, numParityUnits=1]], CellSize=1048576, Id=4], State=DISABLED
(2)在HDFS创建目录,并设置RS-3-2-1024k策略
[offcn@bd-offcn-01 ~]$ hadoop fs -mkdir -p /user/offcn/testrs
[offcn@bd-offcn-01 ~]$ hdfs ec -setPolicy -path /user/offcn/testrs -policy RS-3-2-1024k
Set RS-3-2-1024k erasure coding policy on /user/offcn/testrs
(3)上传文件,并查看文件编码后的存储情况
[offcn@bd-offcn-01 ~]$ hdfs dfs -put app-2021-05-05.log /user/offcn/testrs
注:你所上传的文件需要大于2M才能看出效果。(低于2M,只有一个数据单元和两个校验单元)
(4)查看存储路径的数据单元和校验单元,并作破坏实验
十一、HDFS的权限管理
1、总览概述
(1)认证、授权和审计
- 认证(Authentication)、授权(Authorization)和审计(Accounting)指计算机安全领域的一个架构模式。通常缩写为 AAA。
- 在该模式中,使用服务的用户先要证明自己的身份;然后根据规则被授予权限,同时其操作被记录下来留待审计。
例如Linux的系统认证:
认证
授权
审计
(2)HDFS的权限管理
作为分布式文件系统,HDFS也集成了一套权限管理系统。客户端在进行每次文件操时,系统会从用户身份认证和数据访问授权两个环节进行验证:
客户端的操作请求会首先通过本地的用户身份验证机制来获得“凭证”(类似于身份证书),然后系统根据此“凭证”分辨出合法的用户名,再据此查看该用户所访问的数据是否已经授权。一旦这个流程中的某个环节出现异常,客户端的操作请求便会失败。
2、UGO权限管理
(1)HDFS的文件权限介绍
HDFS的文件权限与Linux/Unix系统的UGO模型类型类似,可以简单描述为:每个文件和目录都与一个所有者和一个组相关联。该文件或目录对作为所有者(USER)的用户,作为该组成员的其他用户(GROUP)以及对所有其他用户(OTHER)具有单独的权限。
在HDFS中,对于文件,需要r权限才能读取文件,而w权限才能写入或追加到文件。没有x可执行文件的概念。
对于目录,需要r权限才能列出目录的内容,需要w权限才能创建或删除文件或目录,并且需要x权限才能访问目录的子级。
(2)umask权限掩码
Linux中umask可用来设定权限掩码。权限掩码是由3个八进制的数字所组成,将现有的存取权限减掉权限掩码后,即可产生建立文件时预设的权限。
与Linux/Unix系统类似,HDFS也提供了umask掩码,用于设置在HDFS中默认新建的文件和目录权限位。默认umask值有属性fs.permissions.umask-mode指定,默认值022。
创建文件和目录时使用的umask,默认的权限就是:777-022=755。也就是drwxr-xr-x。
(3)UGO权限相关命令
hadoop fs -chmod 750 /zhangsan/d1 //变更目录或文件的权限位
hadoop fs -chown zhangsan:zhangsan /zhangsan/d1 //变更目录或文件的属主或用户组
hadoop fs -chgrp offcn /zhangsan/d1 //变更用户组
需要注意的是,使用这个命令的用户必须是超级用户,或者是该文件的属主,同时也是该用户组的成员。
(4)Web页面修改UGO权限
Hadoop3.0之后,支持在HDFS Web页面上使用鼠标修改。
注意:如果需要在webui上操作权限,需要设置hdfs的静态用户为offcn
vim core-site.xml
<property>
<name>hadoop.http.staticuser.user</name>
<value>offcn</value>
</property>
粘滞位(Sticky bit)用法在目录上设置,如此以来,只有目录内文件的所有者或者超级管理员才可以删除或移动该文件。如果不为目录设置粘滞位,任何具有该目录写和执行权限的用户都可以删除和移动其中的文件。实际应用中,粘滞位一般用于/tmp目录,以防止普通用户删除或移动其他用户的文件。
3、用户身份认证
用户身份认证独立于HDFS之外,也就说HDFS并不负责用户身份合法性检查,但HDFS会通过相关接口来获取相关的用户身份,然后用于后续的权限管理。用户是否合法,完全取决于集群使用认证体系。目前社区支持两种身份认证,即简单认证(Simple)和Kerberos。模式由hadoop.security.authentication属性指定,默认simple。
(1)Simple认证
基于客户端所在的Linux/Unix系统的登录用户名来进行认证。只要用户能正常登录就认证成功。客户端与NameNode交互时,会将用户的登录账号(通过类似whoami的命令来获取)作为合法用户名传递至Namenode。 这意味着使用不同的账号登录到同一个客户端,会产生不同的用户名,故在多租户条件这种认证会导致权限混淆;同时恶意用户也可以伪造其他人的用户名非法获得相应的权限,对数据安全造成极大的隐患。线上生产环境一般不会使用。simple认证时,HDFS想法是:防止好人误做坏事,不防止坏人做坏事。
(2)Kerberos认证(了解)
在神话里,Kerberos是Cerberus的希腊语,是一只守护地狱入口的三头巨犬,它确保没有人能在进入地狱后离开。
从技术角度来说,Kerberos是麻省理工学院(MIT)开发的一种网络身份认证协议。它旨在通过使用密钥加密技术为客户端/服务器应用程序提供强身份验证。
5、ACL权限管理
(1)背景和介绍
在UGO权限中,用户对文件只有三种身份,就是属主(user)、属组(group)和其他人(other):每种用户身份拥有读(read)、写(write)和执行(execute)三种权限。但是在实际工作中,使用UGO来控制权限可以满足大部分场景下的数据安全性要求,但是对于一些复杂的权限需求则无能为力。
文件系统根目录中有一个 /project 目录,这是班级的项目目录。班级中的每个学员都可以访问和修改这个目录,老师也需要对这个目录拥有访问和修改权限,其他班级的学员当然不能访问这个目录。需要怎么规划这个目录的权限呢?应该这样:老师使用 root 用户,作为这个目录的属主,权限为 rwx;班级所有的学员都加入 tgroup 组,使 tgroup 组作为 /project目录的属组,权限是 rwx;其他人的权限设定为 0。这样这个目录的权限就可以符合我们的项目开发要求了。
有一天,班里来了一位试听的学员 st,她必须能够访问/project 目录,所以必须对这个目录拥有 r 和 x 权限;但是她又没有学习过以前的课程,所以不能赋予她 w 权限,怕她改错了目录中的内容,所以学员 st 的权限就是 r-x。可是如何分配她的身份呢?变为属主?当然不行,要不 root 该放哪里?加入 tgroup 组?也不行,因为 tgroup 组的权限是 rwx,而我们要求学员 st 的权限是 r-x。如果把其他人的权限改为 r-x 呢?这样一来,其他班级的所有学员都可以访问 /project 目录了。
当出现这种情况时,普通权限中的三种身份就不够用了。ACL 权限就是为了解决这个问题的。在使用 ACL 权限给用户 st 陚予权限时,st 既不是 /project 目录的属主,也不是属组,仅仅赋予用户 st 针对此目录的 r-x 权限。
ACL是Access Control List(访问控制列表)的缩写,ACL提供了一种方法,可以为特定的用户或组设置不同的权限,而不仅仅是文件的所有者和文件的组。
vim hdfs-site.xml
<!-- 开启ACL认证 -->
<property>
<name>dfs.namenode.acls.enabled</name>
<value>true</value>
</property>
(2)ACL Shell命令
hadoop fs -getfacl [-R] <path>
显示文件和目录的访问控制列表(ACL)。如果目录具有默认ACL,则getfacl还将显示默认ACL。
hadoop fs [generic options] -setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]
设置文件和目录的访问控制列表(ACL)。
hadoop fs -ls <args>
ls的输出将在带有ACL的任何文件或目录的权限字符串后附加一个'+'字符。
(3)ACL操作实战
[offcn@bd-offcn-01 hadoop]$ hadoop fs -getfacl /testacl
# file: /testacl
# owner: dr.who
# group: supergroup
# flags: --t
user::rwx
group::rwx
other::rwx
使用ACL给testacl用户单独添加rwx权限
[offcn@bd-offcn-01 hadoop]$ hadoop fs -setfacl -m user:testacl:rwx /testacl
设置成功之后查看ACL权限
[offcn@bd-offcn-01 hadoop]$ hadoop fs -getfacl /testacl
# file: /testacl
# owner: dr.who
# group: supergroup
# flags: --t
user::rwx
user:testacl:rwx
group::rwx
mask::rwx
other::rwx
1、带有ACL的任何文件或目录的权限字符串后附加一个'+'字符
[offcn@bd-offcn-01 hadoop]$ hadoop fs -ls /
Found 8 items
drwxrwxrwt+ - dr.who supergroup 0 2021-05-21 00:14 /testacl
drwxr-xr-x - offcn supergroup 0 2021-05-11 22:04 /har-demo
drwxr-xr-x - offcn supergroup 0 2021-05-19 22:38 /home
drwxr-xr-x - Jocker supergroup 0 2021-05-11 08:39 /javaAPI
drwxr-xr-x - offcn supergroup 0 2021-05-11 20:13 /system
drwxr-xr-x - offcn supergroup 0 2021-05-19 22:44 /test
drwx------ - offcn supergroup 0 2021-05-19 22:44 /tmp
drwxr-xr-x - offcn supergroup 0 2021-05-19 20:37 /user
2、删除指定的ACL条目
[[offcn@bd-offcn-01 hadoop]$ hadoop fs -setfacl -x user:testacl /testacl
3、设置默认的ACl权限,以后在该目录中新建文件或者子目录时,新建的文件/目录的ACL权限都是之前设置的default ACLs
[[offcn@bd-offcn-01 hadoop]$ hadoop fs -setfacl -m default:user:testacl:rwx /testacl
[offcn@bd-offcn-01 hadoop]$ hadoop fs -getfacl /testacl
# file: /testacl
# owner: dr.who
# group: supergroup
# flags: --t
user::rwx
group::rwx
other::rwx
default:user::rwx
default:user:testacl:rwx
default:group::rwx
default:mask::rwx
default:other::rwx
4、删除默认ACL权限
hadoop fs -setfacl -k /testacl