HDFS 基础理论 ( 四大机制+读写原理 )

HDFS 基础理论

四大机制: 心跳机制, 安全模式, 机架感知, 负载均衡;
两大核心: 读写原理

1.心跳机制

master 和 slave 之间通过 ipc 服务通信, 通信有固定时间周期(默认3秒),称之为心跳。

​ dfs.heartbeat.interval: 配置心跳时间

slave 超时时间的计算:
timeout = 2 * dfs.namenode.heartbeat.recheck.interval + 10 *  dfs.heartbeat.interval
默认值:  dfs.namenode.heartbeat.recheck.interval  300000(5 min)
         dfs.heartbeat.interval 3 (3 sec)

查看资料发现, datanode 的 offerService 方法中, 有着每隔3秒向 namenode 发送心跳的代码,
该代码表示, datanode 实际是对 namenode 进行调用:

 public void offerService() throws Exception {
    ...
   while (shouldRun) {
      try {
        long startTime = now();
		// 心跳机制间隔时间判断
        if (startTime - lastHeartbeat > heartBeatInterval) {
          lastHeartbeat = startTime;
          // 在 datanode 中执行 namenode.sendHeartbeat(...)
          // 实际上 **心跳机制就是在 datanode 中 调用 namenode 的方法** !!!
          DatanodeCommand[] cmds = namenode.sendHeartbeat(dnRegistration,
                                                       data.getCapacity(),
                                                       data.getDfsUsed(),
                                                       data.getRemaining(),
                                                       xmitsInProgress.get(),
                                                       getXceiverCount());
    ...

但是 datanode 与 namenode 是不同节点上的两个 jvm 进程, 他们具体是怎样调用的呢 ?
datanode向namenode发送heartbeat过程是这样的:

实际上是通过动态代理的方式进行调用, 以下是大佬总结步骤:
详细请移步, 一步步推理逻辑清晰 :
https://blog.csdn.net/fly542/article/details/6797139

  1. 在 datanode 初始化获得 namenode 的 proxy
  2. 在 datanode上,调用 namenode proxy 的 heartbeat 方法: namenode.sendHeartbeat ( dnRegistration,
    data.getCapacity(),
    data.getDfsUsed(),
    data.getRemaining(),
    xmitsInProgress.get(),
    getXceiverCount() );
  3. 在 datanode 上的 namenode 动态代理类将这个调用包装成 (或者叫“序列化成”) 一个Invocation对象,并调用client.call方法
  4. client.call 方法将 Invocation 转化为 Call 对象
  5. client 将 call 发送到真正的 namenode 服务器
  6. namenode 接收后,转化成 namenode 端的 Call,并处理后,通过 Responder 发回来!
  7. datanode 接收结果,并将结果转化为 DatanodeCommand[]

2.安全模式

namenode在系统启动时会首先进入安全模式, 此时对datanode进行检查数据块的有效性.
如果 datanode 丢失的数据达到 0.1%, 则一直处于安全模式, 此时只读模式, 不可修改与删除文件;
若block丢失小于 0.1% 则自动退出.

  1. safemode是namenode的一种状态 ( active / standby / safemode )

    集群中的文件不能被操作 (安全模式是一种自我保护)

  2. 进入safemode的状况

    dfs.namenode.safemode.threshold-pct ( 默认值0.999f )

    即: block块丢失率达到0.1%, 自动进入, 只读不可修改删除文件

  3. 退出safemode

    方法一: 修复宕机的节点(推荐),自动退出

    方法二: 强制退出safemode(没有解决问题,有可能再次出现数据丢失)

           强制退出命令: hdfs dfsadmin -safemode leave
    
  4. 问题: 为什么集群启动时会自动进入 safemode, 然后又自动退出?

    block 所在的 datanode 的信息存在于内存中,而不在磁盘中。

    故冷启动时,刚开始找不到 block 所在的节点的, 认为 block 丢失, 后再内存中加载, 则恢复.

  5. 安全模式常见命令

	hdfs dfsadmin -safemode get:获取当前的safemode状态
	hdfs dfsadmin -safemode enter:进入safemode状态
	hdfs dfsadmin -safemode leave:退出safemode状态
	hdfs dfsadmin -safemode wait:等待

3.机架感知 - 副本存放策略

  1. HDFS文件块副本的放置对于系统整体的可靠性和性能有关键性影响
    配置机架感知作用 : 将数据分散冗余存储, 以保证数据的可靠性和高效性

  2. 机架感知 ( 又称副本存放策略 )

    1. 原则 ( 从三方面进行考虑 )
      1.高可靠 (副本存放不在同一机架上, 若该机架崩溃, 在另一机架上存放的副本数据仍保全 )
      2.负载均衡 (每个机架副本数均匀分布, 防止出现单个机架存放副本远多于其他机架 )
      3.带宽 (跨越的机架个数, 例如只跨越了一个机架等)
    2. 通常存放策略
      1.第一个副本放在与 Client 相同机架的 Node 中(如果Client不在集群范围,第一个Node是随机选取不太满或者不太忙的Node)
      2.第二个副本放在与第一个 Node 不同的机架中的 Node 中
      3.第三个副本放在与第二个 Node 所在机架里不同的 Node 中
  3. 当没有配置机架信息时
    hadoop 默认所有的机器都在同一个默认的机架下,名为 “/default-rack”

此时,任何一台datanode机器,不管物理上是否属于同一个机架,都会被认为是在同一个机架下
容易出现问题 : 增添机架间网络负载
同时: namenode 默认将所有的slaves机器全部默认为在/default-rack下,
因此在这种情况下写 block 时,三个datanode机器的选择完全是随机的

  1. 配置机架感知方法
    1.配置之前:
    首先要知道一点: 机架感知需要网络拓扑图支持
    简单说, 网络拓扑图就是网络节点设备和通信介质构成的网络结构图 ( 没有地图怎么导航?)
    2.启动机架感知:
    默认情况下, 机架感知是没有启用的, 需要在 NameNode 节点中 hadoop-site.xml 中配置,
    同时用户需要自定义脚本来配置网络拓扑结构:
    <property>  
    	 <name>topology.script.file.name</name>
    	 <value>/path/to/script</value>	  脚本名称及路径
    </property>
    
    3.自定义脚本
    脚本接受一个参数,输出一个值。
    接受的参数通常为 datanode 机器的 ip 地址 (此参数由心跳机制通信传输信息得到 )
    输出的值通常为该 ip 地址对应的 datanode 所在的机架编号( rackID )

过程:
Namenode 启动时,会判断该配置选项是否为空,if not null,则表示已经启用机架感知的配置.
此时 namenode 会根据配置寻找该脚本:
接收到每一个datanode的heartbeat时,将该 datanode 的 ip地址 作为参数传给该脚本运行,
将得到的输出作为该 datanode 所属的机架,保存到内存的一个 map 中。

	脚本的编写
	需将真实网络拓朴和机架信息了解清楚后,通过脚本能将机器的ip地址正确映射到相应的机架上
	官方参考: http://wiki.apache.org/hadoop/topology_rack_awareness_scripts  截图如下
	在脚本编写完成后, 查看网络拓扑结构命令: hdfs dfsadmin -printTopology

HDFS 基础理论 ( 四大机制+读写原理 )_第1张图片
至此机架感知配置完成, hadoop在选择三个 datanode 时,就会按照副本存放策略进行相应的判断.
此时这三步就进行 block 的写入:

  1. 得到 3个 datanode 的列表以后,从返回到客户端之前,会在 namenode 端首先根据该客户端跟每个 datanode 之间的“距离”由近到远进行一个排序,客户端根据这个顺序有近到远的进行数据块的写入
  2. 当根据“距离”排好序的 datanode 节点列表返回给 Client 以后,Client便会创建 Block OutputStream,并向这次 block 写入 pipeline 中的第一个节点(最近的节点)开始写入block数据
  3. 写完第一个block以后,依次按照datanode列表中的次远的node进行写入,直到最后一个block写入成功,Client 返回成功,该 block 写入操作结束

namenode在选择数据块的写入datanode列表时,就充分考虑到了将block副本分散在不同机架下,并同时依据从近到远避免了多余的网络开销.

需要注意的是

  1. HDFS中存储的文件的副本数由上传文件时设置的副本数决定
    无论以后怎么更改系统副本系数,这个文件的副本数都不会改变
  2. 上传文件时优先使用启动命令中指定的副本数, 若启动命令中未指定则使用hdfs-site.xml中配置
修改hdfs-site.xml
  dfs.replication
通过shell命令实现:
  hdfs dfs -setrep 2 文件

4.负载均衡

  1. 产生原因
    HDFS集群非常容易出现机器与机器之间磁盘利用率不平衡的情况,
    例如:当集群内新增、删除节点,节点宕机或者某个节点机器内硬盘存储达到饱和值。
  2. 出现问题
    数据不平衡, Map任务可能会分配到没有存储数据的机器
    导致网络带宽的消耗,也无法很好的进行本地计算, 此时需要对 HDFS 进行数据负载均衡调整
  3. 负载均衡
    负载均衡需要遵循一定原则

1.数据平衡不能导致数据块减少,数据块备份丢失
2.管理员可以中止数据平衡进程
3.每次移动的数据量以及占用的网络资源,必须是可控的
4.数据均衡过程,不能影响 namenode 的正常工作

命令:
实现负载均衡,默认移动速度1m/s(出于带宽考虑,读写)
	start-balancer.sh: 			
设置默认的移动速度
	hdfs dfsadmin -setBalanacerBandwidth 10485760: 
负载最高的节点和最低节点之间的数据差距比例不超过10%
	stat-balancer.sh -t 10%: 
  1. 数据均衡原理
    请移步大佬博客: https://www.cnblogs.com/BYRans/p/5128162.html

5.读原理HDFS 基础理论 ( 四大机制+读写原理 )_第2张图片

读流程总结

  1. client 向 namenode 发送文件下载 (RPC) 请求
    client 调用 FileSystem 对象中 open( ) 方法, 获取文件输入流
  2. namenode 在元数据中进行校验请求下载文件是否存在
    ① 不存在, 报错
    ② 存在, 返回对应文件的 blkid 以及每一个 blkid 对应的的每一个副本的存放位置
    ③ 返回格式: /hadoop.tar.gz [blk001:[hdp01 hdp02] blk002:[hdp01 hdp03]]
  3. client 开始下载第一个数据块, 就近原则
    client 使用 InputStream 中 read( ) 与最近的 datanode 建立连接读取数据
  4. 第一个数据块下载完成, 进行 crc 文件校验, 检验通过, 下载成功
  5. 重复下载步骤, 将内容自动追加到之前的数据块末尾
  6. 直至所有数据块下载成功, 返回给客户端.

至此 HDFS 读流程 ( 文件下载 ) 全部结束, 开始重点部分:

6.写原理

HDFS 基础理论 ( 四大机制+读写原理 )_第3张图片

写流程总结

  1. client 向 namenode 发送上传文件 (RPC) 请求
    client 提供工具根据 url 解析 Hadoop 主节点及端口信息, 来确定将请求发送给哪个节点哪个进程
  2. namenode 在元数据中进行检查, 上传文件目录是否存在, 客户端是否具有权限, 请求是否合理等
    上传文件目录必须存在, 若不存在, 则需要手动创建, 并不会自动创建
  3. namenode 检查通过, 返回 client 允许上传
  4. client 提交真正上传文件的请求, 包含一个重要信息, 上传文件的大小
  5. namenode 返回所有数据块的多个副本的存放节点列表
    在此过程中, namenode 完成三个操作
    ① 通过文件大小计算切块个数 ( 文件总长 / 128M = 切块个数, 向上取整)
    ② 从配置文件中获取副本个数
    ③ 返回节点列表, 按照就近原则返回 ( 同节点 → 同机架 → 同机房), 格式如下:
    file1_blk1 hadoop02,hadoop03,hadoop04
    file1_blk2 hadoop03,hadoop04,hadoop05
  6. client 准备上传文件, 预先进行逻辑切块, 为物理切块做准备
    逻辑切块 : 范围划分, 将数据的每一个数据块对应的数据偏移量范围划分出来, 没有实际切分
    物理切块 : 将需要上传的数据 按照逻辑切块的区域划分进行真正的切块
  7. 开始真正的文件上传, 准备上传第一个数据块
  8. 准备工作:
    ① client 构建第一个数据块上传的通道 pipline
    构建过程: 依次从 client → 第一个副本节点 → 第二个副本节点 → … 并依次向前反馈构建结果
    ② 同时 client 开启一个守护进程 (阻塞) , 等待上传结果的反馈
  9. pipline 构建完成, 开始上传第一个数据块
    文件上传:
    ① client 边进行物理切分边进行上传
    ② 以 packet 为单位上传, 以 dfs.write.packet.size 参数为参考, 默认是 64 K,
    同样, 上传过程: 依次从 client → 第一个副本节点 → 第二个副本节点 → …
    ③ 每次上传一个数据块,每个副本节点都会进行校验,校验结果依次原路给客户端
  10. client 守护线程等待上传文件校验结果通过, 表示写入成功
  11. 重复上传文件步骤, 直至所有数据都上传成功, 此时 client 向 namenode 发送上传成功反馈
    namenode 接到文件上传成功反馈, 修改 namenode 中的元数据

至此 HDFS 写流程 ( 文件上传 ) 全部结束.

你可能感兴趣的:(学习笔记)