HDFS
HDFS的基本介绍
- HDFS: 分布式文件存储系统
- 目的: 存储海量数据
- 分布式文件存储过程:
HDFS的应用场景:
- 存储非常大的文件(GB TB PB), 适合于做批量化高吞吐的业务
- 一次写入、多次读取 : 对数据没有修改的要求, 但是需要多次读取, HDFS不支持随机修改文件中数据
- 思考, 什么数据一般不需要修改的? 过去已经既定发生过数据
- 在有限成本下, 存储更多数据
- 需要高容错性: 数据不能给丢失了
- 需要具备扩展能力
HDFS不适用场景:
- 需要进行随机修改的场景
- 需要交互式强场景
- 存储大量的小文件场景
HDFS的架构及核心概念
注意:
假设现在有一个300M 文件, 请问分几个块呢? 3个块
第一个块: 128M
第二个块: 128M
第三个块: 44M
假设还有一个150M文件, 请问分2个块?
第一个块为: 128M
第二个块为 22M
一个块最大为128M , 请问第一个文件中第三个块和第二个文件的第二个块, 是否会占用128M大小呢? 不会的
最终一个文件块占用多大的磁盘空间, 取决于存储数据大小
一个块只能代表一个文件的内容副本的机架感知原理, 以及网络拓扑机制
说明: 第一副本:优先放置到离写入客户端最近的DataNode节点,如果上传节点就是DataNode,则直接上传到该节点,如果是集群外提交,则随机挑选一台磁盘不太满,CPU不太忙的节点。 第二个副本:放置在另一个机架中, 某一个服务器中 第三个副本:放置在与第二个同机架的不同机器中
HDFS的原理
namenode是如何存储元数据的流程
SNN辅助节点流程方案
从整个流程中 可以发现, SNN在对namenode元数据进行冷备份(备份前一个小时的元数据或者前一个edits达到64M的数据), 在一些特殊场景下, 可以基于SNN进行元数据的恢复工作, 此种操作, 可能无法恢复全部的数据, 但是也可以恢复到1个小时以前(或者...)的数据
HDFS的数据写入的流程
HDFS的数据读取流程
HDFS相关的shell操作:
一、简介
linux alias 是命令的一种别称,输入
alias
可以看到像下面这样的结果:
alias vi="vim"
也即,输入vi后,被自动定向到vim这个命令了。alias的作用就是,可以简写命令。
二、修改alias
若要添加自己的alias,格式如下
alias la="ls -al --color=auto"
三、修改配置文件
上述命令,在用户登出后就无效了,可以用修改配置文件的办法,使每次都能够自动生效。
若要修改用户(而非全部用户)自己的alias,可以修改~/.bashrc文件
vi ~/.bashrc
再最后面加上你自己定义的alias,如
alias la="ls -al --color=auto"
这个修改,要下次登录的时候才能生效。想要即刻生效,可以输入
source ~/.bashrc
四、常用的alias
这个根据个人爱好了,可以google之~找到你自己喜欢的alias
PS: 修改全局的alias可以修改系统配置文件,我这里就不说了。
还有其他的方面知识,如交互式、非交互式登录的配置文件,这个也不多说了。
alias hls='hadoop fs -ls'
alias hlsr='hadoop fs -lsr'
alias hcp='hadoop fs -cp '
alias hmv='hadoop fs -mv'
alias hget='hadoop fs -get'
alias hput='hadoop fs -put'
alias hrm='hadoop fs -rm'
alias hmkdir='hadoop fs -mkdir'
alias hcat='hadoop fs -cat'
alias hrmr='hadoop fs -rmr'
alias hstat='hadoop fs -stat'
alias htest='hadoop fs -test'
alias htext='hadoop fs -text'
alias htouchz='hadoop fs -touchz'
alias hdu='hadoop fs -du'
alias hdus='hadoop fs -dus'
alias hchmod='hadoop fs -chmod'
alias hchgrp='hadoop fs -chgrp'
alias hchown='hadoop fs -chown'
alias htail='hadoop fs -tail'- HDFS的操作命令基本格式:
hadoop fs <args>: 通用文件系统操作 既可以操作HDFS文件系统, 也可以操作本地文件系统, 默认操作hdfs文件系统
默认取决于: 在 core-site.xml中 fs.defaultFS
hdfs dfs <args>: 操作HDFS文件系统常用命令介绍:
- ls
- 作用: 查看某一个路径的目录结构
格式: hdfs dfs -ls [-R] 路径 参数说明: -R : 是否递归获取某个目录所有子目录内容 案例: hdfs dfs -ls /- mkdir
- 作用: 创建目录
格式: hdfs dfs -mkdir [-p] 路径 参数说明: -p : 创建多级目录时 需要添加 案例: hdfs dfs -mkdir -p /aaa/bbb/ccc- put
- 作用: 用于上传文件
格式: hdfs dfs -put srcLocalFilePath hdfsDirPath 案例: hdfs dfs -put jdk-8u241-linux-x64.tar.gz /aaa/bbb/ccc- moveFromLocal
- 作用: 将本地文件系统的文件移动到HDFS中
格式: hdfs dfs -moveFromLocal srcLocalFilePath hdfsDirPath 案例: hadoop fs -moveFromLocal jdk-8u241-linux-x64.tar.gz /aaa/bbb- moveToLocal
- 作用: 将HDFS的文件系统文件数据移动到本地文件系统
格式: hdfs dfs -moveToLocal hdfsFilePath srcLocalDirPath 案例: 此命令未实现- get
- 作用: 从HDFS中下载数据到本地文件系统
格式: hdfs dfs -get hdfsFilePath srcLocalDirPath 案例: hadoop fs -get /aaa/bbb/jdk-8u241-linux-x64.tar.gz ~ 注意: 此操作下载后, 在HDFS中, 依然存在, 相当于是读取数据操作- getmerge
- 作用: 合并下载
#格式: hdfs dfs -getmerge hdfsFilePath1 hdfsFilePath2 ... srcLocalFilePath #案例: hdfs dfs -getmerge /aaa/bbb/jdk-8u241-linux-x64.tar.gz /aaa/bbb/ccc/jdk-8u241-linux-x64.tar.gz ~/jdk_merge.gz- mv
- 作用: 在hdfs中 从一个目录移动到另一个目录, 或者进行重命名操作
#格式: hdfs dfs -mv srchdfsFilePath disthdfsFilePath #案例: hdfs dfs -mv /aaa/bbb/ccc/jdk-8u241-linux-x64.tar.gz / #注意: 此处移动是在hdfs内部进行数据移动- rm
- 作用: 删除HDFS中数据
格式: hdfs dfs -rm [-r -f -skipTrash] 删除的hdfs的文件路径或者目录路径 参数说明: -r: 表示是否递归删除(删除目录需要携带) -f: 强制删除 -skipTrash: 跳过垃圾桶 (一般不使用) 案例: hdfs dfs -rm /jdk.gz 注意: 默认情况下, 删除数据, 本质上将其移动到垃圾桶 hdfs的垃圾桶, 默认情况 到达7天后, 自动删除过期数据 在生产中, 建议不要跳过垃圾桶, 将删除数据放置到回收站, 给自己一次反悔机会- cat
- 作用: 查看某个文件的内容
格式 : hdfs dfs -cat hdfsFilePath 案例: hdfs dfs -cat /aaa.txt 注意: 此操作只适合查看小文件的数据- du
- 作用: 查看目录或者文件的大小
格式: hdfs dfs -du [-h] hdfsFilePath|hdfsDirPath 参数说明: -h : 表示友好展示文件大小 案例: hdfs dfs -du /jdk-8u241-linux-x64.tar.gz- chmod
- 作用: 设置权限
格式: hdfs dfs -chmod 权限编号(3位) hdfsPath 权限 4 2 1法则: 4: 可读 2: 可写 1: 可执行 案例: hdfs dfs -chmod 755 /jdk.gz 描述: 所属用户为可读可写可执行, 其他所有的用户可读可执行权限 注意: 在hdfs中, 由于我们在hdfs-site.xml中将hdfs的权限已经关闭了, 所以不管设置任何权限, 都没有用 对于root而言, 即使开启了权限设置, 对这个用户也是无效的 在HDFS中, 权限管理只能防止好人做错事, 而不能防止坏人做坏事- chown
- 作用: 设置所属用户和所属用户组
格式: hdfs dfs -chown [-R] 所属用户:所属组 路径 参数说明: -R : 表示是否递归设置所属用户和所属组 案例: hdfs dfs -chown itcast:itcast /aaa.txt- appendToFile
- 作用: 追加数据到hdfs的某一个文件中 (修改文件数据)
格式: hdfs dfs -appendToFile srcLocalFilePath hdfsFilePath 案例: hdfs dfs -appendToFile bbb.txt /aaa.txt
- hdfs的高级shell命令
hdfs的安全模式
hdfs的安全模式, 是hdfs的保护机制, 当刚刚启动HDFS的时候, 系统会自动的进入安全模式下, 在此模式下, 开始校验副本块是否安全(完整), 如果校验发现都是OK, hdfs会自动离开安全模式(30s), 在运行的过程中, 如果发现块出现问题, 依然会进入安全模式的;
hdfs会自动维护块信息, 当发现某个块副本数量少, 自动新增, 如果发现块的副本变多了, 自动减少的
安全模式的相关的操作:
hdfs dfsadmin -safemode get #查看安全模式状态 hdfs dfsadmin -safemode enter #进入安全模式 hdfs dfsadmin -safemode leave #离开安全模式
hdfs的基准测试
hdfs的基准测试, 主要目的就是为了检测刚刚搭建好的HDFS集群, 整体吞吐量是多大
检测方案:
- 向hdfs一次性写入多个文件, 测试其写入时间和写入数据量的比例
hadoop jar /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -write -nrFiles 10 -fileSize 10MB- 从hdfs一次性读取多个文件, 测试其读取时间和读取数据量之间的比例
hadoop jar /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -read -nrFiles 10 -fileSize 10MB- 清空基准测试的数据:
hadoop jar /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean注意:
- 在生产中进行检测的时候, 一定要多测试几次, 而且每次测试, 采用不同的文件数量和数据量来测试, 这样测出结果会比较准确一些
服务器与服务器之间数据拷贝操作
服务器之间数据远程拷贝: scp
方式1:指定用户名,命令执行后需要再输入密码; 从本地拷贝到远程
scp -r local_folder remote_username@remote_ip:remote_folder
例如:
scp -r hadoop root@node2:/export/server
简写方案: 远端目的地路径和当前路径是一致的, 并且操作用户也是一样的
scp -r hadoop node2:$PWD
注意,如果实现了ssh免密登录之后,则不需要输入密码即可拷贝。
方式二: 从远程拷贝到本地:
格式:
scp [email protected]:/root/test.txt /root/test.txt
例如:
scp root@node1:/export/server/hadoop /export/serverhdfs集群之间数据拷贝
格式:
hadoop distcp 第一个集群的路径 目的地集群路径
案例:
hadoop distcp hdfs://node1:8020/jdk-8u241-linux-x64.tar.gz hdfs://cluster2:8020/
描述:
将 第一个集群中 根目录下的jdk包 发送给第二个集群的根目录下hdfs的归档文件
目的: 用于小文件的合并操作, 从而得到一个更大的文件
场景: 在hdfs中以及存在了大量的小文件, 需要进行合并的场景
通过java代码实现一种小文件合并操作 请问, 此种操作, 有什么弊端吗?
- 重新获取每一个文件不是很方便 2) 合并只能合并同类型的数据
所以说, java合并操作, 比较适合于同类型的文本数据合并操作, 其他的都不适用了
而归档文件, 类似于 windows中压缩方案, 但是规约文件不会进行缩 只会进行压: 归档文件后缀名为 .har
有什么好处呢?
1) 压在一起后, 依然可以看到里面有那些文件
2) 压在一起后, 也可以将其解压出来
3) 压在一起可以不局限于任何类型- 如何使用呢?
- 如何构建归档文件
语法格式:
hadoop archive -archiveName name -p <parent> <src>* <dest>
例如:
hadoop archive -archiveName test.har -p /config /outputdir
说明:
将 /config目录下所有的文件或者目录合并到test.har文件中, 然后将这个归档文件放置在 /outputdir
需求: 在 /smallFile 目录下 有很多的小文件, 需要进行合并操作
hadoop archive -archiveName smallMerge.har -p /smallFile /harFile- 如何查看合并后的文件
格式:
hadoop fs -ls har://hdfs-node1:8020/outputdir/test.har
案例:
hdfs dfs -ls har://hdfs-node1:8020/harFile/smallMerge.har- 如何解压归档文件
格式:
hadoop fs -cp har:///outputdir/test.har/* /config2
案例:
hdfs dfs -mkdir -p /harOpen
hdfs dfs -cp har://hdfs-node1:8020/harFile/smallMerge.har/* /harOpen注意事项:
1. Hadoop archives是特殊的档案格式。一个Hadoop archive对应一个文件系统目录。Hadoop archive的扩展名是*.har;
2. 创建archives本质是运行一个Map/Reduce任务,所以应该在Hadoop集群上运行创建档案的命令,要提前启动Yarn集群;
3. 创建archive文件要消耗和原文件一样多的硬盘空间;
4. archive文件不支持压缩,尽管archive文件看起来像已经被压缩过;
5. archive文件一旦创建就无法改变,要修改的话,需要创建新的archive文件。事实上,一般不会再对存档后的文件进行修改,因为它们是定期存档的,比如每周或每日;
6. 当创建archive时,源文件不会被更改或删除;hdfs的快照机制
hdfs的快照的目的: 对hdfs文件系统进行备份操作
可以对hdfs中某个目录进行快照的拍摄, 注意在拍摄之后, 不会产生任何的内容, 只要当对以及拍摄快照的目录进行修改之后, 记录那些修改的信息即可 ----- 差异化快照
- 1 开启指定目录的快照功能 :
- 默认hdfs对目录的快照功能是关闭状态
hdfs dfsadmin -allowSnapshot 路径- 2 禁用指定目录的快照功能(默认就是禁用状态)
hdfs dfsadmin -disallowSnapshot 路径3 给某个路径创建快照snapshot
hdfs dfs -createSnapshot 路径- 指定快照名称进行创建快照snapshot
hdfs dfs -createSanpshot 路径 名称- 5 ) 给快照重新命名
hdfs dfs -renameSnapshot 路径 旧名称 新名称6 列出当前用户所有可快照目录
hdfs lsSnapshottableDir7 比较快照目录中, 两个快照的不同之处
hdfs snapshotDiff 路径 快照1名称 快照2名称8 删除快照snapshot
hdfs dfs -deleteSnapshot <path> <snapshotName>
2.4 hdfs的回收站(垃圾桶)
hdfs的回收站默认是禁用状态, 如果需要使用, 手动在core-site.xml中进行开启:
<!-- 开启hdfs的垃圾桶机制,删除掉的数据可以从垃圾桶中回收,单位分钟 -->
<property>
<name>fs.trash.interval</name>
<value>10080</value>
</property> 一旦开启了回收站, 当执行shell的操作时候, 就会自动将删除移动到回收站目录下, 回收站默认情况下 7天之后, 自动删除数据, 此时才会将空间进行释放, 回收站出现给与我们反悔机会, 防止出现误删操作
如果使用java api执行delete操作, 直接跳过回收站, 永久删除掉, 如果解决呢?
解决方案: 在java API操作的, 将需要删除的数据直接移动的回收站的目录下 即可
- 清空回收站 (慎用)
hadoop fs -expungehdfs的javaAPI的操作
配置windows下的hadoop环境
- 第一步, 将资料中 hadoop-2.7.5 目录拷贝到一个没有中文没有空格的目录下
- 第二步: 配置环境变量 HADOOP_HOME
- 第三步, 将这个HADOOP_HOME配置到path环境变量中:
- 注意: 配置完, 一定要一顿点确定, 千万不要点取消
- 第四步: 将 hadoop-2.7.5目录下bin目录中 hadoop.dll文件, 放置在 c盘system32目录下
- 配置以上操作 目的, 是为了解决下面的两个问题:
- 第五步: 重启电脑
获取某个路径下所有文件listFiles
// 需求2: 查询某一个目录下所有的文件
@Test
public void test04() throws Exception{
//1. 创建java连接HDFS的FileSystem对象
URI uri = new URI("hdfs://node1:8020");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(uri, conf);
//2. 执行相关的操作: 获取根目录下所有的文件
//2.1: 执行获取某个路径的文件(递归获取)
RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/"), true);
//2.2: 遍历迭代器, 获取每一个文件
while ( listFiles.hasNext()){
LocatedFileStatus fileStatus = listFiles.next();
//2.3: 从文件状态对象中获取文件的路径
Path path = fileStatus.getPath();
//2.4: 从path路径上获取文件的名称
String name = path.getName();
System.out.println(path);
System.out.println(name);
System.out.println("--------------------------");
}
//3. 释放资源
fileSystem.close();
}创建文件夹操作mkdirs
// 需求三: 创建一个文件夹
@Test
public void test05() throws Exception{
//1. 创建fileSystem对象
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://node1:8020");
FileSystem fileSystem = FileSystem.newInstance(conf);
//2. 执行相关的操作 : 创建文件夹
fileSystem.mkdirs(new Path("/javaDIR/aaa/bbb"));
//3. 释放资源
fileSystem.close();
}上传文件操作copyFromLocalFile
// 需求四: 上传文件操作
@Test
public void test06() throws Exception{
//1. 创建fileSystem对象
URI uri = new URI("hdfs://node1:8020");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.newInstance(uri, conf);
//2. 执行相关的操作 上传命令: put
fileSystem.copyFromLocalFile(new Path("file:///D:\\大数据操作_精华篇\\day04_hadoop\\资料\\aaa.sql"), new Path("/javaDIR/aaa/bbb"));
//3. 释放资源
fileSystem.close();
}下载文件的操作copyToLocalFile
// 需求五: 下载数据操作
@Test
public void test07() throws Exception{
//1. 创建fileSystem对象
URI uri = new URI("hdfs://node1:8020");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.newInstance(uri, conf);
//2. 执行相关的操作 下载操作: get
fileSystem.copyToLocalFile(new Path("/javaDIR/aaa/bbb/aaa.sql"),new Path("file:///本地文件路径"));
//3. 释放资源
fileSystem.close();
}小文件合并操作
- 第一种实现方式: 推荐使用的, 如果不能用可以采用第二种
// 需求六: 合并小文件操作
@Test
public void test08() throws Exception{
//1. 创建 HDFS的文件系统对象 和 本地文件系统对象
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://node1:8020");
FileSystem dfsFileSystem = FileSystem.get(conf);
LocalFileSystem localFileSystem = FileSystem.getLocal(new Configuration());
//2. 执行相关的操作:
//2.1: 在HDFS中创建一个文件,返回一个输出流
FSDataOutputStream outputStream = dfsFileSystem.create(new Path("/javaDIR/aaa/bbb/merge.xml"));
//2.2 通过本地文件系统, 读取某个路径下所有文件
RemoteIterator<LocatedFileStatus> listFiles = localFileSystem.listFiles(new Path("file:///本地路径"), false);
while(listFiles.hasNext()){
LocatedFileStatus fileStatus = listFiles.next();
Path path = fileStatus.getPath();
//2.3: 读取文件, 获取这个文件的输入流
FSDataInputStream inputStream = localFileSystem.open(path);
//2.4: 两个流对接
int len ;
byte[] b = new byte[1024];
while( ( len= inputStream.read(b) ) != -1) {
outputStream.write(b,0,len);
outputStream.flush();
}
inputStream.close();
}
outputStream.close();
//3. 释放资源
localFileSystem.close();
dfsFileSystem.close();
}- 第二种实现方案:
// 需求六: 小文件合并操作: 原生写法
@Test
public void test09() throws Exception{
//1. 创建DFS的文件系统对象
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://node1:8020");
FileSystem fileSystem = FileSystem.get(conf);
//2. 执行相关的操作
//2.1: 在HDFS中创建一个文件, 并且获取到这个文件的输出流, 用于通过此流将数据输出大目标文件中
FSDataOutputStream outputStream = fileSystem.create(new Path("/javaDIR/aaa/bbb/merge2.xml"));
//2.2: 读取某个路径下所有文件
File fileDir = new File("D:\\day04_hadoop\\资料\\上传小文件合并");
File[] files = fileDir.listFiles();
for (File file : files) {
//2.3: 创建一个输入流: 指定读取文件对象
FileInputStream inputStream = new FileInputStream(file);
//2.4: 两个流对接
int len;
byte[] b = new byte[1024];
while( (len = inputStream.read(b) ) != -1 ) {
outputStream.write(b,0,len);
outputStream.flush();
}
// 每将一个文件写完后, 就将这个文件的输入流给关闭
inputStream.close();
}
// 当所有文件都写入到目标文件后, 然后关闭输出流
outputStream.close();
//3 释放资源
fileSystem.close();
}文件权限的操作
- 开启HDFS的文件权限
此配置在 hdfs-site.xml中
<property>
<name>dfs.permissions.enabled</name>
<value>true</value>
</property>
更改后, 需要将hdfs-site.xml发送给node2 和 node3
然后进行重启hdfs即可- 通过代码测试
- 向一个没有权限的目录上传文件操作, 观察是否可以上传, 然后在通过模拟用户的方式来操作
// 需求七: 在 /hsTest01 目录上传一个 c.txt 文件
// /hsTest01的权限为: drwxr-xr-x root supergroup
@Test
public void test10() throws Exception{
//1. 创建 hdfs的文件系统对象
Configuration conf = new Configuration();
URI uri = new URI("hdfs://node1:8020");
FileSystem fileSystem = FileSystem.get(uri,conf,"root");
//2. 执行相关的操作
fileSystem.copyFromLocalFile(new Path("file:///本地文件路径"),new Path("/hsTest01"));
//3. 释放资源
fileSystem.close();
}