HDFS工作机制
工作机制:
1. HDFS集群分为两大角色:DataNode.NameNode 节点
2. NameNode:管理文件系统的Namespace,维护着文件系统的元数据(MetaData)
3. DataNode : 负责用户的文件数据块的存储.根据客户端或者namenode的调度存储和检索数据,并且 定期向namenode发送他们所存储的块(block)的列表.
4. 文件会按照固定大小(blocksize 默认值是128M [可以配置]) 切分成若干块后分布式存储在不同的DataNode上.
5. 每一个切片文件可以存在多个备份 ,(默认是3 [可以配置])存储在不同的DataNode上
6. HDFS的内部工作机制对客户端保持透明,客户端请求访问都是通过向NameNode发送请求来进行的.
HDFS写数据流程分析
1.客户端向NameNode发送写数据请求.
2.NameNode检查元数据的目录树是否存在该文件,父目录是否存在.检查权限.
3.返回通知客户端可以上传文件.客户端切分文件为blocks.
4.请求上传block0.
5.NameNode检查DataNode信息池,查看那些DataNode适合存储block块与副本.
6.返回可以上传与备份的DataNode信息 (例:2台机器)
- 首先就近原则挑选一台机器存储
- 第二台优选另一机架上的DataNode
- 第三台在本机架上再挑选一台
7.发出传输数据建立pipleline(管道通信)请求,本质上是RPC请求.
8.建立pipleline连接 (这种写数据的方式呈流水线的形式).
9.客户端开始往DataNode01上传第一个block0(先从磁盘读取数据放到本地缓存),以packet为单位,
DataNode01接收到第一个packet就会通过pip传给DataNode02; 每传一个packet会放到一个应答队 列等待应答.
10.第一块上传完成后,客户端再次请求 上传block02.
HDFS读数据流程分析
客户端将要读取的文件路径发送给NameNode,NameNode获取文件的元信息(主要是block的存放位置信息)返回给客户端,客户端根据返回的信息找到相应的DataNode 逐个获取文件的block并在客户端本地进行数据追加合并从而获得整个文件.
- 请求读取文件 /test.txt
- 查询NameNode元数据信息
- 返回元数据信息:(主要是文件所对应的机器)
/test.txt
{blk_01,blk_02,blk_03} {blk_01:dn01,dn02}
{blk_02:dn02,dn03} {blk_03:dn01,dn03}
- 建立socket连接,发送请求读取block_01,从节点机器将块数据读取到内存中,并以packet为单位发送给客户端.
- 客户端以packet方式,先在本地缓存,然后写入目标文件.
NameNode工作机制
NameNode作为HDFS集群 中的主节点,其主要职责为:
- 负责客户端的请求与响应
- 实现源数据的管理(其中包括查看,修改)
- 与DataNode存在hb心跳机制 (交互状态信息)
NameNode对数据的管理采用了三种存储形式:
- 内存元数据 : 内存中有一份完整的元数据.(meta data)
- 磁盘元数据镜像文件FSImage : 磁盘有一个"准完整"的元数据镜像文件,里面记录了自最后一次检查点之前HDFS文件系统中所有目录和文件的序列化信息;
- 数据操作日志文件edit : 用于衔接内存meta data和磁盘元数据镜像FSImage之间的日志.
客户端对HDFS的操作请求会记录到edit日志中.
如下图所示:
每隔一段时间(系统默认1小时 或 自定义时间 )会由Secondary NameNode 将NameNode上积攒的所有edits和一个最新的FSImage 下载到本地,并加载到内存中进行merge (这个过程称之为Checkpoint)
1.Secondary NameNode 向NameNode发送请求 准备执行check point操作.
2.快速切换日志文件,将之前的日志文件保存到磁盘中
3.Secondary NameNode copy FSImage文件 和 edit日志文件到磁盘中
4.通过镜像文件与日志文件读取到meta data内存中
5.模拟用户操作 将其合并后 序列化 成功一个新的image checkpint 文件
6.上传到NameNode FSImage镜像文件中
checkpoint操作的触发条件配置参数有2种 一种是定时执行,另一种是2次checkpint之间的时间间隔,
可以在hdfs-site.xml中配置:
dfs.namenode.checkpoint.check.period=60 # 检查触发条件是否满足频率 60s
dfs.namenode.checkpoint.dir=file://${hadoop.tmp.dir}/dfs/namesecondary
# 这两个参数 : 做checkpint操作时,secondary namenode 的本地工作目录
dfs.namenode.checkpoint.edits.dir=${dfs.namenode.checkpoint.dir}
dfs.namenode.checkpoint.max-retries=3 #๋ 失败的最大重试次数
dfs.namenode.checkpoint.period=3600 # 两次checkpoint之间的时间间隔
dfs.namenode.checkpoint.txns=1000000 #两次checkpoint之间最大的操作记录数
DataNode工作机制
DataNode作为HDFS集群的从节点,其职责:
1.存取管理用户的切片文件.
2.通过心跳机制定期向NameNode汇报自身所持有的block信息,以及容量情况.
可以通过hdfs-site.xml文件中进行配置
<property>
<name>dfs.blockreport.intervalMsec</name>
<value>3600000</value> <!-- 这里定义每一小时汇报一次 -->
<description>Determines block reporting interval in milliseconds.</description>
</property>
DataNode进程死亡 或者 网络延迟造成的无法与NameNode通信,NameNode不会立刻把该节点判定死亡,要经过一段时间,这段时间称之为超长时间.HDFS默认超长时间为10分钟30秒如果定义超长时间timeout,
则超长时间的计算公式为:
timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval
默认的 heartbeat.recheck.interval 大小为5分钟 , dfs.heartbeat.interval 默认为3分钟
hdfs-site.xml 配置文件中的 heartbeat.recheck.interval 单位是毫秒.
dfs.heartbeat.interval 的单位是秒
HDFS内部RPC通讯模拟
Hadoop在客户端与服务端之间.服务端的各个节点无时无刻都在进行着数据交互,这些交互都是通过RPC来实现的,为了简化RPC实现的开发流程,Hadoop做了进一步的封装.
模拟RPC通信
导入依赖
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.6.4</version>
<!-- 如果不是跑在集群上 这句需要删除否则报错 -->
<scope>provided</scope>
</dependency>
</dependencies>
服务端代码如下:
/**
* 对外提供服务接口
*/
public interface NameNodeServiceProtocal {
//必须添加一个versionID
public long versionID = 1L;
public String getMetaData(String path);
}
/**
* 模拟NameNode提供元数据
*/
public class NameNode implements NameNodeServiceProtocal{
@Override
public String getMetaData(String path) {
return path+" 2,{blk_1,blk_2},{blk_1:mini1,mini2},{blk_2:mini2:mini3}";
}
}
/**
* 模拟服务端对外提供服务
*/
public class ServerPublisher {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
Builder builder = new RPC.Builder(conf)
.setBindAddress("localhost")
.setPort(8383)
.setProtocol(NameNodeServiceProtocal.class)
.setInstance(new NameNode());
Server server = builder.build();
server.start();
}
}
/**
* 为了保证提供的服务接口能够在客户端接收到,所以必须将服务端的 NameNodeServiceProtocal 接口 拷贝
* 到客户端, 注意:NameNodeServiceProtocal所在的包必须与服务端所在的包同名
*/
public class HDFSClient {
public static void main(String[] args) throws Exception {
NameNodeServiceProtocal nameNode = RPC
.getProxy(NameNodeServiceProtocal.class,
NameNodeServiceProtocal.versionID,
new InetSocketAddress("localhost", 8383),
new Configuration());
String metaData = nameNode.getMetaData("/a.txt");
System.out.println(metaData);
}
}