分布式计算系统
随着数据量越来越大,在一个操作系统存不下的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。HDFS的使用场景:适合一次写入,多次读出的场景,



















yarn
<configuration>
<!--Resource Manager的主机名 -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>master</value>
</property>
<! --NodeManager提供的辅助服务,运行MapReduce必配 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<! --NodeManager监控本地磁盘的健康 <磁盘空间使用率上限为98.5%>
<property>
<name>yarn.nodemanager.disk-health-checker.max-disk-utilization-per-disk-percentage</name>
<value>98.5</value>
</property>
</configuration>
配置slave节点
-z用gzip解压压缩文件
-x
-c
-f
tar -zcf压缩文件的路径和名字 原本将被压缩的文件


()

测试集群环境
启动hdfs start-dfs.sh 关闭 stop-dfs.sh
启动yarn start-yarn.sh 关闭 stop-yarn.sh
启动顺序:hdfs start-dfs.sh ---》start-yarn.sh
关闭顺序:stop-yarn.sh --》stop-dfs.sh
测试hdfs上传文件
1.在一台机器上创建一个tjj.txt



2.创建一个hdfs的文件夹

3.把本地文件tjj.txt文件上传到hdfs系统
hadoop fs -put 本地文件地址和名字 上传到hdfs的地址

4.查看文件上传成功
hadoop fs -cat 文件地址和文件名
查看hdfs系统里面的文件内容
逻辑地址 hdfs 系统 /mInput/tjj.txt
物理地址 /
hdfs-site.xml里面记录了实际的物理地址,
datanode的实际存放地
/usr/local/hadoop/tmp/dfs/data
QQ邮箱是逻辑地址,先登录到qq邮箱网站,未读邮件,相应的邮件
物理地址:真实存在,(开发需要知道)
注意:/tInput/tjj.txt hdfs默认存三份 slave1,salve2,slave3,master(分配机制只存储了3台)
怎么去看,存在哪几台机器上了

在availability下面有的机器上(例如上图1,2,3):去执行如下步骤

最后的地址:/usr/local/hadoop/tmp/dfs/data/current/BP-229506653-172.18.0.2-1774328938356/current/finalized/subdir0/subdir0
通过实际物理地址查看文件

测试上传大文件
1.创建文件夹存放
2.本地大文件上传到hdfs系统

3.需要知道大文件在hdfs系统怎么存放的


所有的文件都是按照块存储,大文件可能会分为多个块文件存储。(例如上图,分为两个块分别进行存放)
hdfs系统里面的/bigFiles/jdk-8u171-linux-x64.tar.gz 逻辑地址
物理地址 真正存放的路径 /usr/local/hadoop/tmp/dfs/data
通过物理地址查看文件(去两个块都存在的机器)
cd/usr/local/hadoop/tmp/dfs/data/current/BP-229506653-172.18.0.2-1774328938356/current/finalized/subdir0/subdir0
先到这个路径,可以看到有两个新的块
将两个块文件合并
cat blk_1073741826 >> tmp.tar.gz
cat blk_1073741827 >> tmp.tar.gz
解压压缩包:tar -zxvf tmp.tar.gz

测试wordcount
1.
2.hadoop jar hadoop-mapreduce-examples-3.4.0.jar wordcount /tInput/tjj.txt /tOutput
hadoop jar jar包的位置 jar里面的那个方法 输入路径 输出路径(一定是之前不存在的)
3.



多了一个tOutput文件夹

如下图:可以看到统计了单词出现的频率




为什么会出现问题?为什么加了这几行就能有tOutoput这个文件夹了
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
可以研究下8088这个端口号
第二章重点
1.常用端口号
hadoop3.x
| HDFS NameNode内部通常端口 | 8020/9000/9820 |
| HDFS NameNode 对用户的查询类端口 | 9870 |
| Yarn查看任务运行情况 | 8088 |
| 历史服务器 | 19888 |
hadoop2.x
| HDFS NameNode内部通常端口 | 8020/9000 |
| HDFS NameNode 对用户的查询类端口 | 50070 |
| Yarn查看任务运行情况 | 8088 |
| 历史服务器 | 19888 |
2.常用的配置文件
3.x core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml workers /hadoop/etc/hadoop目录下的
2.x core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml slaves
HDFS
一、概述
1.1HDFS产生背景
随着数据量越来越大,在一个操作系统存不下的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。
1.2HDFS定义
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。
1.3 HDFS 优缺点
优点:
(1)高容错性
- 数据自动保存多个副本。它通过增加副本的形式,提高容错性。
- 某个副本丢失后,它可以自动恢复。
(2)适合处理大数据
- 数据规模:能够处理数据规模到GB、TB,甚至PB级别的数据。
- 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
(3)可构建在廉价机器上,通过多副本机制,提高可靠性。
缺点:
(1)不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。
(2)无法高效的对大量小文件进行存储。
- 存储大量小文件的话,他会占用NameNode大量的内存来存储文件目录和块信息。这样是不可取的,因为NameNode的内存总是有限的;(理解:书包含目录和具体内容)
- 小文件存储的寻址时间会超过读取时间,他违反了HDFS的设计目标
(3)不支持并发写入,文件随机修改。
一个文件只能有一个写,不允许多个线程同时写;
仅支持数据append(追加),不支持文件的随机修改。
1.4HDFS的架构
Apache Hadoop
https://hadoop.apache.org/

NameNode(nn):就是Master(老板),它是一个主管、管理者。
- 管理HDFS的名称空间;
- 配置副本策略;
- 管理数据块(Block)映射信息;
- 处理客户请求。
DataNode:就是Slave(奴隶).NameNode下达命令,DataNode执行实际操作。
- 存储实际的数据块;
- 执行数据块的读/写操作。
Client:就是客户端
- 文件切分。文件上传HDFS的时候Client将文件切分成一个一个的Block,然后进行上传;
- 跟NameNode交互,获取文件的位置信息。
- 与DataNode交互,读取或者写入数据;
- Client提供一些命令来管理HDFS,比如NameNode格式化;
- Client可以通过一些命令来访问HDFS,比如对HDFS增删改查操作。
Secondary NameNode:并非NameNode的热备,当NameNode挂掉的时候,它不能马上替换NameNode并提供服务。
- 辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode
- 在紧急情况下,可恢复辅助NameNode。




发现namenode多了一个 edits_inprogress_0000000000000000164
内存 硬盘
Fsimage(硬盘):为了防止断电数据丢失
Edits:
1.5HDFS文件块大小(面试重点)
HDFS中文件在物理上是分块存储(Block),块的大小可以通过配合参数(dfs.blocksize)来规定,默认大小在Hadoop2.x版本中128M,老版是64M.
block1 block2 block3 block4 block5 ... block66
1.如果寻址时间约为10ms,即查找到目标block的时间约为10ms.
2.寻址时间为传输时间的1%时,则为最佳状态。因此,传输时间=10ms/0.01=1000ms=1s
目前磁盘的输出速率普遍为100MB/s 块大小:100M/s * 1s=100M 128M
普通机械硬盘:80M/s~90M/s 块大小:80M/s * 1s=80M 80M~90M 64M,128M
固态硬盘:200M/s~300M/s 块大小:200M/s * 1s=200M 200M~300M 256M
计算机组成原理 2的多少次方
思考:为什么块的大小不能设置太小,也不能设置太大?
(1)HDFS的块设置太小,会增加寻址时间,程序一直在找块的位置。
(2)如果块设置的太大,从磁盘传输数据的时间会明显大于定位这个块开始新的位置所需要的时间(寻址时间)。导致程序在处理这块数据时,会非常慢。
总结:HDFS块的大小设置主要取决于磁盘传输效率。
1.6HDFS的Shell操作(10分)
1.基本语法(这两作用一模一样)
bin/hadoop fs 具体的命令
bin/hdfs dfs 具体的命令

2.常用的操作命令
(0)启动Hadoop集群
sbin/start-dfs.sh 启动hdfs
sbin/start-yarn.sh 启动yarn
(1) -help :输出这个命令的参数

(2) -ls:显示目录信息
hadoop fs -ls/ :

(3)-mkdir:在HDFS上创建目录


(4)moveFromLocal:从本地剪切粘贴到HDFS
touch:创建一个文件


(5)-appendToFile:追加一个文件到已经存在的文件的末尾
1.要有一个本地文件
touch 文件名(创建一个空文件)
vi 文件名 (编辑这个文件)
cat 文件名(查看这个文件)

2.把本地文件追加到已经存在的HDFS系统里面的文件的末尾
hadoop fs -appendToFile 本地文件和地址 HDFS已经存在的文件的路径以及文件名

(6)-cat 文件名:查看文件

(7) -chgrp ,-chmod, -chown:Linux文件系统中的用法一样。修改文件所属权限(ch代表change,grp代表group,mod代表mode,own代表所有者和组)

drwxr-xr-x :权限 - root:所有者 supergroup:所属组
-chgrp [R] 组名 文件或目录名:改变文件所属的组别


chown 改变文件夹所有者的命令
hadoop fs -chown 文件所有者:组别名字 hdfs的文件或者文件夹

chmod [用户类别][操作符][权限] 文件/目录
1.用户类别
u:所有者(user)
g:所属者组(group)
o:其他用户(others)
a:所有用户(all,默认值)
2.操作符
+:添加权限
-:移除权限
=:直接设置权限(覆盖原有权限)
3.权限
r:读
w:写
x:执行
| 原本的权限 | 语句 | 新的权限 |
| rw- | chmod u+x script.sh | rwx |
| rw- |
chmod g-w data.txt |
r-- |
| rwx | chmod o=r file.txt | r-- |
二、数字模式
chmod [数字组合] 文件/目录
1.权限对应数字
r=4
w=2
x=1
-(无权限)=0
2.数字组合规则
将三类用户(所有者,组,其他用户)的权限,得到三位数字
第一位:所有者权限
第二位:组权限
第三位:其他用户权限
例1:rwxr-xr--
所有者:rwx 4+2+1=7
组:r-x 4+0+1=5
其他用户:r-- 4+0+0=4
例2:rw-r--r--
所有者:rw- 4+2+0=6
组:r-- 4+0+0=4
其他用户:r-- 4+0+0=4

hadoop fs -chmod 666 文件名:将这个文件的三类用户都给了读,写的权利
![]()

(8)-copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去。
hadoop fs -copyFromLocal 本地文件 HDFS的路径(要放的路径下)

(9)-copyToLocal:从HDFS拷贝到本地
(10)-cp:从HDFS的一个路径拷贝到HDFS的另一个路径

(11)-mv:在HDFS目录中移动文件
将ludan.txt从/目录移动到wangzherongyao/fayu/目录下

(12)-get:等同于copyToLocal,就是从HDFS下载文件到本地

(13)-put:等同于copyFromLocal
hadoop fs -put 本地文件 上传到HDFS的系统位置

(14)-tail:显示一个文件的末尾

(15)-rm:删除文件或者文件夹
删文件:hadoop fs -rm hdfs文件路径和名字

删文件夹及文件夹下面所有的文件
hadoop fs -rm -r HDFS文件夹路径及名字
(16)-du:统计文件夹的大小信息

-du:disk usage,查看文件 / 目录占用的磁盘空间
-s:summarize,只显示目录的总大小,不展开子文件
-h:human-readable,用易读的单位(KB/MB/GB)显示大小(但这里因为文件太小,还是显示的字节数)
/wangzherongyao/:HDFS 上要查询的目录路径

(17)-setrep:设置HDFS文件的副本数量



如果想要在web端修改文件副本数,需要将文件的other给到写的权限


Maven:版本管理器,jdk1.8,xml文件
1.7 HDFS客户端操作
集群(master,slave1,slave2,slave3)
shell
windows(不属于集群的机器)(hdfs客户端代码) ---控制 --> 集群
Maven:版本管理器,jdk1.8,xml文件
1.pom.xml文件
<!-- dependencies整个项目的依赖,maven会去找junit 4.12 -->
<dependencies>
<!-- junit 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- log4j 打印日志,日志级别 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.0</version>
</dependency>
<!-- hadoop 的客户端 -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
2.log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig">
<Appenders>
<!-- 类型名为Console,名称为必须属性 -->
<Appender type="Console" name="STDOUT">
<!-- 布局为PatternLayout的方式,
输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here -->
<Layout type="PatternLayout"
pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" />
</Appender>
</Appenders>
<Loggers>
<!-- 可加性为false -->
<Logger name="test" level="info" additivity="false">
<AppenderRef ref="STDOUT" />
</Logger>
<!-- root loggerConfig设置 -->
<Root level="info">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
3.代码
package org.tjj;
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.URI;
public class HdfsClient {
@Test
public void testmkdir() throws IOException, InterruptedException {
//1.创建HDFS客户端,传入uri,配置文件,用户,请求连接172.18.0.2(namenode所在的ip)的集群
FileSystem fileSystem = FileSystem.get(URI.create("hdfs://172.18.0.2:9000"),new Configuration(),"root");
//2.第一步连接已经成功,操作集群,所以去创建一个叫xiyouji的文件夹
fileSystem.mkdirs(new Path("/xiyouji"));
//3.关闭连接
fileSystem.close();
}
}
package org.tjj;
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.URI;
public class HdfsClient {
@Test
public void testmkdir() throws IOException, InterruptedException {
//1.创建HDFS客户端,传入uri,配置文件,用户,请求连接172.18.0.2(namenode所在的ip)的集群
URI uri = new uri("hdfs://172.18.0.2:9000");
Configuration conf=new Configuration();
String user="root";
FileSystem fileSystem=FileSystem.get(uri,conf,user);
//2.第一步连接已经成功,操作集群,所以去创建一个叫xiyouji的文件夹
fileSystem.mkdirs(new Path("/xiyouji"));
//3.关闭连接
fileSystem.close();
}
}
API

public void testCopyFromLocalFile() throws URISyntaxException, IOException, InterruptedException {
//1.连接集群的name node地址
URI uri=new URI("hdfs://172.18.0.2:9000");
//创建一个配置文件
Configuration configuration=new Configuration();
//登录用户
String user ="root";
//获取客户端对象
FileSystem fileSystem=FileSystem.get(uri,configuration,user);
//2.copyFromLocalFile:从本地文件上传到HDFS系统的方法
//参数1(false):表示要不要删掉本地的原始数据,参数2(true):是否可以覆盖
//参数3:要上传的本地文件路径的地址,参数4:Hdfs参数的地址
fileSystem.copyFromLocalFile(false,true,new Path("/root/IdeaProjects/HdfsDemo/src/main/resources/tjjAPI.txt"),new Path("/xiyouji"));
//3.关闭资源
fileSystem.close();
}
package org.tjj;
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.URI;
import java.net.URISyntaxException;
public class HdfsClientV1 {
private FileSystem fileSystem;
@Before
public void init() throws URISyntaxException, IOException, InterruptedException {
URI uri=new URI("hdfs://172.18.0.2:9000");
Configuration configuration=new Configuration();
String user ="root";
fileSystem=FileSystem.get(uri,configuration,user);
}
@After
public void close() throws IOException {
fileSystem.close();
}
@Test
public void testCopyFromLocalFile() throws URISyntaxException, IOException, InterruptedException {
fileSystem.copyFromLocalFile(false,true,new Path("/root/IdeaProjects/HdfsDemo/src/main/resources/tjjAPI.txt"),new Path("/xiyouji"));
}
}
hdfs参数优先级
参数优先级排序:
(1)客户端代码中设置的值>(2)ClassPath下用户自定义配置文件 >(3)服务器的自定义配置(hadoop/etc/hadoop/xxx-site.xml)>(4)服务器的默认配置(xxx-default.xml)
默认值:3

代码运行后:1

代码修改值后:2


hdfs文件下载
public void testCopyToLocalFile() throws IOException {
//从HDFS系统下载文件到本地
//参数1 delsrc:原文件是否删除,参数2 src:HDFS里面要下载的文件路径
//参数3 dst:文件要下载到本地的什么路径下,参数4 useRawLocalFileSystem:是否开启文件校验
//参数4,如果不开启校验,下载的文件会多一个crc结尾的校验文件;选择了true,就不会生成crc结尾的校验文件
fileSystem.copyToLocalFile(false,
new Path("/wangzherongyao/fayu/maKeboluo.txt"),
new Path("/root/IdeaProjects/HdfsDemo/src/main/resources"),
false);
}
作业:测试两个boolean类型,如果修改成True会怎样
HDFS删除
//hdfs里面的删除
public void testDelete() throws IOException {
//参数1:要删除的路径 参数2:是否递归删除
fileSystem.delete(new Path("/xiyouji/tjjAPI.txt"),false);
}
HDFS文件名更改/移动
把luban.txt改成了ludan.txt
public void testRename() throws IOException {
//文件名字的修改
//参数1:HDFS系统里面原本的路径和名字,参数2:hdfs系统里面修改后的路径和名字
boolean rename = fileSystem.rename(new Path("/wangzherongyao/fayu/luban.txt"),
new Path("/wangzherongyao/fayu/ludan.txt"));
}



改文件路径

HDFS文件详情查看
查看文件名称、权限、长度、块信息


public void testListFiles() throws IOException {
//listFiles返回该目录下所有文件和子目录的详细信息,包括文件的长度,块大小,备份数,修改时间,所有者,权限
//参数1:HDFS系统文件夹的位置以及名字,参数2:boolean recursive:是否递归遍历子目录。设置为true的时候,会返回路径下所有子目录的文件,false时仅返回当前目录下的直接文件。
//左边:右边返回的所有文件信息都存储在listFiles对象里面。
RemoteIterator<LocatedFileStatus> listFiles=fileSystem.listFiles(new Path("/bigFiles"),true);
//遍历listFiles
while(listFiles.hasNext()){
//获取到listFiles里面具体的某一条信息,存储在status对象里面
LocatedFileStatus status=listFiles.next();
//输出详细信息
//文件名称
System.out.println(status.getPath().getName());
//文件长度
System.out.println(status.getLen());
//文件权限
System.out.println(status.getPermission());
//文件分组
System.out.println(status.getGroup());
System.out.println("------beautiful------");
//获取存储的块信息,同一个文件的所有块信息都存储在getBlockLocations对象里面
BlockLocation[] blockLocations=status.getBlockLocations();
//对于大文件,一个文件有多个块的情况。所以我们需要遍历getBlockLocations,去获取具体某一个块的信息
for (BlockLocation blockLocation:blockLocations){
//获取存储这个块的hosts(一般是有多少个备份,就有多少个节点)
String[] hosts=blockLocation.getHosts();
//遍历所有节点的hosts
for (String host:hosts){
System.out.println(host);
}
}
System.out.println("+++++++yitiaoxinxijieshu+++++++");
}
}

判断路径下是文件夹还是文件
public void testListStatus() throws IOException{
//获取在hdfs系统下的/wangzherongyao/fayu路径下,所有文件以及文件夹的状态
FileStatus[] listStatus=fileSystem(new Path.listStatus("/wangzherongyao/fayu"));
//遍历listStatus
for(FileStatus fileStatus:listStatus){
//isFile()方法,判断是不是文件
if (fileStatus.isFile()){
System.out.println("file:"+fileStatus.getPath().getName());
}else{
System.out.println("wenjianjia:"+fileStatus.getPath().getName());
}
}
}
}
1.8 hdfs写数据流程(面试重点)(可能会考)
(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步)。
网络拓扑-节点距离计算
在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和。

Distance(d1/r1/n0,d1/r1/n0)=0;
Distance(d1/r1/n1,d1/r1/n2)=1+1=2;
Distance(d1/r2/n1,d1/r3/n2)=2+2=4;
Distance(d1/r2/n0,d2/r4/n1)=3+3=6;

机架感知(replication副本存储节点选择)
机架感知(replication副本存储节点选择)数据可靠性,传递速度快

副本节点选择:
第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。(上传速度最快)
第二个副本在另一个机架的随机一个节点。(数据可靠性)
第三个副本在第二个副本所在机架的随即节点。(速度)
1.9hdfs读取数据流程

(1)客户端通过DistributedFileSystem向NameNode请求下载文件,NameNode通过查询元数00据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
1.10NameNode和SecondaryNameNode
NameNode中的元数据是存储在哪里的?(内存,磁盘)
NameNode的元数据(磁盘,数据):(FsImage存储数据+edits追加修改)合并到fsimage,开机的时候就会将fsimage加载到内存

1)第一阶段:NameNode启动
(1)第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode记录操作日志,更新滚动日志。
(4)NameNode在内存中对元数据进行增删改。
2)第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
(2)Secondary NameNode请求执行CheckPoint。
(3)NameNode滚动正在写的Edits日志。
(4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint。
(7)拷贝fsimage.chkpoint到NameNode。
(8)NameNode将fsimage.chkpoint重新命名成fsimage。
1.11DataNode工作机制

(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的块信息。
(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
(4)集群运行中可以安全加入和退出一些机器。
MapReduce(40分)
1.1 MapReduce定义
MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。
MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。
1.2 MapReduce优缺点
1.2.1 优点
1)MapReduce易于编程
它简单的实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点使得MapReduce编程变得非常流行。
2)良好的扩展性
当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。
3)高容错性
MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由Hadoop内部完成的。
4)适合PB级以上海量数据的离线处理
可以实现上千台服务器集群并发工作,提供数据处理能力。
1.2.2缺点
1)不擅长实时计算
MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果。
2)不擅长流式计算
流式计算的输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化。这是因为MapReduce自身的设计特点决定了数据源必须是静态的。
3)不擅长DAG(有向无环图)计算
多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。
1.3MapReduce进程
(172.18.0.2:9870:看hdfs 8088:看yarn)
一个完整的MapReduce程序在分布式运行时有三类实例进程:
(1)MrAppMaster:负责整个程序的过程调度及状态协调。
(2)MapTask:负责Map阶段的整个数据处理流程。
(3)ReduceTask:负责Reduce阶段的整个数据处理流程。
1.4常用数据序列化类型
| Java类型 | Hadoop Writable类型 |
| Boolean | BooleanWritable |
| Byte | ByteWritable |
| Int | IntWritable |
| Float | FloatWritable |
| Long | LongWritable |
| Double | DoubleWritable |
| String | Text |
| Map | MapWritable |
| Array | ArrayWritable |
1.5MapReduce编程规范
用户编写的程序分成三个部分:Mapper、Reducer和Driver。
1.Mapper阶段
(1)用户自定义的Mapper要继承自己的父类
(2)Mapper的输入数据是KV对的形式(KV的类型可自定义)
(3)Mapper中的业务逻辑写在map()方法中
(4)Mapper的输出数据是KV对的形式(K,V的类型可自定义)
(5)map()方法(MapTask进程)对每一个<k,v>调用一次
2.Reduce阶段
(1)用户自定义的Reducer要继承自己的父类
(2)Reduce的输入数据类型对应Mapper的输出数据类型,也是k,v
(3)Reducer的业务逻辑写在reduce()方法中
(4)ReduceTask进程对每一组相同k的<k,v>组调用一次reduce()方法
3.Driver阶段
相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象
wordcount案列
统计文本文件单词的个数,输出每个单词出现的总次数
I am somebody
I am smart and kind
I am important
I am starve of education
I have places to go
I have people to impress
I have world to change
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)