目录
- 一、操作
- 1. web工具
- 2.命令行----常用命令
- 3.Java API
- JavaAPI创建HDFS目录,获取HDFS修改权限
- JavaAPI上传和下载数据
- 使用JavaAPI获取HDFS元信息
- 二、HDFS原理解析
- 1.数据上传
- 2.数据下载
- 三、HDFS的高级特性
- 1.回收站
- 2.快照
- 3.配额Quota
- 4.安全模式
- 5.权限管理
- 命令行
- JavaAPI
- 6.HDFS集群
- 四、HDFS底层原理
- 1.Java代理对象Proxy
- 2.RPC协议
一、操作
1. web工具
NameNode端口:50070
SecondaryNameNode端口:50090
运行代码
start-all.sh
启动Hadoop后,通过以下网址,对NameNode和SecondaryNameNode进行访问,网址内部记载了详细信息(具体请自行查看,网址内容为 虚拟机IP/+端口)
NameNode:
http://192.168.80.111:50070/dfshealth.html#tab-overview
SecondaryNameNode:
http://192.168.80.111:50090/status.html
2.命令行----常用命令
只写了几个常用的,具体用法请自行搜索
hdfs dfs //关于目录和文件操作的命令(键入查看所有)
- mkdir:在HDFS中创建目录
hdfs dfs -mkdir /a
创建目录a
hdfs dfs -mkdir -p /b/c
创建目录b和目录c(若父目录不存在,先创建父目录)- ls:查看HDFS的某个目录
hdfs dfs ls /
- ls -R :查看HDFS的某个目录即目录下的子目录
hdfs dfs ls -R /
- put:上传数据
- copyFromLocal:上传数据
- moveFromLocal:上传数据后,删除本地数据(剪切)
- get:下载
hdfs dfs get /a/data.txt .
下载文件到当前路径- copyToLocal:下载
- rm:删除目录
- rmr:删除目录,包含子目录
- getmerge:先将某个目录下的文件合并,之后下载
- cp:复制
- mv:剪切
- count:查看目录下的文件个数以及大小
- du:相较于count时更详细的查看
- text:查看文本文件内容
- cat:查看文本文件内容
- balancer:平衡操作
hdfs dfsadmin //关于HDFS集群的管理命令(键入查看所有)
- report:显示HDFS状态
- safemode:安全模式(后面跟部分参数,具体自行查看)
3.Java API
jar包路径(自行从安装位置寻找下载,以下为主要jar包的位置):
/root/training/hadoop-2.7.3/share/hadoop/common/*.jar
/root/training/hadoop-2.7.3/share/hadoop/common/lib/*.jar
/root/training/hadoop-2.7.3/share/hadoop/hdfs/*.jar
/root/training/hadoop-2.7.3/share/hadoop/hdfs/lib/*.jar
Idea创建相关工程并引用库
引用库(jar包的位置)
JavaAPI创建HDFS目录,获取HDFS修改权限
运行代码如下:
package com.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
public class mkdir {
//设置系统属性,模拟root用户,取得操作权限
@Test
public void test1() throws Exception{
//设置系统属性,即JAVA运行的环境,模拟root用户,避免权限不足导致执行失败
System.setProperty("HADOOP_USER_NAME","root");
//指定NameNode地址
Configuration conf =new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS","hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//创建目录
client.mkdirs(new Path("/1_20240810"));
//关闭客户端
client.close();
}
//设置arguments即运行参数,模拟root用户
@Test
public void test2() throws Exception{
//指定NameNode地址
Configuration conf =new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS","hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//创建目录
client.mkdirs(new Path("/2_20240810"));
//关闭客户端
client.close();
}
}
test2的参数配置
运行结果:
当然如果修改HDFS的权限检查即hdfs-site.xml文件中dfs.permissions参数为false也可以,此情况默认不进行任何权限检查
JavaAPI上传和下载数据
运行代码如下
上传:
package com.hadoop;
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.junit.Test;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class Upload {
@Test
public void test1()throws Exception {
//Hadoop基本操作:NameNode设置,客户端创建
//指定NameNode地址
Configuration conf =new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS","hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//构建一个输入流,代表要上传的数据
InputStream input =new FileInputStream("G:\\temp\\hadoop-2.7.3.tar.gz");
//构造一个输出流,指向HDFS,此处的“hadoop-2.7.3.tar.gz"可以重命名为a.tar.gz,一般不要改文件后缀
// 注意:这里的路径是HDFS上的路径,不是本地文件系统路径
OutputStream output =client.create(new Path("/1_20240810/upload_test1.tar.gz"));
// 创建一个字节数组作为缓冲区,用于从输入流读取数据并写入输出流
byte[] buffer = new byte[1024];
用于存储每次从输入流读取的字节数
int len =0;
// 使用循环从输入流读取数据,直到没有更多数据可读
while ((len=input.read(buffer))>0){
//写入
output.write(buffer,0,len);
}
// 刷新输出流,确保所有数据都被写入HDFS
output.flush();
// 关闭输出流和输入流,释放资源
output.close();
input.close();
//关闭客户端,释放与HDFS的连接
client.close();
}
@Test
public void test2()throws Exception {
//Hadoop基本操作:NameNode设置,客户端创建
//指定NameNode地址
Configuration conf =new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS","hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//构建一个输入流,代表要上传的数据
InputStream input =new FileInputStream("G:\\temp\\hadoop-2.7.3.tar.gz");
//构造一个输出流,指向HDFS,此处的“hadoop-2.7.3.tar.gz"可以重命名为a.tar.gz,一般不要改文件后缀
// 注意:这里的路径是HDFS上的路径,不是本地文件系统路径
OutputStream output =client.create(new Path("/1_20240810/upload_test2.tar.gz"));
// 使用IOUtils工具类简化文件复制过程
// IOUtils.copyBytes方法会自动从输入流读取数据并写入到输出流,直到输入流结束
// 这里的1024是缓冲区大小,表示每次从输入流读取的数据量
IOUtils.copyBytes(input, output,1024);
//关闭客户端,释放与HDFS的连接
client.close();
}
}
运行效果
下载
与上传类似,代码如下
package com.hadoop;
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.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class Download {
@Test
public void test1()throws Exception {
//Hadoop基本操作:NameNode设置,客户端创建
//指定NameNode地址
Configuration conf =new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS","hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//构造一个输出流指向本地
OutputStream output=new FileOutputStream("G:\\temp\\1_2024_08_10.tar.gz");
//
InputStream input=client.open(new Path("/1_20240810/upload_test2.tar.gz"));
// 创建一个字节数组作为缓冲区,用于从输入流读取数据并写入输出流
byte[] buffer = new byte[1024];
用于存储每次从输入流读取的字节数
int len =0;
// 使用循环从输入流读取数据,直到没有更多数据可读
while ((len=input.read(buffer))>0){
//写入
output.write(buffer,0,len);
}
// 刷新输出流,确保所有数据都被写入HDFS
output.flush();
// 关闭输出流和输入流,释放资源
output.close();
input.close();
//关闭客户端,释放与HDFS的连接
client.close();
}
@Test
public void test2()throws Exception {
//Hadoop基本操作:NameNode设置,客户端创建
//指定NameNode地址
Configuration conf =new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS","hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//构造一个输出流指向本地
OutputStream output=new FileOutputStream("G:\\temp\\2_2024_08_10.tar.gz");
//
InputStream input=client.open(new Path("/1_20240810/upload_test2.tar.gz"));
// 使用IOUtils工具类简化文件复制过程
// IOUtils.copyBytes方法会自动从输入流读取数据并写入到输出流,直到输入流结束
// 这里的1024是缓冲区大小,表示每次从输入流读取的数据量
IOUtils.copyBytes(input, output,1024);
//关闭客户端,释放与HDFS的连接
client.close();
}
}
效果:
使用JavaAPI获取HDFS元信息
HDFS元信息说明:元信息一般包含1.文件和目录的相关属性;2.文件内容存储的相关信息;3.DataNode信息等
以下为主要代码,具体情况会针对实际变动
package com.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
import org.apache.zookeeper.server.DataNode;
import org.junit.Test;
import java.util.Arrays;
public class HDFS {
//查看HDFS的数据节点
@Test
public void test1()throws Exception {
//Hadoop基本操作:NameNode设置,客户端创建
//指定NameNode地址
Configuration conf = new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS", "hdfs://192.168.80.111:9000");
//DistributedFileSystem
DistributedFileSystem client = (DistributedFileSystem)FileSystem.get(conf);
//获取所有的数据节点
DatanodeInfo[] list = client.getDataNodeStats();
for (DatanodeInfo data:list){
System.out.println(data.getHostName());
}
//关闭客户端,释放与HDFS的连接
client.close();
}
//查找某个文件在HDFS DataNode的位置
@Test
public void test2()throws Exception {
//Hadoop基本操作:NameNode设置,客户端创建
//指定NameNode地址
Configuration conf = new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS", "hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//得到文件状态
FileStatus status =client.getFileStatus(new Path("/1_20240810/hadoop-2.7.3.tar.gz"));
//获取文件的数据块信息,一般而言当文件大小超过设定值时,保存的数据块会不止1个,因此用数组存储信息
BlockLocation[] list = client.getFileBlockLocations(status,0,status.getLen());
for (BlockLocation blk:list) {
System.out.println("数据块:主机:"+ Arrays.toString(blk.getHosts()));
}
//关闭客户端,释放与HDFS的连接
client.close();
}
//删除HDFS数据
@Test
public void test3()throws Exception {
//Hadoop基本操作:NameNode设置,客户端创建
//指定NameNode地址
Configuration conf = new Configuration();
//这个在前面的分布模式中有相关设置,表示NameNode的具体地址
conf.set("fs.defaultFS", "hdfs://192.168.80.111:9000");
//创建一个HDFS的客户端DistributedFileSystem
FileSystem client = FileSystem.get(conf);
//删除数据,第二个false表示是否使用递归
boolean flag=client.delete(new Path("/1_20240810/hadoop-2.7.3.tar.gz"),false);
System.out.println(flag?"完成":"删除失败");
}
}
二、HDFS原理解析
1.数据上传
2.数据下载
三、HDFS的高级特性
1.回收站
默认回收站是关闭的,可以通过在core-site.xml中添加fs.trash.interval来打开并配置时间阈值。例如:
- 删除文件时,其实是将文件放入回收站(/trash)。
- 回收站里的文件可以快速恢复。
- 可以设置一个时间阈值,当回收站里文件的存放时间超过这个阈值,文件就被彻底删除,并且释放占用的数据块。
core-site.xml
<!--1440单位是分钟-->
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
2.快照
定义一个snapshot(快照)是一个全部文件系统、或者某个目录在某一时刻的镜像。
- 开启input目录的快照
hdfs dfsadmin -allowSnapshot /input
- 创建快照
hdfs dfs -createSnapshot /input backup_input_01
- 查看快照
hdfs lsSnapshottableDir
- 对比快照
hdfs snapshotDiff /input backup_input_01 backup_input_02
- 恢复快照
hdfs dfs -cp /input/.snapshot/backup_input_01/data.txt /input/
3.配额Quota
- 名称配额
定义:规定的是某个HDFS目录下文件的个数
例:设置名称配额是N,表示只能在该目录下存放N-1个文件或者目录
目录1_20240810最多只能存放2个目录和文件
hdfs dfsadmin-setQuota 3 /1_20240810
- 空间配额
定义:规定的是某个HDFS目录下文件的大小
例:设置某个HDES目录的空间配额是200M,只能存放200M以下的文件以及目录
目录1_20240810最大只能存放1M
hdfs dfsadmin-setspaceQuota 1M /1_20240810
4.安全模式
定义:
“安全模式”是用于保证Hadoop集群中数据块(blocks)的安全性的一种机制。如果HDFS(Hadoop Distributed
File
System)处于安全模式,则表示它当前是一种保护状态,此时HDFS是只读状态。这是一种防止在集群启动或某些数据节点(DataNodes)不可用时对数据进行修改的保护机制,旨在确保数据的一致性和完整性。
作用:
当集群启动的时候,会首先进入安全模式。在安全模式下,系统会检查数据块的完整性。假设我们设置的副本数(即参数dfs.replication)是5(一般不超过3,此处仅为了方便运算),那么在正常情况下,每个数据块应该在不同的DataNode上有5个副本存在。如果系统检测到某个数据块的副本数少于这个设定值,比如只存在3个副本,那么副本率就是3/5=0.6。在配置文件hdfs-default.xml中,定义了一个最小的副本率阈值,比如0.999。由于我们的副本率0.6明显小于这个阈值0.999,因此系统会自动复制副本到其他DataNode,以确保副本率不小于0.999。相反,如果系统中有8个副本,超过了我们设定的5个副本,那么系统也会删除多余的3个副本,以保持副本数与设定值一致。
以下为代码,查看,进入,离开安全模式
hdfs dfsadmin -safemode get
hdfs dfsadmin -safemode enter
hdfs dfsadmin -safemode leave
5.权限管理
命令行
和Linux权限管理类似,以下代码仅为示例
# 查看文件或目录的详细信息(包括权限信息,但不完整)
hdfs dfs -ls /path/to/file_or_dir
# 修改文件或目录的权限
hdfs dfs -chmod 755 /path/to/file_or_dir
# 修改文件或目录的所有者
hdfs dfs -chown newowner:newgroup /path/to/file_or_dir
# 只修改文件或目录的所有者(不改变所属组)
hdfs dfs -chown newowner /path/to/file_or_dir
# 查看文件或目录的ACL
hdfs dfs -getfacl /path/to/file_or_dir
# 设置文件或目录的ACL(示例:为用户user添加读权限)
hdfs dfs -setfacl -m user:user:r /path/to/file_or_dir
# 删除文件或目录的ACL条目(示例:删除用户user的所有权限)
hdfs dfs -setfacl -b user:user /path/to/file_or_dir
# 完全替换文件或目录的ACL
hdfs dfs -setfacl -k /path/to/file_or_dir
hdfs dfs -setfacl -R -m default:user:user:rwx /path/to/dir
JavaAPI
以下方法都位于org.apache.hadoop.fs.FileSystem类中,在操作使用时,本身一定要有root权限
// 创建一个新文件,并设置其权限、是否覆盖、缓冲区大小、副本数、块大小和进度监听器
public FSDataOutputStream create(Path f, FsPermission permission, boolean overwrite, int bufferSize, short replication, long blockSize, Progressable progress) throws IOException;
// 创建一个目录,包括所有必需的父目录,并设置其权限
public boolean mkdirs(Path f, FsPermission permission) throws IOException;
// 设置文件或目录的权限
public void setPermission(Path p, FsPermission permission) throws IOException;
// 设置文件或目录的所有者和组
public void setOwner(Path p, String username, String groupname) throws IOException;
// 获取文件或目录的状态信息,包括所有者、组和权限等
public FileStatus getFileStatus(Path f) throws IOException;
6.HDFS集群
-
负载均衡——Federation(联盟)
-
失败迁移——HA
四、HDFS底层原理
1.Java代理对象Proxy
代理对象是一种设计模式中的构造,它充当原始对象(或称为被代理对象)的代理或中介。代理对象与原始对象实现相同的接口,使得它可以替代原始对象进行交互。通过代理对象,可以在不修改原始对象代码的情况下,为原始对象增加额外的功能、控制访问、进行懒加载、记录日志等。代理对象在客户端和目标对象之间起到中介的作用,客户端对目标对象的所有调用都通过代理对象进行,从而可以在调用前后执行一些附加操作。
- 远程代理,也就是为一个位于不同的地址空间(如远程机器)上的对象提供一个本地的代理对象,这个代理对象负责将调用请求发送到远程对象上,并返回远程对象的执行结果。
- 虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
- 保护(访问)代理,控制对原始对象的访问。
- 智能指引(Smart Reference)代理,取代了简单的静态引用。
2.RPC协议
RPC框架是一种用于实现远程过程调用的技术框架,它允许开发者编写能够在不同机器或不同进程间进行通信和调用的代码,就像调用本地方法一样简单。通过使用RPC框架,开发者可以轻松地实现分布式系统的服务调用和集成,无需关心底层网络通信的复杂性。RPC框架通常提供序列化/反序列化机制,用于将调用参数和返回结果转换为可以在网络上传输的格式,并确保数据的正确性和完整性。此外,RPC框架还支持服务注册与发现、负载均衡、容错处理等高级特性,使得构建和维护分布式系统变得更加高效和可靠。