39_尚硅谷_Hadoop_HDFS_课程介绍
40_尚硅谷_Hadoop_HDFS_产生背景和定义
HDFS就是为了解决海量数据的存储问题
分布式存储:就是利用多台服务器来解决同一件事,每个服务器用来存储一部分数据。
41_尚硅谷_Hadoop_HDFS_优缺点
hdfs擅长的是:快速把数据存进去,然后查询。只适合查询,数据量越大越有优势
适合大文件,不适合小文件低延时数据存储
42_尚硅谷_Hadoop_HDFS_组成
hadoop官方文档
https://hadoop.apache.org/docs/r3.1.3/
2NN也只能起到辅助作用,也只是恢复一部分数据。因为秘书知道的事情跟老板知道的事情还是有一定的差距,那差距的那部分数据就是损失的数据。
对于客户端:NameNode是告诉你允许不允许读,或者说我这机器上有没有,这些都是namenode说的算。那实际来干活和对接的是DataNode。
43_尚硅谷_Hadoop_HDFS_文件块大小
在公司当中,主流的块大小有两种:128M(中小型企业)、256M(大厂)
未来计算的单元是以块来计算的
44_尚硅谷_Hadoop_HDFS_Shell命令上传
一般会选择hadoop fs,因为这个简洁
在根目录下创建sanguo文件夹
hadoop fs -mkdir /sanguo
-moveFromLocal:从本地剪切粘贴到HDFS
hadoop fs -moveFromLocal shuguo.txt /sanguo
-copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
hadoop fs -copyFromLocal weiguo.txt /sanguo
-put:等同于copyFromLocal,生产环境更习惯用put
hadoop fs -put wuguo.txt /sanguo
-appendToFile:追加一个文件到已经存在的文件末尾(只能追加,不能后续的修改)
hadoop fs -appendToFile liubei.txt /sanguo/shuguo.txt
45_尚硅谷_Hadoop_HDFS_Shell命令下载&直接操作
常用-get,比较简洁
1)-ls: 显示目录信息
hadoop fs -ls /
hadoop fs -ls /sanguo
2)-cat:显示文件内容
hadoop fs -cat /sanguo/shuguo.txt
3)-chgrp、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
hadoop fs -chown atguigu:atguigu /sanguo/shuguo.txt
4)-mkdir:创建路径
hadoop fs -mkdir /jinguo
5)-cp:从HDFS的一个路径拷贝到HDFS的另一个路径
hadoop fs -cp /sanguo/shuguo.txt /jinguo
6)-mv:在HDFS目录中移动文件
hadoop fs -mv /sanguo/weiguo.txt /jinguo
hadoop fs -mv /sanguo/wuguo.txt /jinguo
7)-tail:显示一个文件的末尾1kb的数据
hadoop fs -tail /jingguo/shuguo.txt
8)-rm:删除文件或文件夹
hadoop fs -rm /sanguo/shuguo.txt
9)-rm -r:递归删除目录及目录里面内容
hadoop fs -rm -r /sanguo
10)-du统计文件夹的大小信息
hadoop fs -du -s -h /jinguo
副本里面是每台机器只能存储其中的一块副本,它不会重复的存,因为重复的存没有意义
11)-setrep:设置HDFS中文件的副本数量
hadoop fs -setrep 10 /jinguo/shuguo.txt
46_尚硅谷_Hadoop_HDFS_API环境准备
要使windows能够连接到远程的Hadoop集群,那么windows这边也得有相关的Hadoop环境变量
E:\HadoopEnvironmentData\hadoop-3.1.0
在IDEA中创建一个Maven工程HdfsClientDemo,并导入相应的依赖坐标+日志添加
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入(目的是为了打印日志)
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
创建包名:com.atguigu.hdfs、创建HdfsClient类
47_尚硅谷_Hadoop_HDFS_API创建文件夹
客户端是跟namenode打交道
package com.atguigu.hdfs;
import com.sun.org.apache.xml.internal.utils.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
import java.io.IOException;
import java.net.URISyntaxException;
/*
客户端代码常用套路
1、获取一个客户端对象
2、执行相关的操作命令
3、关闭资源
HDFS zookeeper
*/
public class HdfsClient {
@Test
public void testmkdir() throws IOException, URISyntaxException {
/*
new URI("hdfs://hadoop102:8020").var
alt+回车:抛个异常
*/
// 连接的集群Namenode的地址:8020是内部的地址
java.net.URI uri = new java.net.URI("hdfs://192.168.10.102:8020");
//创建一个配置文件
Configuration configuration = new Configuration();
/*
注意FileSystem是在hadoop包下,别导错了(没有的鼠标对着FileSystem按alt+enter导入包)
ctrl+p:提示参数
*/
//用户
String user="atguigu";
//1、获取到了客户端对象
FileSystem fs = FileSystem.get(uri, configuration,user);
//2、创建一个文件夹
fs.mkdirs(new Path("/xiyou/huaguoshan"));
//3、关闭资源
fs.close();
}
}
如果 FileSystem fs = FileSystem.get(uri, configuration,user);中不添加user,将会报如下的异常:
添加user后执行完成之后,打开HDFS网页,会出现xiyou文件夹
//换一种写法:junit的@after、@before、@test
package com.atguigu.hdfs;
import com.sun.org.apache.xml.internal.utils.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URISyntaxException;
/*
客户端代码常用套路
1、获取一个客户端对象
2、执行相关的操作命令
3、关闭资源
HDFS zookeeper
*/
public class HdfsClient {
private FileSystem fs; //升级为全局变量
@Before
public void init() throws URISyntaxException, IOException, InterruptedException {
// 连接的集群Namenode的地址:8020是内部的地址
java.net.URI uri = new java.net.URI("hdfs://192.168.10.102:8020");
//创建一个配置文件
Configuration configuration = new Configuration();
//用户
String user="atguigu";
//1、获取到了客户端对象
// ctrl+alt+f:将fs变成全局变量
fs = FileSystem.get(uri, configuration,user);
}
@After
public void close() throws IOException {
//3、关闭资源
fs.close();
}
@Test
public void testmkdir() throws Exception {
//2、创建一个文件夹huaguoshan1
fs.mkdirs(new Path("/xiyou/huaguoshan1"));
//fs.mkdirs(new Path("/xiyou/huaguoshan1"));
}
/*执行顺序:
首先执行before,执行完before之后再执行Test,Test结束之后再执行after
*/
}
48_尚硅谷_Hadoop_HDFS_API上传
(1)查看帮助
hdfs dfs -help
(2)查看当前目录信息
hdfs dfs -ls /
(3)上传文件
hdfs dfs -put /本地路径 /hdfs路径
(4)剪切文件
hdfs dfs -moveFromLocal a.txt /aa.txt
(5)下载文件到本地
hdfs dfs -get /hdfs路径 /本地路径
(6)合并下载
hdfs dfs -getmerge /hdfs路径文件夹 /合并后的文件
(7)创建文件夹
hdfs dfs -mkdir /hello
(8)创建多级文件夹
hdfs dfs -mkdir -p /hello/world
(9)移动hdfs文件
hdfs dfs -mv /hdfs路径 /hdfs路径
(10)复制hdfs文件
hdfs dfs -cp /hdfs路径 /hdfs路径
(11)删除hdfs文件
hdfs dfs -rm /aa.txt
(12)删除hdfs文件夹
hdfs dfs -rm -r /hello
(13)查看hdfs中的文件
hdfs dfs -cat /文件
hdfs dfs -tail -f /文件
(14)查看文件夹中有多少个文件
hdfs dfs -count /文件夹
(15)查看hdfs的总空间
hdfs dfs -df /
hdfs dfs -df -h /
(16)修改副本数
hdfs dfs -setrep 1 /a.txt
用客户端进行远程访问HDFS,然后上传文件
49_尚硅谷_Hadoop_HDFS_API参数的优先级
1)编写源代码
@Test
public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
configuration.set("dfs.replication", "2");
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "atguigu");
// 2 上传文件
fs.copyFromLocalFile(new Path("d:/sunwukong.txt"), new Path("/xiyou/huaguoshan"));
// 3 关闭资源
fs.close();
}
2)将hdfs-site.xml拷贝到项目的resources资源目录下
<?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>
优先级一般是就近原则
最高优先级是代码里面,其次是资源目录,再往前是hdfs-site.xml,然后最后是hdfs-defaule.xml
50_尚硅谷_Hadoop_HDFS_API文件下载
下载就是从HDFS里面把数据下载到我们windows本地
crc:循环校验文件,检错用的。目的是为了保证从hdfs传输过来的数据不会发生错误
最后一个参数userRalLocalFileSystem表示的是否开启本地模式(即是否开启本地校验crc,如果是true则开启本地校验,从hdfs下载下来的文件夹中会多出来一个以.crc结尾的文件,即循环校验文件;如果是false则下载下来的文件中没有循环校验文件)。这里可以不写,不用管它。
@Test
public void testCopyToLocalFile() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "atguigu");
// 2 执行下载操作
// boolean delSrc 指是否将原文件删除
// Path src 指要下载的文件路径
// Path dst 指将文件下载到的路径
// boolean useRawLocalFileSystem 是否开启文件校验
fs.copyToLocalFile(false, new Path("/xiyou/huaguoshan/sunwukong.txt"), new Path("d:/sunwukong2.txt"), true);
// 3 关闭资源
fs.close();
}
51_尚硅谷_Hadoop_HDFS_API文件删除
FileSystem.get里面已经设置URI了,后面的都是相对根目录的路径
@Test
public void testDelete() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "atguigu");
// 2 执行删除
fs.delete(new Path("/xiyou"), true);
// 3 关闭资源
fs.close();
}
52_尚硅谷_Hadoop_HDFS_API文件更名和移动
@Test
public void testRename() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "atguigu");
// 2 修改文件名称
fs.rename(new Path("/xiyou/huaguoshan/sunwukong.txt"), new Path("/xiyou/huaguoshan/meihouwang.txt"));
// 3 关闭资源
fs.close();
}
53_尚硅谷_Hadoop_HDFS_API文件详情查看
那么通过客户端能不能拿到我这个文件存在那几个块上呢?也就是块信息的存储拿不拿得到?
@Test
public void testListFiles() throws IOException, InterruptedException, URISyntaxException {
// 1获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "atguigu");
// 2 获取文件详情
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
while (listFiles.hasNext()) {
LocatedFileStatus fileStatus = listFiles.next();
System.out.println("========" + fileStatus.getPath() + "=========");
System.out.println(fileStatus.getPermission());
System.out.println(fileStatus.getOwner());
System.out.println(fileStatus.getGroup());
System.out.println(fileStatus.getLen());
System.out.println(fileStatus.getModificationTime());
System.out.println(fileStatus.getReplication());
System.out.println(fileStatus.getBlockSize());
System.out.println(fileStatus.getPath().getName());
// 获取块信息
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
System.out.println(Arrays.toString(blockLocations));
}
// 3 关闭资源
fs.close();
}
54_尚硅谷_Hadoop_HDFS_API文件和文件夹判断
Ctrl+L:进行代码格式化
@Test
public void testListStatus() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件配置信息
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "atguigu");
// 2 判断是文件还是文件夹
FileStatus[] listStatus = fs.listStatus(new Path("/"));
for (FileStatus fileStatus : listStatus) {
// 如果是文件
if (fileStatus.isFile()) {
System.out.println("f:"+fileStatus.getPath().getName());
}else {
System.out.println("d:"+fileStatus.getPath().getName());
}
}
// 3 关闭资源
fs.close();
}
55_尚硅谷_Hadoop_HDFS_写数据流程
本节内容讲的是:我从客户端如何将数据写到HDFS集群的
既考虑了节点距离最近,有考虑了负载均衡(就近原则和负载均衡)
老师传给班长,班长传给组长,一层一层慢慢传比较好(串行)。如果是方案1,当一个DataNode结点没有传输,outputStrame还要继续等待,一直等到所有结点传输完成。
每个DataNode内部既向其它DataNode传输数据,又同时将写入磁盘,这样效率很高。(一边写一边出)
先是形成chunk,等达到64k过后就形成packet。形成一个一个packet之后,这个packet就发送到下一个DataNode
上游ack队列,进行判断应答是否成功
/*
(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
(2)NameNode返回是否可以上传。
(3)客户端请求第一个 Block上传到哪几个DataNode服务器上。
(4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
(5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
(6)dn1、dn2、dn3逐级应答客户端。
(7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
(8)当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
*/
56_尚硅谷_Hadoop_HDFS_节点距离计算
网络拓扑-节点距离计算:
是到达共同祖先的步数和;
画一个树就知道了,同一个机器上的节点都是兄弟
就是到达同一个祖先所要连接线的个数
57_尚硅谷_Hadoop_HDFS_机架感知(副本存储节点选择)
一般情况下,它会选择你在哪台服务器上提交,我就优先选择谁
(机架感知的前提是,配置了机架感知系统)
第一个机架我选择本地,考虑的是结点距离最近,我上传速度最快;第二个数据为什么跑别的机架上去传了?保证了你的数据的可靠性,同时又要兼顾对应的效率,同机架内部传输比你跨机架传输网络速度要快一些。
58_尚硅谷_Hadoop_HDFS_读数据流程
客户端向NameNode请求,它要读取数据。为什么客户端不直接请求DataNode?因为NameNode是HDFS的老大,得问NameNode能不能读?那么客户端得创建一个客户端对象(分布式文件系统对象),类似于一个谈判代表跟NameNode交涉。最后还要创建一个FSDataInputStream数据流对象来对应读数据,它选择读取数据的原则是:首先选择结点距离最近的读,同时还会考虑当前这个结点的负载均衡能力。它是串行读取数据。
59_尚硅谷_Hadoop_HDFS_NN和2NN工作机制
内存:断电丢失
存储在磁盘里我们一般用fsimage(快照)来存储数据
Edits只记录你的过程,不给你进行计算
关机的时候才将fsimage和Edits进行合并,效率比较低
2NN将fsimage和Edits文件进行定期的进行合并(即做了一些我合并一些)
当对元数据进行增删改请求,假如先更改内存再记账,如果断电了,edits_inprogress没有记录这条数据,那么整个这条数据就丢了。所以说非常严谨的办法就是先记账到edits_inprogress,然后再加载到内存。未来edits_inprogress和fsimage进行合并,就是当前内存当中最新的数据,也就是这条数据它不会丢。
重要提示:每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。
60_尚硅谷_Hadoop_HDFS_FsImage镜像文件
原始记录+日志记录=fsimage+edits=数据库常规操作
打开fsimage.txt文件里面对应的是根目录下对应的文件存储信息
61_尚硅谷_Hadoop_HDFS_Edits编辑日志
Edits的特点是:只进行追加,不进行合并修改
62_尚硅谷_Hadoop_HDFS_检查点时间设置
检查点设置就是:2NN给NN说需不需要进行合并,进行检查。这个时候的触发事件
63_尚硅谷_Hadoop_HDFS_DN工作机制
本节主要将老板和员工是如何工作的
64_尚硅谷_Hadoop_HDFS_数据完整性
65_尚硅谷_Hadoop_HDFS_掉线时限参数设置
66_尚硅谷_Hadoop_HDFS_总结
开发用到最多的是它的shell操作,而API用的少