六、深度剖析 Hadoop 分布式文件系统(HDFS)的数据存储机制与读写流程

深度剖析 Hadoop 分布式文件系统(HDFS)的数据存储机制与读写流程

在当今大数据领域当中,Hadoop 分布式文件系统(HDFS)作为极为关键的核心组件之一,为海量规模的数据的存储以及处理构筑起了坚实无比的根基。本文将会对 HDFS 的数据存储机制以及读写流程展开全面且深入的探究,通过将原理与实际的实例紧密结合的方式,助力广大读者更加全面地理解 HDFS 的工作原理以及其具体的应用场景。

一、HDFS 概述

HDFS 是一种高度分布式的文件系统,其专门为在大规模的集群环境之下存储和管理海量规模的数据而精心设计。它具备着极高的容错性、极为可靠的稳定性以及强大的可扩展性等显著特点,能够轻松处理 PB 级乃至更加庞大的数据量。HDFS 采用了主从架构的模式,主要是由 NameNode 和 DataNode 共同组成。NameNode 负责对文件系统的元数据进行管理,其中涵盖了文件名、文件的目录结构以及文件块的位置信息等等;而 DataNode 则承担着实际的数据存储任务。

二、数据存储机制

(一)数据块(Block)

HDFS 会将文件分割成为固定大小的数据块来进行存储,默认的数据块大小为 128MB(在 Hadoop 3.x 版本当中,可以进行配置以便设定为更大的值,例如 256MB 或者 512MB)。采取这样的举措具有诸多的优势:

  • 首先,对于数据的分布式存储与处理是非常有益的。将大文件拆分为小块,能够使得不同的 DataNode 并行地存储和处理这些数据块,从而极大地提升系统的并发处理能力。
  • 其次,便于数据的容错与恢复。如果某个数据块受到损坏,仅仅需要重新复制该数据块即可,无需对整个文件进行操作。
  • 最后,数据块的大小设置需要综合考虑磁盘传输效率等多方面的因素。较大的数据块可以减少磁盘寻道时间和传输开销,但是同时也会增加内存占用等问题,因此需要依据实际情况进行合理的配置。
    例如,假设有一个大小为 1GB 的文件,按照默认的 128MB 数据块大小进行分割,那么该文件将被划分为 8 个数据块(1GB = 1024MB,1024MB / 128MB = 8)。

(二)副本机制

为了确保数据的可靠性与可用性,HDFS 采用了多副本存储的策略。每个数据块在不同的 DataNode 上会保存多个副本(默认是 3 个副本)。副本的放置策略在 HDFS 的数据存储机制当中占据着重要的地位:

  • 第一个副本通常会放置在与客户端上传数据的节点相同的机架上的某个 DataNode 上(如果客户端位于集群节点上),如此一来可以降低网络传输的开销,提高数据写入的速度。
  • 第二个副本会放置在与第一个副本不同机架的某个节点上,以保障在一个机架出现故障的时候,数据仍然能够保持可用的状态。
  • 第三个副本会放置在与第二个副本相同机架的不同节点上,进一步提升数据的可靠性与可用性。
    以一个简单的集群为例,假设有三个机架分别是 Rack1、Rack2 和 Rack3。客户端 Client 位于 Rack1 上,当它上传一个文件的时候,第一个数据块的副本可能会被存储在 Rack1 的 DataNode1 上,第二个副本可能会被存储在 Rack2 的 DataNode2 上,第三个副本可能会被存储在 Rack1 的 DataNode3 上(但是 DataNode3 与 DataNode1 不在同一服务器上)。
    这种副本放置策略在确保数据可靠性的同时,也兼顾了数据的读写性能以及网络带宽的利用效率。当客户端读取数据的时候,可以从距离最近的副本进行读取,以减少网络延迟。同时,当某个 DataNode 出现故障的时候,系统能够自动从其他副本读取数据,确保数据的可用性。

三、数据写入流程

(一)客户端请求

当客户端想要向 HDFS 写入一个文件的时候,首先会向 NameNode 发起创建文件的请求。请求当中包含文件名、文件权限等元数据信息。

(二)NameNode 响应

NameNode 接收到客户端的请求后,会进行一系列的检查与操作:

  • 首先,检查文件是否已经存在,如果存在则向客户端返回错误信息。
  • 然后,根据文件的大小以及当前集群的负载状况,确定文件要被分割成的数据块数量以及每个数据块的存储位置(即哪些 DataNode 来存储这些数据块的副本)。NameNode 会选取一些具有足够存储空间的 DataNode,并为每个数据块分配一个唯一的标识符(Block ID)。
  • 最后,NameNode 将这些信息反馈给客户端,包括每个数据块的目标 DataNode 列表。

(三)数据写入

客户端接收到 NameNode 的响应后,开始按照指定的顺序将数据块写入对应的 DataNode 中。写入过程呈现出流水线式,即客户端会同时向多个 DataNode 发送数据块,以此来提升写入性能。具体步骤如下:

  1. 客户端首先将数据块分割成一个个数据包(Packet),每个数据包的大小通常为 64KB。
  2. 客户端将第一个数据包发送给第一个 DataNode(DataNode1),DataNode1 接收到数据包后,会将其存储在本地,并立即将该数据包转发给第二个 DataNode(DataNode2),DataNode2 再将其转发给第三个 DataNode(DataNode3),依此类推,形成一个数据传输的流水线。
  3. 当客户端发送完一个数据包后,会立即开始发送下一个数据包,而无需等待第一个数据包完全传输至所有的 DataNode。
  4. 每个 DataNode 在接收到数据包后,都会向客户端发送一个确认信息(ACK),表示已成功接收该数据包。当客户端收到所有 DataNode 对某个数据包的确认信息后,才会认定该数据包写入成功,然后开始发送下一个数据包。
  5. 在数据块写入过程中,如果某个 DataNode 出现故障,客户端会自动从 NameNode 获取新的 DataNode 列表,并重新将数据包发送至新的 DataNode 上,以确保数据的完整性。

(四)副本复制

当第一个数据块写入完成后,客户端会按照相同的流程将其他数据块写入对应的 DataNode 中。在整个文件写入过程中,DataNode 之间会自动进行副本的复制,以保证每个数据块的副本数量达到指定要求。例如,当 DataNode1 接收到客户端写入的数据块后,它会依据副本策略,将该数据块复制到其他指定的 DataNode 上。

(五)结束写入

当客户端完成所有数据块的写入后,会向 NameNode 发送一个完成写入的通知。NameNode 接收到通知后,会将文件的元数据信息持久化存储至磁盘上,至此,整个文件写入过程宣告完成。
下面通过一个实际案例进一步说明数据写入流程。假设我们要将一个大小为 500MB 的视频文件上传至 HDFS。客户端首先向 NameNode 发起创建文件的请求,NameNode 确定该文件需要分成 4 个数据块(假设每个数据块大小为 128MB,最后一个数据块大小为 108MB),并为每个数据块分配存储位置,比如数据块 1 的副本要存储在 DataNodeA、DataNodeB 和 DataNodeC 上。客户端开始将数据块 1 分割成数据包并依次发送给 DataNodeA,DataNodeA 一边接收数据包并存储,一边将其转发给 DataNodeB,DataNodeB 再转发给 DataNodeC。在发送过程中,客户端会持续收到 DataNode 的确认信息,确保数据包写入成功。当数据块 1 写入完成后,客户端按照同样的方式写入其他数据块,直至整个文件写入完成。

四、数据读取流程

(一)客户端请求

当客户端要读取 HDFS 上的一个文件时,首先会向 NameNode 发送一个读取文件的请求,请求中包含文件名。

(二)NameNode 响应

NameNode 接收到客户端的请求后,会根据文件名查找对应的元数据信息,包括文件的数据块列表以及每个数据块的位置信息(即存储该数据块副本的 DataNode 列表)。NameNode 将这些信息返回给客户端。

(三)客户端读取数据

客户端接收到 NameNode 的响应后,会根据数据块的位置信息选择一个距离最近的 DataNode 来读取数据块。读取过程如下:

  1. 客户端向选定的 DataNode 发送一个读取数据块的请求。
  2. DataNode 接收到请求后,将相应的数据块读取出来,并以数据包的形式发送给客户端。每个数据包通常也为 64KB 大小。
  3. 客户端在接收到数据包后,会进行校验和验证,以确保数据的完整性。若校验和不匹配,说明数据在传输过程中可能出现错误,客户端会向 DataNode 请求重新发送该数据包。
  4. 客户端按照顺序依次读取每个数据块,直至整个文件读取完成。
    在读取过程中,如果客户端发现所选的 DataNode 出现故障或者无法正常提供数据,它会自动从 NameNode 获取新的 DataNode 列表,并从其他可用的 DataNode 上读取数据块。
    例如,假设客户端要读取一个存储在 HDFS 上的图片文件,NameNode 返回的信息显示该文件的数据块 1 的副本存储在 DataNodeX、DataNodeY 和 DataNodeZ 上,客户端通过网络距离等因素判断 DataNodeX 距离最近,于是向 DataNodeX 发送读取请求。DataNodeX 将数据块 1 以数据包的形式发送给客户端,客户端在接收过程中进行校验和验证,确保数据正确后继续读取下一个数据包,直至数据块 1 读取完成。然后按照同样的方式读取其他数据块,最终完成整个文件的读取。

五、总结

HDFS 的数据存储机制和读写流程是其实现高效、可靠、可扩展的大数据存储和处理的关键要素。通过将文件分割成数据块并采用多副本存储策略,HDFS 确保了数据的可靠性和可用性,同时也提高了数据的读写性能和并发处理能力。在实际应用中,深入理解 HDFS 的这些原理和流程对于优化大数据应用、解决可能出现的问题以及充分发挥 HDFS 的优势具有重大意义。无论是进行大规模数据存储、数据分析还是数据挖掘等工作,掌握 HDFS 的工作原理都是不可或缺的基础。希望本文通过原理结合实例的讲解,能够帮助读者对 HDFS 有更深入的理解和认识,为在大数据领域的进一步学习和实践奠定坚实的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/58279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android aild 传递多个参数, in ,out,inout

在 HIDL 和 AIDL 中,方法参数的传递方式有所不同。HIDL 使用 generates 关键字来表示方法的返回值,而 AIDL 使用 in、out 和 inout 关键字来表示参数的传递方向。 HIDL 中的 generates 在 HIDL 中,generates 关键字用于指定方法的返回值。例…

https://huggingface.co/上的模型无法用linux服务器clone怎么办(只需要稍微改一下网址,就可以切换到镜像下载)

问题描述: 在ubuntu系统上,使用如下命令,克隆仓库,报无法访问错误: git clone https://huggingface.co/distilbert/distilroberta-base通用解决方案: 把下面部分更换: https://huggingface.…

内存泄漏的隐形陷阱:console.log

console.log 本身不会直接导致内存泄漏,但在特定的场景下,其使用方式可能间接引发内存泄漏问题,特别是在以下情况: 1. console.log 引用闭包或对象 console.log 输出的数据如果包含引用类型(例如:对象、数…

Python 基础语法 - 逻辑运算符

逻辑运算符是用来做逻辑计算的,就像之前用到的比较运算符 ,每一次比较其实就是一次条件判断,都会得到一个相应的True或者False的值,而逻辑运算符的操作数就是一个用来做条件判断的表达式或者变量 运算符说明and与or或not非 1. an…

【云原生】云原生与DevOps的结合:提升软件开发与交付的效率

目录 引言一、什么是云原生?1.1 云原生的核心原则1.2 云原生的技术栈1.3 云原生的优势 二、DevOps的概述2.1 DevOps的起源与发展2.2 DevOps文化的重要性2.3 DevOps工具链 三、云原生与DevOps的结合3.1 CI/CD的概念与重要性3.2 持续交付的实施策略3.3 整合CI/CD流程3…

数字IC后端实现Innovus |给各种IP子模块添加port buffer和antenna diode万能脚本

我们之前分享过在hierarchical flow后端实现中为了确保顶层flatten时timing signoff和physical signoff看到的情况和模块级看到的情况一致,我们会在模块io port添加io port buffer(主要是timing,antenna一致性)。实际上在芯片级我…

PSINS工具箱函数介绍——inserrplot

关于工具箱 i n s e r r p l o t inserrplot in

一个关于@JsonIgnore的isxxx()问题

一个关于JsonIgnore的问题 版本:2.13.5 <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><optional>true</optional></dependency>代码&#xff1a; Data public clas…

多源BFS问题(1)_01矩阵

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 多源BFS问题(1)_01矩阵 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题…

el-select实现模糊搜索、远端搜索

el-select实现模糊搜索、远端搜索 实现代码&#xff1a; <template><div class"item-select-wrapper"><el-select v-model"value1" filterable"filterable" :disabled"disabled" remote"remote" clearable…

前端请求格式

1.multipart/form-data格式发送请求参数 什么时候用&#xff1a; 当后端API要求以表单的形式接收数据时&#xff0c;比如<input type"text" name"username">和<input type"password" name"password">&#xff0c;这些数据…

Java案例——屏蔽信息

首先这次的案例需要用到substring方法&#xff0c;先了解一下&#xff1a; 首先我们来加密一下电话号码&#xff1b; package String; public class Demo_06 {public static void main(String[] args) {// 定义一个电话号码字符串String phoneNumber"13111112598"…

精选:HR招聘管理工具Top5使用体验

作为企业招聘者&#xff0c;如何在选择中找到开启高效招聘之门的钥匙&#xff0c;成为了每一位企业招聘管理者必须面对的难题&#xff0c;在面对市场上琳琅满目的招聘工具&#xff0c;你是否也曾感到无头绪&#xff0c;不知所措&#xff1f;每个工具都声称自己拥有独特的优势和…

【MySQL】JDBC的连接

目录 一. 具体操作如下 1.注册驱动 二.实操 JDBC&#xff08;Java DataBase Connectivity&#xff09;java 数据库连接&#xff0c;是 JavaEE 平台下的技术规范&#xff0c;其定义了在 Java 语言中连接数据&#xff0c;执行 SQL 语句的标准&#xff0c;可以为多种关系数据库…

二叉树的链式表示及实现(实验6--作业)

一、功能概述 这段 C 代码实现了二叉树的一系列操作&#xff0c;包括创建二叉树、前序遍历、中序遍历、后序遍历、层次遍历、中序非递归遍历、求二叉树深度、交换左右子树、统计节点个数以及销毁二叉树等功能。 二、主要数据结构和类型定义 BiTNode结构体表示二叉树的节点&a…

三维测量与建模笔记 - 2.1 坐标转换基础

2D坐标变换 平移可以看做是对原始的x和y加上了一个偏移&#xff0c;也可以理解为按照给定的平移向量进行移动。 缩放变换&#xff0c;本质是对x&#xff0c;y乘上一个缩放系数。 综合缩放、旋转、平移 矩阵乘法的顺序会对结果有影响&#xff0c;需要注意。 2D欧氏变换 2D欧式…

LeetCode_2119. 反转两次的数字_java

1、题目 2119. 反转两次的数字https://leetcode.cn/problems/a-number-after-a-double-reversal/ 反转 一个整数意味着倒置它的所有位。 例如&#xff0c;反转 2021 得到 1202 。反转 12300 得到 321 &#xff0c;不保留前导零 。 给你一个整数 num &#xff0c;反转 num 得…

二十四、Python基础语法(变量进阶)

一、引用 在定义变量的时候, 解释器会给变量和数据分别在内存中分配内存&#xff0c;变量中保存的是数据的地址, 称为引用&#xff0c;Python 中数据的传递,传递的都是引用&#xff0c;可以使用 id(变量) 函数,获取变量中引用地址。 # 将数字1在内存中的地址储存到变量a中 a …

Javascript遍历对象for ....in

//遍历对象for...In //用字变量创建对象&#xff0c;对象中有title&#xff0c;date,author属性和read()方法&#xff0c; let w{ title:xxx塌房了, date:2024年10月28日, author:狗仔, read:function(){ console.log(阅读新闻this.title); } }; w.read(); for(let temp in w){…

帝国CMS 内容页调用上一篇下一篇的方法(精华汇总)

帝国cms默认的内容页的上一页&下一页的调用代码是&#xff1a; 上一篇&#xff1a;[!--info.pre--] 下一篇&#xff1a;[!--info.next--] 但是实话实说&#xff0c;如果做个很普通的模版那足够用了&#xff0c;但是如果想个性化一点的话&#xff0c;比如加背景&#xff…