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.mzph.cn/pingmian/30442.shtml

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

相关文章

Gobject tutorial 七

The GObject base class GObject是一个fundamental classed instantiatable type,它的功能如下&#xff1a; 内存管理构建/销毁实例set/get属性方法信号 /*** GObjectClass:* g_type_class: the parent class* constructor: the constructor function is called by g_object…

云徙科技助力竹叶青实现用户精细化运营,拉动全渠道销售额增长

竹叶青茶以其别具一格的风味与深厚的历史底蕴&#xff0c;一直被誉为茶中瑰宝。历经千年的传承与创新&#xff0c;竹叶青不仅坚守着茶叶品质的极致追求&#xff0c;更在数字化的浪潮中&#xff0c;率先打破传统&#xff0c;以科技力量赋能品牌&#xff0c;成为茶行业的领军者。…

家长必备:超全的VIP硬笔书法课程(250课完结版),手把手教附可打印控笔素材!

今天要跟大家聊聊一个特别有意思的玩意儿——硬笔书法。你没听错&#xff0c;就是那种用钢笔、圆珠笔&#xff0c;甚至铅笔就能写出漂亮字的技艺。这可不仅仅是写字那么简单&#xff0c;它是一门艺术&#xff0c;一种生活的态度。 阿星记得小时候&#xff0c;爷爷总是拿着毛笔…

http缓存及http2配置

http缓存及http2配置极大提高了网页加载得速度 1.1 nginx安装 首先是需要安装nginx 去官网下载windows版本的安装包 nginx 命令 nginx start //启动 nginx -s stop nginx -s reload // 重新运行 tasklist /fi "imagename eq nginx.exe" //进程 把打包好的文件copy…

PyTorch -- RNN 快速实践

RNN Layer torch.nn.RNN(input_size,hidden_size,num_layers,batch_first) input_size: 输入的编码维度hidden_size: 隐含层的维数num_layers: 隐含层的层数batch_first: True 指定输入的参数顺序为&#xff1a; x&#xff1a;[batch, seq_len, input_size]h0&#xff1a;[batc…

使用密钥对登录服务器

目录 1、使用密钥文件登录服务器 2、登录成功画面&#xff1a; 3、如若出现以下状况&#xff0c;则说明密钥文件登录失败 1、使用密钥文件登录服务器 首先需要上传pem文件 2、登录成功画面&#xff1a; 3、如若出现以下状况&#xff0c;则说明密钥文件登录失败 解决方法&…

嵌入式技术学习——Linux环境编程(高级编程)——shell编程

一、shell编程的基础介绍 1.为什么要进行shell编程? 在Linux系统中&#xff0c;虽然有各种各样的图形化接口工具&#xff0c;但是shell仍然是一个非常灵活的 工具。 Shell不仅仅是命令的收集&#xff0c;而且是一门非常棒的编程语言。 您可以通过使用shell使大量的任务自动化…

mfc140.dll电脑文件丢失的处理方法,这4种方法能快速修复mfc140.dll

mfc140.dll文件是一个非常重要的dll文件&#xff0c;如果它丢失了&#xff0c;那么会严重的影响程序的运行&#xff0c;这时候我们要找方法去修复mfc140.dll这个文件&#xff0c;那么你知道怎么修复么&#xff1f;如果不知道&#xff0c;那么不妨看看下面的mfc140.dll文件丢失的…

【DAMA】掌握数据管理核心:CDGA考试指南

引言&#xff1a;        在当今快速发展的数字化世界中&#xff0c;数据已成为组织最宝贵的资产之一。有效的数据管理不仅能够驱动业务决策&#xff0c;还能提升竞争力和市场适应性。DAMA国际一直致力于数据管理和数字化的研究、实践及相关知识体系的建设。秉承公益、志愿…

集合系列(二十六) -利用LinkedHashMap实现一个LRU缓存

一、什么是 LRU LRU是 Least Recently Used 的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c;选择最近最久未使用的页面予以淘汰。 简单的说就是&#xff0c;对于一组数据&#xff0c;例如&#xff1a;int[] a {1,2,3,4,5,6}&#xff0c;…

SpringBoot配置第三方专业缓存技术Ehcache

Ehcache缓存技术 我们刚才是用Springboot提供的默认缓存技术 我们用的是simple 是一个内存级的缓存 我们接下来要使用专业的缓存技术了 Ehcache 是一个流行的开源 Java 分布式缓存&#xff0c;由 Terracotta 公司开发和维护。它提供了一个快速、可扩展、易于集成的内存缓存…

如何制定适合不同行业的新版FMEA培训计划?

在快速变化的市场环境中&#xff0c;失效模式与影响分析&#xff08;FMEA&#xff09;作为一种预防性的质量控制工具&#xff0c;越来越受到企业的重视。然而&#xff0c;不同行业在FMEA应用上存在着明显的差异&#xff0c;因此制定适合不同行业的新版FMEA培训计划显得尤为重要…

Sui主网升级至V1.27.2版本

其他升级要点如下所示&#xff1a; 重点&#xff1a; #17245 增加了一个新的协议版本&#xff0c;并在开发网络上启用了Move枚举。 JSON-RPC #17245: 在返回的JSON-RPC结果中增加了对Move枚举值的支持。 GraphQL #17245: 增加了对Move枚举值和类型的支持。 CLI #179…

明基的台灯值得入手吗?书客、柏曼真实横向测评对比

如今&#xff0c;近视问题在人群中愈发凸显&#xff0c;据2024年的最新统计数据揭示&#xff0c;我国儿童青少年的近视率已经飙升至惊人的52.7%。在学业日益繁重的背景下&#xff0c;学生们的视力健康成为了社会各界关注的焦点。近视不仅影响视力&#xff0c;还可能引发一系列严…

LeetCode80. 删除有序数组中的重复项 II题解

LeetCode80. 删除有序数组中的重复项 II题解 题目链接&#xff1a; https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/ 题目描述&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素…

渲染农场深度解析:原理理解、配置要点与高效使用策略

许多设计领域的新手可能对“渲染农场”这一概念感到陌生。渲染农场是一种强大的计算资源集合&#xff0c;它通过高性能的CPU和GPU以及专业的渲染引擎&#xff0c;为设计项目提供必要的渲染支持。这种平台由多台计算机或渲染节点组成&#xff0c;形成一个分布式网络&#xff0c;…

从零基础到学完CCIE要多久?

思科认证的CCIE是网络工程师追求的顶级认证之一。 对于刚入门的初学者来说&#xff0c;从零基础到通过CCIE认证&#xff0c;这条路需要多长时间&#xff1f; 这个问题的答案因人而异&#xff0c;取决于多种因素。 这不仅是一个关于时间的问题&#xff0c;更是一个关于规划、学习…

操作系统真象还原:输入输出系统

第10章-输入输出系统 这是一个网站有所有小节的代码实现&#xff0c;同时也包含了Bochs等文件 10.1 同步机制–锁 10.1.1 排查GP异常&#xff0c;理解原子操作 线程调度工作的核心内容就是线程的上下文保护&#xff0b;上下文恢复 。 根本原因是访问公共资源需要多个操作&…

【教学类-64-04】20240619彩色鱼骨图(一)6.5*1CM 6根棒子720种

背景需求&#xff1a; 幼儿益智早教玩具❗️鱼骨拼图 - 小红书在家也能自制的木棒鱼骨拼图&#xff0c;你也收藏起来试一试吧。 #母婴育儿 #新手爸妈 #玩具 #宝宝玩具怎么选 #早教 #早教玩具 #幼儿早教 #益智早教 #玩具 #宝宝早教 #益智拼图 #宝宝拼图 #玩不腻的益智玩具 #儿童…

vscode插件开发之 - Treeview视图

一些测试类插件&#xff0c;往往需要加载测试文件&#xff0c;并执行这些测试文件。以playwright vscode为例&#xff0c;该插件可以显示目录下所有的测试文件。如下图所示&#xff0c;显示了tests目录下的所有xxx.spec.js文件&#xff0c;那么如何在vscode插件开发中显示TreeV…