hdfs文件系统增删查原理

目录

1、hdfs读取文件原理

1.1、读取流程图解

1.2、架构层面读取流程详解

1.3、源码层面读取流程详解

2、hdfs写入文件原理

2.1、写入流程图解

2.2、架构层面写入流程

2.3、源码层面写入流程

3、hdfs删除文件原理

3.1、删除文件图解

3.2、架构层面删除流程

3.3、源码层面删除流程


1、hdfs读取文件原理

1.1、读取流程图解

1.2、架构层面读取流程详解

  1. client向namenode节点发送rpc请求,获取block元数据信息,比如block存放位置;
  2. namenode会使情况返回文件的部分或者全部block列表,对于每个block,namenode都会返回该block副本的datanode地址;
  3. 客户端获取到返回的datanode地址,根据集群拓扑结构获取datanode与客户端的距离,然后进行排序,排序规则(网络拖布结构距离近的client靠前;心跳机制中超时汇报的datanode状态为STALE,这样的靠后);
  4. Client 选取排序靠前的 DataNode 来读取 block,如果客户端本身就是 DataNode,那么将从本地直接获取数据;底层上本质是建立 Socket Stream(FSDataInputStream),重复的调用父类 DataInputStream 的 read 方法,直到这个块上的数据读取完毕;

1.3、源码层面读取流程详解

1. 客户端请求文件信息

//客户端通过 DistributedFileSystem 类的 open 方法请求文件信息:
public FSDataInputStream open(Path f, int bufferSize) throws IOException {// 获取 DFSClient 实例DFSClient dfsClient = new DFSClient();// 调用 DFSClient 的 open 方法return dfsClient.open(f.toString(), bufferSize, true);
}

2. DFSClient 获取文件信息

//在DFSClient类中,open方法与NameNode进行通信以获取文件信息:public DFSInputStream open(String src, int buffersize, boolean verifyChecksum) throws IOException {// 向 NameNode 发送打开文件请求return new DFSInputStream(src, buffersize, verifyChecksum);
}

3. 获取数据块位置信息 

//DFSInputStream 类负责获取文件的块信息
public DFSInputStream(String src, int buffersize, boolean verifyChecksum) throws IOException {this.src = src;this.buffersize = buffersize;this.verifyChecksum = verifyChecksum;// 获取文件的数据块信息openInfo();
}private void openInfo() throws IOException {// 向 NameNode 请求文件信息LocatedBlocks locatedBlocks = dfsClient.getNamenode().getBlockLocations(src, 0, Long.MAX_VALUE);this.blocks = locatedBlocks.getLocatedBlocks();
}

4. 读取数据块

//DFSInputStream通过read方法从DataNode读取数据块
@Override
public synchronized int read(byte[] buf, int off, int len) throws IOException {// 确保文件打开checkOpen();// 读取数据块if (pos < getFileLength()) {// 获取当前数据块信息LocatedBlock currentBlock = getCurrentBlock();// 从 DataNode 读取数据byte[] blockData = readBlock(currentBlock, pos, len);// 将数据写入缓冲区System.arraycopy(blockData, 0, buf, off, len);pos += len;return len;} else {return -1; // 文件读取完毕}
}private byte[] readBlock(LocatedBlock block, long offset, int len) throws IOException {// 获取 DataNode 列表DatanodeInfo[] nodes = block.getLocations();for (DatanodeInfo node : nodes) {try {// 与 DataNode 建立连接InetSocketAddress targetAddr = NetUtils.createSocketAddr(node.getXferAddr());Socket socket = new Socket();socket.connect(targetAddr, dfsClient.getConf().socketTimeout);// 发送读取请求DataOutputStream out = new DataOutputStream(socket.getOutputStream());out.writeLong(block.getBlock().getBlockId());out.writeLong(offset);out.writeInt(len);out.flush();// 接收数据DataInputStream in = new DataInputStream(socket.getInputStream());byte[] data = new byte[len];in.readFully(data);return data;} catch (IOException e) {// 处理读取失败continue;}}throw new IOException("Failed to read block " + block.getBlock().getBlockId());
}

5. 数据组装

//客户端按顺序将读取到的数据块组装成完整的文件
@Override
public void readFully(long position, byte[] buffer, int offset, int length) throws IOException {// 确保文件打开checkOpen();// 逐个读取数据块并组装while (length > 0) {// 获取当前数据块信息LocatedBlock currentBlock = getCurrentBlock();// 计算读取长度int bytesToRead = Math.min(length, (int)(currentBlock.getBlockSize() - offset));// 从 DataNode 读取数据byte[] blockData = readBlock(currentBlock, position, bytesToRead);// 将数据写入缓冲区System.arraycopy(blockData, 0, buffer, offset, bytesToRead);offset += bytesToRead;length -= bytesToRead;position += bytesToRead;}
}

2、hdfs写入文件原理

2.1、写入流程图解

2.2、架构层面写入流程

1)客户端初始化写入请求
        客户端向NameNode发送一个创建文件的请求,包括文件的路径和其他元数据信息。
        NameNode检查是否有同名文件存在,如果没有则创建一个新的文件条目,并返回一个写入            的确认信息给客户端。
2)分块写入数据
        HDFS将文件分成多个块(默认块大小为128MB,可以配置)。
        客户端负责将数据分成适当大小的块进行写入。
3) 数据流和数据节点选择
        客户端从NameNode获取数据块副本的存储位置,NameNode会选择若干个DataNode来存储          每个数据块的副本(默认3个副本)。
        客户端通过Pipeline方式将数据块写入到这些DataNode。
4)数据写入DataNode
        客户端首先将数据写入第一个DataNode。
        第一个DataNode在接收到完整的数据块后,将数据传输给第二个DataNode,第二个                      DataNode再传输给第三个DataNode,依此类推,形成一个数据流管道。
5)数据校验和确认
        每个DataNode在接收到数据块后,会进行数据校验(使用CRC校验),DataNode向客户端            返回确认信息,确认数据块已经成功写入。
6)最终确认和元数据更新
       客户端在接收到所有DataNode的确认信息后,向NameNode发送一个确认请求,表示数据块         已经成功写入。
        NameNode更新文件的元数据信息,包括文件长度、数据块的位置和副本信息。

2.3、源码层面写入流程

1. 客户端请求文件写入

DFSOutputStream out = dfs.create(filePath, true);

2. 创建文件并获取元数据

#客户端通过 NameNode 创建文件,并获取文件元数据,包括所需的 DataNode 列表。
namenode.create(filePath, clientName, true, replication, blockSize);#namenode创建block块
LocatedBlock addBlock(String src, String clientName, ExtendedBlock previous, DatanodeInfo[] excludeNodes, long fileId, String[] favoredNodes) throws IOException {// 分配新的数据块Block newBlock = allocateNewBlock(src, clientName, previous, excludeNodes, fileId, favoredNodes);return new LocatedBlock(newBlock, new DatanodeInfo[0]);
}

3. 初始化写入流

#客户端初始化 DFSOutputStream,准备写入数据块。
DFSOutputStream out = new DFSOutputStream(...);#datastream写入数据包
class DataStreamer extends Daemon {public void run() {while (!closed && !hasError) {Packet packet = getPacket();if (packet == null) {continue;}dfsClient.datanode.writeBlock(packet);}}
}

4. 块的分配

#在 DFSOutputStream 的构造函数中,分配第一个数据块。通过 DFSOutputStream#nextBlockOutputStream 方法,调用 DFSClient#namenode.addBlock 方法向 NameNode 请求分配一个新的数据块。
ExtendedBlock block = namenode.addBlock(src, clientName, previous, excludeNodes, fileId, favoredNodes);

5. 数据流写入 DataNode

#DFSOutputStream 维护一个 DataStreamer 对象,该对象负责将数据写入 DataNode。数据以数据包的形式写入,具体通过 DataStreamer#run 方法进行。
class DataStreamer extends Daemon {public void run() {// 数据包的生成与写入Packet packet = new Packet();dfsClient.datanode.writeBlock(packet);}
}

6. 数据包的传输

#数据包通过 DataStreamer 传输给 DataNode。DataNode 接收到数据包后,写入本地磁盘并通过数据流传递给下一个 DataNode(如果存在副本)。
DataNode datanode = new DataNode(...);
datanode.receiveBlock(block, ...)

 7. 确认接收

#每个 DataNode 接收到数据包并写入后,会发送确认信息给客户端,确认数据已经被成功写入。
DataNode.sendAck();

 8. 数据块的关闭

#所有数据块写入完成后,客户端关闭写入流。
out.close();#在DFSOutputStream的close方法中,调用DFSClient的namenode.complete方法通知NameNode文件写入完成。
namenode.complete(src, clientName, lastBlock);

 9. 元数据更新
NameNode 更新元数据,标记文件状态为已完成,并记录文件的块信息和副本位置。

10. 错误处理
如果写入过程中出现错误,DFSOutputStream 会处理错误并进行重试或失败处理。源码中会有重试逻辑和错误处理代码。

3、hdfs删除文件原理

3.1、删除文件图解

3.2、架构层面删除流程

1)客户端请求删除文件
        客户端通过HDFS API发起删除文件的请求。客户端将文件路径和删除选项(例如是否递归删          除)发送到NameNode。
2)NameNode 处理删除请求
        NameNode接收到客户端的删除请求后,首先会进行权限检查,以确保请求发起者有删除该            文件的权限。
3) 更新元数据和记录日志
        通过权限检查后,NameNode会更新文件系统的元数据,将目标文件或目录从命名空间中删            除。同时,NameNode会将这一操作记录到EditLog中,以确保操作的持久化。
4)通知DataNode清理数据块
        NameNode不会立即通知DataNode删除对应的数据块文件。相反,NameNode将这些数据块          标记为“待删除”,并将这一信息加入到一个待处理的删除队列中。在DataNode的定期心跳汇          报中,NameNode会将需要删除的数据块信息传递给相应的DataNode。
5) DataNode 执行数据块删除
        DataNode接收到来自NameNode的删除指令后,会从本地存储中删除相应的数据块文件,并          释放相关的存储空间。

3.3、源码层面删除流程

1. 客户端请求删除文件

//客户端通过 DistributedFileSystem 类的 delete 方法请求删除文件
public boolean delete(Path f, boolean recursive) throws IOException {// 获取 DFSClient 实例DFSClient dfsClient = new DFSClient();// 调用 DFSClient 的 delete 方法return dfsClient.delete(f.toString(), recursive);
}

2. DFSClient 向 NameNode 发送删除请求

//在 DFSClient 类中,delete 方法与 NameNode 进行通信以删除文件:
public boolean delete(String src, boolean recursive) throws IOException {checkOpen();try {// 向 NameNode 发送删除文件请求return namenode.delete(src, recursive);} catch (RemoteException re) {throw re.unwrapRemoteException(AccessControlException.class,FileNotFoundException.class,SafeModeException.class,UnresolvedLinkException.class);}
}

3. NameNode 处理删除请求

//NameNode 在接收到删除请求后,更新文件系统的元数据,将文件标记为已删除,并记录操作到 EditLog 中。关键类是 FSNamesystem 和 INode。
public boolean delete(String src, boolean recursive) throws IOException {// 获取写锁writeLock();try {// 调用 FSNamesystem 的 delete 方法处理删除请求return fsNamesystem.delete(src, recursive);} finally {// 释放写锁writeUnlock();}
}boolean delete(String src, boolean recursive) throws IOException {checkOperation(OperationCategory.WRITE);FSPermissionChecker pc = getPermissionChecker();boolean ret = false;writeLock();try {checkOperation(OperationCategory.WRITE);ret = deleteInt(pc, src, recursive);} finally {writeUnlock();}return ret;
}private boolean deleteInt(FSPermissionChecker pc, String src, boolean recursive)throws IOException {// 查找文件对应的 INodeINode targetNode = dir.getINode(src);if (targetNode == null) {throw new FileNotFoundException("File/Directory does not exist: " + src);}// 权限检查checkPermission(pc, targetNode, FsAction.WRITE);// 递归删除子目录和文件if (targetNode.isDirectory() && !recursive) {throw new IOException("Cannot delete directory: " + src + " without recursive flag");}// 从目录中删除节点boolean removed = dir.remove(src, targetNode);if (removed) {// 记录操作到 EditLoglogAuditEvent(true, "delete", src);}return removed;
}

4. 更新 DataNode

//在删除文件的过程中,NameNode 不会立即通知 DataNode 删除对应的数据块。DataNode 会定期向 NameNode 汇报数据块的状态,NameNode 在收到汇报后会通知 DataNode 删除不再需要的数据块。
void removeBlocks(List<Block> blocks) {for (Block block : blocks) {addToInvalidateBlocks(block);}processPendingInvalidateBlocks();
}void addToInvalidateBlocks(Block block) {invalidateBlocks.put(block.getBlockId(), block);
}void processPendingInvalidateBlocks() {for (Block block : invalidateBlocks.values()) {DataNode dn = getDataNode(block);if (dn != null) {dn.removeBlock(block);}}
}

5. DataNode 删除数据块

void removeBlock(Block block) {File blockFile = getBlockFile(block);if (blockFile != null && blockFile.exists()) {blockFile.delete();}
}

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

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

相关文章

【Java】已解决java.lang.UnsupportedOperationException异常

文章目录 问题背景可能出错的原因错误代码示例正确代码示例注意事项 已解决java.lang.UnsupportedOperationException异常 在Java编程中&#xff0c;java.lang.UnsupportedOperationException是一个运行时异常&#xff0c;通常表示尝试执行一个不支持的操作。这种异常经常发生…

Word2Vec基本实践

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

MATLAB入门知识

目录 原教程链接&#xff1a;数学建模清风老师《MATLAB教程新手入门篇》https://www.bilibili.com/video/BV1dN4y1Q7Kt/ 前言 历史记录 脚本文件&#xff08;.m&#xff09; Matlab帮助系统 注释 ans pi inf无穷大 -inf负无穷大 i j虚数单位 eps浮点相对精度 0/&a…

【AI】通义千问使用指南:让你快速上手,成为问题解决高手!

大家好&#xff0c;我是木头左。 近日&#xff0c;继文心一言和讯飞星火之后&#xff0c;阿里虽迟但到&#xff0c;直接宣布开源两款“通义千问”大模型。作为国内首个开源且可商用的人工智能大模型&#xff0c;这会给我们带来哪些变化呢&#xff1f; 如何申请阿里通义千问&am…

JupyterLab使用指南(六):JupyterLab的 Widget 控件

1. 什么是 Widget 控件 JupyterLab 中的 Widget 控件是一种交互式的小部件&#xff0c;可以用于创建动态的、响应用户输入的界面。通过使用 ipywidgets 库&#xff0c;用户可以在 Jupyter notebook 中创建滑块、按钮、文本框、选择器等控件&#xff0c;从而实现数据的交互式展…

springboot集成积木报表,怎么将平台用户信息传递到积木报表

springboot集成积木报表后怎么将平台用户信息传递到积木报表 起因是因为需要研究在积木报表做数据筛选的时候需要拿到系统当前登录用户信息做筛选新的模块 起因是因为需要研究在积木报表做数据筛选的时候需要拿到系统当前登录用户信息做筛选 官网有详细介绍怎么集成进去的&…

力扣每日一题 6/19 排序+动态规划

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 2713.矩阵中严格递增的单元格数【困难】 题目&#xff1a; 给你一个下标从…

爆赞!GitHub首本Python开发实战背记手册,标星果然百万名不虚传

Python (发音:[ paiθ(ə) n; (US) paiθɔn ] n. 蟒蛇&#xff0c;巨蛇 )&#xff0c;是一种面向对象的解释性的计算机程序设计语言&#xff0c;也是一种功能强大而完善的通用型语言&#xff0c;已经具有十多年的发展历史&#xff0c;成熟且稳定。Python 具有脚本语言中最丰富…

无问芯穹Qllm-Eval:制作多模型、多参数、多维度的量化方案

前言 近年来&#xff0c;大语言模型&#xff08;Large Models, LLMs&#xff09;受到学术界和工业界的广泛关注&#xff0c;得益于其在各种语言生成任务上的出色表现&#xff0c;大语言模型推动了各种人工智能应用&#xff08;例如ChatGPT、Copilot等&#xff09;的发展。然而…

list集合自定义排序

一、基本类型排序 1.list中只有数字或字符串 //升序排序 List<T> ,T为数字或字符串 Collections.sort(list); //降序排序 Collections.sort(list,Collections.reverseOrder());2.list中为对象 基于jdk.18 import lombok.Data;Data public class User {private int i…

Android网络性能监控方案 android线上性能监测

1 Handler消息机制 这里我不会完整的从Handler源码来分析Android的消息体系&#xff0c;而是从Handler自身的特性引申出线上卡顿监控的策略方案。 1.1 方案确认 首先当我们启动一个App的时候&#xff0c;是由AMS通知zygote进程fork出主进程&#xff0c;其中主进程的入口就是Ac…

linux环境编程基础学习

Shell编程&#xff1a; 相对的chmod -x xx.sh可以移除权限 想获取变量的值要掏点dollar&#xff08;&#xff04;&#xff09; 多位的话要加个花括号 运算&#xff1a;expr 运算时左右两边必须要加空格 *号多个含义必须加转义符 双引号可以加反单&#xff0c;但是发过来就不行 …

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] LYA 的幸运游戏(100分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

Idea连接GitLab的过程以及创建在gitlab中创建用户和群组

上期讲述了如何部署GitLab以及修复bug&#xff0c;这期我们讲述&#xff0c;如何连接idea。 首先安装gitlab插件 下载安装idea上并重启 配置ssh免密登录 使用管理员打开命令行输入&#xff1a;ssh-keygen -t rsa -C xxxaaa.com 到用户目录下.ssh查看id_rsa.pub文件 打开复制…

算法第六天:力扣第977题有序数组的平方

一、977.有序数组的平方的链接与题目描述 977. 有序数组的平方的链接如下所示&#xff1a;https://leetcode.cn/problems/squares-of-a-sorted-array/description/https://leetcode.cn/problems/squares-of-a-sorted-array/description/ 给你一个按 非递减顺序 排序的整数数组…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 部门组队编程(200分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

ArcGIS for js 4.x FeatureLayer 点选查询

示例&#xff1a; 代码如下&#xff1a; <template><view class"map" id"mapView"></view></template><script setup> import "arcgis/core/assets/esri/themes/light/main.css"; import Map from "arcgis/…

没有名为 keras.preprocessing 的模块

估计是因为版本原因 我安装的是 3.3.3版本 >>> import keras >>> print(keras.__version__) 3.3.3 keras.preprocessing.image 将 keras.preprocessing.image 改为 from keras_preprocessing.image 之后报image_type啥的错误&#xff0c;后面查找之后…

使用vscode插件du-i18n处理前端项目国际化翻译多语言

前段时间我写了一篇关于项目国际化使用I18n组件的文章&#xff0c;Vue3 TS 使用国际化组件I18n&#xff0c;那个时候还没真正在项目中使用&#xff0c;需求排期还没有定&#xff0c;相当于是预研。 当时就看了一下大概怎么用&#xff0c;改了一个简单的页面&#xff0c;最近需…

qt事件和连接TCP协议

QT网络聊天室服务器实现 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),server(new QTcpServer(this))//给服务器指针实例化一个空间 {ui->setupUi(this); }Widget::~Widget() {d…