Hadoop了解篇
Hadoop之HDFS
Hadoop之MapReduce
Hadoop之Yarn
Hadoop之优化&新特性
当下数据量的爆发式增长,在一个操作系统中,我们很难存下所有数据,这时就需要将数据放在等多个操作系统的磁盘中。此时另一个难题就出来了,我们如何对多台电脑的磁盘进行管理呢?这个时候分布式文件管理系统就登场了。
是一个文件系统,用于储存文件,通过目录树来定位文件
并且是分布式的,文件分布在多台服务器的磁盘中。
适合一次写入,多次读出,不支持文件的修改。(内部维持多个副本,随机写的话,分布式数据一致性会受到挑战。而如果一定要保证实时的数据一致性,那么性能上的牺牲就会太大了。所以说,随机写不属于HDFS的适用场景。)
优点:
特点 | 为何? |
---|---|
高容错性 | 内部维持多个副本,单一副本丢失,可自动恢复 |
处理数据量大 | 最大处理TB、PB级别的数据;处理百万规模的文件数量 |
可在廉价机器上 | 内部维持多个副本,单一副本丢失,可自动恢复 |
缺点:
特点 | 为何? |
---|---|
低延迟储存做不到 | 多副本机制的弊端 ,毫秒级储存难以达到 |
多小文件高效存储做不到 | 会占用大量的NameNode的内存来储存文件元数据;小文件的寻址时间会超过读取时间 |
并发写入,随机修改做不到 | 一个文件只能一个写,不可以多线程同时写;仅支持数据的追加(Append) |
组件 | 作用 |
---|---|
NameNode | 管理元数据、配置副本策略、管理Block映射信息、处理客户端读写请求 |
DataNode | 存储实际的数据块、执行数据的读/写操作 |
Client | 文件切分成Block然后上传 、与NameNode交互,获取文件位置信息、与DataNode交互,读取/写入数据、提供命令管理/操作HDFS,eg:对NameNode的格式化 |
Secondory NameNode | 紧急情况下,可辅助恢复NameNode了,具体见后续 |
首先明白:HDFS上的文件在物理上是分块存储(Block),块的大小我们可以根据实际的生产环境通过配置参数(dfs blocksize)来设定。在老版本中默认大小为64M,新版本(2.X)中默认大小为128M。
以从HDFS上下载一个文件为例:
约定:寻址时间为传输时间的1%时,为最佳状态 |
---|
1.假设寻址时间为10ms,即查找目标Block的时间为10ms |
2.因此在最佳状态下,传输时间为10/0.01=1s |
3.而目前磁盘的传输速率普遍为100M/S |
4.1S * 100M/S = 100M |
5.最接近100M就是128M |
1)基本语法
bin/hadoop fs 具体命令
or
bin/hdfs dfs 具体命令
2)常用命令实操
(1)上传
-moveFromLocal:从本地剪切粘贴到HDFS上
hadoop fs -moveFromLocal ./helloworld.txt /input
-copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
hadoop fs -copyFromLocal ./helloworld.txt /input
-appendToFile:追加一个文件到已经存在的文件末尾
hadoop fs -appendToFile helloworld.txt /input/yilei.txt
-put:等同于copyFromLocal
hadoop fs -put ./helloworld.txt /input
(2)下载
-copyToLocal:从HDFS上拷贝到本地
hadoop fs -copyToLocal /input/helloworld.txt ./
-get:等同于copyToLocal
hadoop fs -get ./helloworld.txt /input
-getmerge:合并多个文件下载
hadoop fs -getmerge /user/yilei/bin/* ./helloworld.txt
3)HDFS直接操作
-ls:显示目录信息
hadoop fs -ls
-mkdir:在HDFS上创建目录
hadoop fs -mkdir /sanguo/liubei.txt
-cat:显示文件内容
hadoop fs -cat /sanguo/liubei.txt
-cp :从HDFS的一个路径拷贝到HDFS的另一个路径
hadoop fs -cp /sanguo/liubei.txt /input/
-du:统计文件夹的大小信息
hadoop fs -du -s -h /sanguo
2.7k /sanguo
-setrep:设置HDFS中的文件副本数
hadoop fs -setrep 10 /sanguo/liubei.txt
1)下载Hadoop
2)配置Hadoop的环境变量
3)配置Path环境变量,重启电脑
4)创建Maven工程,并导入相应的依赖
获取文件系统对象的方式一:(常用方式)
public class HdfsClient{
@Test
public void testMkdirs(){
//连接地址
UIR uri = new URI("hdfs://hadoop01:9820");
//创建配置文件对象
Configuration conf = new Configuration();
//1.文件系统对象
/*
参数一:NameNode的连接地址
参数二:配置文件对象
参数三:操作hdfs的用户
*/
FileSystem fs = FileSystem.get(uri,conf,"yilei")
//2.对应操作
System.out.println(fs);
//3.关闭资源
fs.close();
}
}
获取文件系统对象的方式二:
注:需要在EditConfigurations中配置
VM options: -DHADOOP_USER_NAME=yilei
public class HdfsClient{
@Test
public void testMkdirs(){
//创建配置文件的对象
Configuration conf = new Configuration();
//通过配置文件配置NameNode的地址
conf.set("fs.defaultFS","hdfs://hadoop01:9820");
FileSystem fs = FileSystem.get(conf);
//2.对应操作
System.out.println(fs);
//3.关闭资源
fs.close();
}
}
客户端操作上传文件
@Test
public void test() throws IOException(){
/*
参数一:是否删除源文件
参数二:是否覆盖目标文件(目标文件已经存在的情况下)
true:覆盖
false:不覆盖,但是目标文件存在的情况下会抛异常
参数三:源文件路径
参数四:目标文件路径
*/
fs.copyFromLocalFile(true,true,new Path("D:\\tset\\aa.txt"),new Path("/"))
}
客户端操作下载文件
@Test
public void test1() throws IOException(){
/*
参数一:是否删除源文件
参数二:源文件路径
参数三:目标文件路径
参数四:是否使用RawLocalFileSystem
false:会生成crc文件
true:不会生成crc文件
*/
fs.copyToLocalFile(false,new Path("/aa.txt"),new Path("D://test"),true);
}
文件删除
@Test
public void test1() throws IOException(){
/*
参数一:要删除的文件或目录的路径
参数二:只对目录有效,如果是一个目录那么必须为true,如果文件就无所谓
*/
fs.delete(new Path("/cc.txt"),true);
}
文件名更改
@Test
public void test1() throws IOException(){
/*
第一个参数 :源文件路径(文件修改名字前的路径)
第二个参数 :目标文件路径 (文件修改名字后的路径)
*/
fs.delete(new Path("/cc.txt"),new Path("aa.txt"));
}
查看文件详情
@Test
public void test1() throws IOException(){
/*
第一个参数 : 要遍历的目录路径
第二个参数 : 是否递归(是否查看子目录中的内容)
*/
RemoteIterator<LocatedFileStatus> fileStatus = fs.listFiles(new Path("/"), true);
//是否有下一个元素
while(fileStatus.hasNext()){
System.out.println("===================文件信息=================");
//获取一个元素
LocatedFileStatus file = fileStatus.next();
//获取文件的名称
System.out.println("文件名:" + file.getPath().getName());
System.out.println("副本数:" + file.getReplication());
System.out.println("-----------------块信息---------------------");
BlockLocation[] blockLocations = file.getBlockLocations();
System.out.println(Arrays.toString(blockLocations));
}
}
判断是文件还是目录
@Test
public void test2() throws IOException {
FileStatus[] status = fs.listStatus(new Path("/"));
for (FileStatus file : status) {
if (file.isFile()){
System.out.println(file.getPath().getName() + "是一个文件");
}else if (file.isDirectory()){
System.out.println(file.getPath().getName() + "是一个目录");
}
}
}
通过流向HDFS上传或下载文件
上传(fs为文件系统对象)
@test
public void test3()throws IOException{
//1.读 - 本地
FileInputStream fis = new FileInputStream("D:\\test\\aa.txt");
//2.写 - HDFS
FSDataOutputStream os = fs.create(new Path("/aa.txt"));
//3.一边读一遍写(文件对拷)
//参数三:缓冲区大小
//参数四:对拷完毕是否关流
IOUtils.copyBytes(fis,os,3000,true);
}
下载(fs为文件系统对象)
@test
public void test4()throws IOException{
//1.读 - HDFS
FSDataInputStream fis = fs.open(new Path("/aa.txt"));
//2.写 - 本地
FileOutputStream fos = new FileOutputStream(new Path("d:\\test\\aa.txt"));
//3.一边读一遍写(文件对拷)
//参数三:缓冲区大小
//参数四:对拷完毕是否关流
IOUtils.copyBytes(fis,fos,3000,true);
}
步骤详述 |
---|
1、客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode请求上传文件,NameNode检查文件是否已存在,父目录是否存在 |
2、NameNode返回是否上传 |
3、客户端请求第一个Block上传到哪几个DataNode服务器上 |
4、NameNode返回3个DataNode节点,分别为n1、n2、n3 |
5、客户端通过FSDataOutputStream模块请求n1上传数据,n1收到请求会继续调用n2,然后n2调用n3,将这个通信管道建立完成 |
6、n1、n2、n3逐级应答客户端 |
7、客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位(一个Packet为64K),dn1收到一个Packet就会传给dn2(同时会往本地磁盘写),dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答 |
8、当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器(重复执行3-7步) |
答:不是随机,客户端会选择距离待上传数据最近的DataNode接收数据。
那如何知道它的距离是最近呢? |
---|
eg:Distance(/d1/r1/n0,/d1/r1/n0)=0 (统一节点上的进程)
Distance(/d1/r2/n1,/d2/r4/n1)=6 (不同数据中心的节点)
副本节点选择(Hadoop3.X) |
---|
第一个副本:在client所处节点上,若客户端在集群外,随机选一个 |
第二个副本:在另外一个机架的随机一个节点上 |
第三个副本:在第二个副本所在机架的随机节点(不与第二副本所在节点相同) |
答:重新建立传输通道,此时就会跳过刚才连接失败的节点;
此时可能就会存在疑问,该案例中是不是就会少了一个副本,短期看是的;
DataNode会定期向NameNode汇报块信息,此时NameNode一旦发现异常,会进行对应的修复,保证Datanode与NameNode的一致性。
答:会进行四次尝试,如果还是连接不上则跳过该节点,向其他节点传输
步骤详述 |
---|
1、客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件所在的DataNode地址 |
2、挑选一台DataNode(就近原则,然后随机)服务器,请求下载数据 |
3、DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验) |
4、客户端以Packet为单位接收,先在本地缓存,然后写入目标文件 |
答:客户端会将读取到的不完整的数据进行清除,重新找一个节点下载blk_1;不存在断点下载。
答:可以,前提是两个客户端(可以并发读,不支持并发写),但是两个客户端读的是两份hello.txt。
假设在磁盘中,我们随机访问时效率会很低
假设在内存中,数据就很容易就丢失了
上面两个假设都不成立,除非上述两种情况同时并行,磁盘内存都存一份
第一阶段:NameNode启动 |
---|
1、第一次启动NameNode格式化后,创建fsimage和edits文件。若不是第一次启动,直接加载编辑日志和镜像文件到内存 |
2、客户端对元数据进行增删改的请求 |
3、NameNode记录操作日志,更新滚动日志 |
4、NameNode在内存中对元数据进行增删改 |
第二阶段 :Secondary NameNode工作 |
---|
1、Secondary NameNode询问NameNode是否需要CheckPoint。直接返回NameNode是否检查结果 |
2、Secondary NameNode请求执行CheckPoint |
3、NameNode滚动正在写的Edits日志 |
4、将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode |
5、Secondary NameNode加载编辑日志和镜像文件到内存,并合并 |
6、生成新的镜像文件fsimage checkpoint |
7、拷贝fsimage checkpoint到NameNode |
8、NameNode将fsimage checkpoint重新命名成fsimage |
NameNode被格式化之后,将在/opt/module/hadoop/data/tmp/dfs/name/current目录中产生如下文件
Fsimage文件:HDFS文件系统元数据的一个永久性检查点,里面包含HDFS文件系统的所有目录和文件inode的序列化信息;
Edits文件:存放文件系统所有的写操作,客户端执行的写操作首次会被记录到Edits文件中;
seen_txid文件:保存最后一个edits_的数字;
注:每次NameNode启动的时候都会将fsimage文件读到内存,加载Edits里面的更新操作,保证内存中的元数据信息都是最新的。
通过查看fsimage_000000000000000000文件,我们并不能看到关于记录块对应的DataNode的信息,为什么?
1)通常情况下,SecondaryNameNode每隔一小时执行一次。
hdfs-default.xml
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
2)自定义
<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 >
答:当NameNode故障,通过Secondary NameNode恢复的元数据是不完整的,最新编辑日志的元数据丢失,这些数据还没有Checkpoint。
1)集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。
查看当前模式
hdfs dfsadmin -safemode get
Safe mode is OFF
bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式状态)
bin/hdfs dfsadmin -safemode enter (功能描述:进入安全模式状态)
bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态)
bin/hdfs dfsadmin -safemode wait (功能描述:等待安全模式状态)
步骤详述 |
---|
1、一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。 |
2、DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。 |
3、心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。 |
4、集群运行中可以安全加入和退出一些机器。 |
DataNode节点保证数据完整性的方法:
添加白名单:添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被退出。
1)在NameNode的/opt/module/hadoop-3.1.3/etc/hadoop目录下创建dfs.hosts文件
hadoop01
hadoop02
hadoop03
2)在NameNode的hdfs-site.xml配置文件中增加dfs.hosts属性
<property>
<name>dfs.hosts</name>
<value>/opt/module/hadoop-3.1.3/etc/hadoop/dfs.hosts</value>
</property>
3)配置文件分发
4)刷新NameNode
hdfs dfsadmin -refreshNodes
5)更新ResourceManager节点
yarn rmadmin -refreshNodes
6)如果数据不均衡,可以用命令实现集群的再平衡
[yilei@hadoop02 sbin]$ ./start-balancer.sh
关于HDFS的内容就总结到这里,欢迎小伙伴们给与指正,同时如果对你有帮助,也劳驾动起你的小手手,投币三联哦!!!