Hadoop了解篇 Hadoop之HDFS Hadoop之MapReduce Hadoop之Yarn Hadoop之优化&新特性
当下数据量的爆发式增长,在一个操作系统中,我们很难存下所有数据,这时就需要将数据放在等多个操作系统的磁盘中。此时另一个难题就出来了,我们如何对多台电脑的磁盘进行管理呢?这个时候分布式文件管理系统就登场了。
是一个文件系统,用于储存文件,通过目录树来定位文件 并且是分布式的,文件分布在多台服务器的磁盘中。
适合一次写入,多次读出,不支持文件的修改。(内部维持多个副本,随机写的话,分布式数据一致性会受到挑战。而如果一定要保证实时的数据一致性,那么性能上的牺牲就会太大了。所以说,随机写不属于HDFS的适用场景。)
优点:
特点为何?高容错性内部维持多个副本,单一副本丢失,可自动恢复处理数据量大最大处理TB、PB级别的数据;处理百万规模的文件数量可在廉价机器上内部维持多个副本,单一副本丢失,可自动恢复缺点:
特点为何?低延迟储存做不到多副本机制的弊端 ,毫秒级储存难以达到多小文件高效存储做不到会占用大量的NameNode的内存来储存文件元数据;小文件的寻址时间会超过读取时间并发写入,随机修改做不到一个文件只能一个写,不可以多线程同时写;仅支持数据的追加(Append)首先明白:HDFS上的文件在物理上是分块存储(Block),块的大小我们可以根据实际的生产环境通过配置参数(dfs blocksize)来设定。在老版本中默认大小为64M,新版本(2.X)中默认大小为128M。
以从HDFS上下载一个文件为例:
约定:寻址时间为传输时间的1%时,为最佳状态1.假设寻址时间为10ms,即查找目标Block的时间为10ms2.因此在最佳状态下,传输时间为10/0.01=1s3.而目前磁盘的传输速率普遍为100M/S4.1S * 100M/S = 100M5.最接近100M就是128M1)基本语法
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.txt3)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.txt1)下载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); }答:不是随机,客户端会选择距离待上传数据最近的DataNode接收数据。
那如何知道它的距离是最近呢?两节点的距离=两节点到达最近的共同祖先的距离总和
eg:Distance(/d1/r1/n0,/d1/r1/n0)=0 (统一节点上的进程) Distance(/d1/r2/n1,/d2/r4/n1)=6 (不同数据中心的节点)
答:重新建立传输通道,此时就会跳过刚才连接失败的节点; 此时可能就会存在疑问,该案例中是不是就会少了一个副本,短期看是的; DataNode会定期向NameNode汇报块信息,此时NameNode一旦发现异常,会进行对应的修复,保证Datanode与NameNode的一致性。
答:会进行四次尝试,如果还是连接不上则跳过该节点,向其他节点传输
答:客户端会将读取到的不完整的数据进行清除,重新找一个节点下载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请求执行CheckPoint3、NameNode滚动正在写的Edits日志4、将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode5、Secondary NameNode加载编辑日志和镜像文件到内存,并合并6、生成新的镜像文件fsimage checkpoint7、拷贝fsimage checkpoint到NameNode8、NameNode将fsimage checkpoint重新命名成fsimageNameNode被格式化之后,将在/opt/module/hadoop/data/tmp/dfs/name/current目录中产生如下文件
fsimage_000000000000000000fsimage_000000000000000000.md5seen_txidversionFsimage文件:HDFS文件系统元数据的一个永久性检查点,里面包含HDFS文件系统的所有目录和文件inode的序列化信息;
Edits文件:存放文件系统所有的写操作,客户端执行的写操作首次会被记录到Edits文件中;
seen_txid文件:保存最后一个edits_的数字; 注:每次NameNode启动的时候都会将fsimage文件读到内存,加载Edits里面的更新操作,保证内存中的元数据信息都是最新的。
通过查看fsimage_000000000000000000文件,我们并不能看到关于记录块对应的DataNode的信息,为什么?
答:集群启动后,要求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 (功能描述:等待安全模式状态)DataNode节点保证数据完整性的方法:
DataNode读取Block的时候,会计算CheckSum若计算的CheckSum,与Block创建时值不一样,说明Block已经损坏Client读取其他DataNode上的BlockDataNode在其文件创建后周期性验证CheckSum添加白名单:添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被退出。 1)在NameNode的/opt/module/hadoop-3.1.3/etc/hadoop目录下创建dfs.hosts文件
hadoop01 hadoop02 hadoop032)在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 -refreshNodes5)更新ResourceManager节点
yarn rmadmin -refreshNodes6)如果数据不均衡,可以用命令实现集群的再平衡
[yilei@hadoop02 sbin]$ ./start-balancer.sh关于HDFS的内容就总结到这里,欢迎小伙伴们给与指正,同时如果对你有帮助,也劳驾动起你的小手手,投币三联哦!!!
