大数据存储域——HDFS存储系统

摘要

本文介绍了HDFS存储系统,包括其组件、工作机制、实战经验总结、使用场景以及与SpringBoot的实战示例和优化设计。HDFS由Client、NameNode、SecondaryNameNode、DataNode等组件构成,通过特定的工作机制实现文件的读取和写入。它适用于多种场景,如日志采集、大数据离线分析等,但也有不适用的场景。文中还展示了如何在SpringBoot项目中使用HDFS,包括引入依赖、配置文件、配置类、操作服务类和控制器层的实现。最后探讨了HDFS的优化设计。

1. HDFS分布式存储系统简介

Apache Hadoop是一个开源的分布式计算框架,专门用来处理大规模数据集。Hadoop 是一套分布式系统框架,包括:分布式存储技术 HDFS、分布式资源调度技术 YARN、分布式计算框架 MapReduce。

组件

全称

功能

HDFS

Hadoop Distributed File System

分布式存储系统:将大文件切分成多个小块,分布存储在多台机器上,具备容错、冗余、高吞吐的特点。

YARN

Yet Another Resource Negotiator

资源调度与管理系统:负责管理集群中的计算资源,并调度任务运行(如 MapReduce)。

MR

MapReduce

分布式计算框架:一种基于“Map”与“Reduce”模型的数据处理方式,适合批处理大数据。

  • HDFS: 是 Hadoop 的基础存储系统,Master是NameNode,Slave是DataNode。
  • YARN: 是从 Hadoop 2.0 开始引入的新资源管理框架,主要包括 ResourceManager、NodeManager。
  • MapReduce: 是最早期的 Hadoop 计算模型,现在很多场景已被 Spark、Flink 替代(效率更高,支持流处理)。

除了上述核心,Hadoop 还衍生出一系列生态工具:

组件

功能

Hive

数据仓库工具,支持 SQL 查询(将 SQL 转为 MapReduce 任务)

HBase

基于 HDFS 的分布式列式数据库,支持实时读写

Pig

高层数据流语言,抽象 MapReduce 操作

Sqoop

用于在 Hadoop 与 RDBMS(MySQL、Oracle)间导入导出数据

Zookeeper

分布式协调服务(服务发现、元数据管理)

Oozie

用于调度 Hadoop 作业的工作流系统

1.1. HDFS的组件

HDFS (Hadoop Distributed File System, 分布式文件系统) 是Google公司的GFS论文思想的实现,也作为 Hadoop 的存储系统,它包含客户端(Client)、元数据节点(NameNode)、备份节点(Secondary NameNode)以及数据存储节点(DataNode)。

1.1.1. Client

HDFS 利用分布式集群节点来存储数据,并提供统一的文件系统访问接口。这样,用户在使用分布式文件系统时就如同在使用普通的单节点文件系统一样,仅通过对 NameNode 进行交互访问就可以实现操作HDFS中的文件。HDFS提供了非常多的客户端,包括命令行接口、Java API、Thrift接口、Web界面等。

1.1.2. NameNode

NameNode 作为 HDFS 的管理节点,负责保存和管理分布式系统中所有文件的元数据信息,如果将 HDFS 比作一本书,那么 NameNode 可以理解为这本书的目录。

其职责主要有以下三点:

  1. 负责接收 Client 发送过来的读写请求;
  2. 管理和维护HDFS的命名空间: 元数据是以镜像文件(fsimage)和编辑日志(editlog)两种形式存放在本地磁盘上的,可以记录 Client 对 HDFS 的各种操作,比如修改时间、访问时间、数据块信息等。
  3. 监控和管理DataNode:负责监控集群中DataNode的健康状态,一旦发现某个DataNode宕掉,则将该 DataNode 从 HDFS 集群移除并在其他 DataNode 上重新备份该 DataNode 的数据(该过程被称为数据重平衡,即rebalance),以保障数据副本的完整性和集群的高可用性。

1.1.3. SecondaryNameNode

SecondaryNameNode 是 NameNode 元数据的备份,在NameNode宕机后,SecondaryNameNode 会接替 NameNode 的工作,负责整个集群的管理。并且出于可靠性考虑,SecondaryNameNode 节点与 NameNode 节点运行在不同的机器上,且 SecondaryNameNode 节点与 NameNode 节点的内存要一样大。

同时,为了减小 NameNode 的压力,NameNode 并不会自动合并 HDFS中的元数据镜像文件(fsimage)和编辑日志(editlog),而是将该任务交由 SecondaryNameNode 来完成,在合并完成后将结果发送到NameNode, 并再将合并后的结果存储到本地磁盘。

1.1.4. DataNode

存放在HDFS上的文件是由数据块组成的,所有这些块都存储在DataNode节点上。DataNode 负责具体的数据存储,并将数据的元信息定期汇报给 NameNode,并在 NameNode 的指导下完成数据的 I/O 操作。

实际上,在DataNode节点上,数据块就是一个普通文件,可以在DataNode存储块的对应目录下看到(默认在$(dfs.data.dir)/current的子目录下),块的名称是 blk_ID,其大小可以通过dfs.blocksize设置,默认为128MB。

初始化时,集群中的每个 DataNode 会将本节点当前存储的块信息以块报告的形式汇报给 NameNode。在集群正常工作时,DataNode 仍然会定期地把最新的块信息汇报给 NameNode,同时接收 NameNode 的指令,比如创建、移动或删除本地磁盘上的数据块等操作。

1.1.5. HDFS数据副本

HDFS 文件系统在设计之初就充分考虑到了容错问题,会将同一个数据块对应的数据副本(副本个数可设置,默认为3)存放在多个不同的 DataNode 上。在某个 DataNode 节点宕机后,HDFS 会从备份的节点上读取数据,这种容错性机制能够很好地实现即使节点故障而数据不会丢失。

1.2. HDFS的工作机制

1.2.1. NameNode 工作机制

NameNode简称NN

  1. NN 启动后,会将镜像文件(fsimage)和编辑日志(editlog)加载进内存中;
  2. 客户端发来增删改查等操作的请求;
  3. NN 会记录下操作,并滚动日志,然后在内存中对操作进行处理。

1.2.2. SecondaryNameNode工作机制

SecondaryNameNode简称2NN

  1. 当编辑日志数据达到一定量或者每隔一定时间,就会触发 2NN 向 NN 发出 checkpoint请求;
  2. 如果发出的请求有回应,2NN 将会请求执行 checkpoint 请求;
  3. 2NN 会引导 NN 滚动更新编辑日志,并将编辑日志复制到 2NN 中;
  4. 同编辑日志一样,将镜像文件复制到 2NN 本地的 checkpoint 目录中;
  5. 2NN 将镜像文件导入内存中,回放编辑日志,将其合并到新的fsimage.ckpt;
  6. 将 fsimage.ckpt 压缩后写入到本地磁盘;
  7. 2NN 将 fsimage.ckpt 传给 NN;
  8. NN 会将新的 fsimage.ckpt 文件替换掉原来的 fsimage,然后直接加载和启用该文件。

1.2.3. HDFS文件的读取流程

  1. 客户端调用FileSystem 对象的open()方法,其实获取的是一个分布式文件系统(DistributedFileSystem)实例;
  2. 将所要读取文件的请求发送给 NameNode,然后 NameNode 返回文件数据块所在的 DataNode 列表(是按照 Client 距离 DataNode 网络拓扑的远近进行排序的),同时也会返回一个文件系统数据输入流(FSDataInputStream)对象;
  3. 客户端调用 read() 方法,会找出最近的 DataNode 并连接;
  4. 数据从 DataNode 源源不断地流向客户端。

1.2.4. HDFS文件的写入流程

  1. 客户端通过调用分布式文件系统(DistributedFileSystem)的create()方法创建新文件;
  2. DistributedFileSystem 将文件写入请求发送给 NameNode,此时 NameNode 会做各种校验,比如文件是否存在,客户端有无权限去创建等;
  3. 如果校验不通过则会抛出I/O异常。如果校验通过,NameNode 会将该操作写入到编辑日志中,并返回一个可写入的 DataNode 列表,同时,也会返回文件系统数据输出流(FSDataOutputStream)的对象;
  4. 客户端在收到可写入列表之后,会调用 write() 方法将文件切分为固定大小的数据包,并排成数据队列;
  5. 数据队列中的数据包会写入到第一个 DataNode,然后第一个 DataNode 会将数据包发送给第二个 DataNode,依此类推。
  6. DataNode 收到数据后会返回确认信息,等收到所有 DataNode 的确认信息之后,写入操作完成。

2. HDFS实战经验总结

2.1. HDFS存储系统和Mysql数据库有什么区别?

这是一个非常经典的问题,HDFSMySQL 都可以“存数据”,HDFS 是为了解决“海量数据的高吞吐分布式存储”,MySQL 是为了解决“结构化数据的实时存储与查询”问题。但它们的定位、设计目标、使用场景完全不同。下面我们从多个维度来对比,帮你全面理解它们的区别。

2.1.1. 🆚 HDFSvsMySQL:核心区别

维度

HDFS(Hadoop Distributed File System)

MySQL(关系型数据库)

🔧 类型

分布式文件系统

关系型数据库管理系统(RDBMS)

📦 数据结构

存储文件(文本、日志、图片、音视频、大数据文件等)

存储结构化数据表(表格、字段、行、列)

🧱 数据组织

无结构,按块切分存储(默认128MB或更大)

有结构,严格遵守表结构和约束

🧮 查询能力

不提供查询语言,需结合 Hive、Spark 等实现 SQL 分析

提供 SQL 查询语言(SELECT、JOIN、GROUP BY 等)

📊 适合数据类型

非结构化/半结构化/大规模数据

结构化数据

📁 存储方式

把文件分成多个 Block 分布在不同机器上存储

将数据表存储在本地磁盘或SSD中

💾 读写模式

高吞吐量、写一次读多次,适合大批量读写

低延迟、频繁读写,支持事务

📈 扩展性

高度可扩展,轻松支持 PB 级别

扩展能力有限(主从复制、分库分表)

♻️ 容错机制

自动副本、多副本容错(默认3份)

依赖主从复制机制,手动或脚本化恢复

💻 应用场景

大数据存储、日志存储、机器学习、视频/图片归档等

交易系统、用户信息、订单管理、财务报表等传统 OLTP 场景

2.1.2. 🧠 HDFS 和 MySQL比较

类比方式

说明

HDFS 像分布式硬盘

把大量文件分散存储在多台机器上,就像一个巨大的分布式网盘

MySQL像电子表格

数据结构清晰,有行有列,便于查找、过滤、分析

2.1.3. 📌 举个具体例子:

假设你是风控系统的开发者:

  • 你用MySQL存:用户表、借款记录表、规则配置表,支持事务操作和实时查询。
  • 你用HDFS存:用户调用记录日志、历史交易大数据、用户行为日志、模型训练数据等,支持后续批量分析。

2.2. HDFS存储系统的使用场景?

HDFS(Hadoop Distributed File System)是专门为大数据存储与处理设计的分布式文件系统。它不是用来替代数据库的,而是为了解决传统存储系统难以处理海量数据、超大文件、高吞吐量、分布式读写的问题。以下是 HDFS 最常见的典型使用场景,你可以根据业务系统的特点对号入座:

2.2.1. 日志采集与分析

📁 应用场景:收集海量系统日志、用户行为日志、访问记录、接口调用日志等。

📌 为什么适合 HDFS:

  • 数据量大(PB 级别)
  • 文件多且持续产生(写一次、读多次)
  • 不需要实时查询,适合离线分析

✅ 常与 Flume + Hive/Spark 组合使用。

2.2.2. 大数据离线分析

📁 应用场景:大数据报表、风控画像、模型训练、批量数据清洗等。

📌 为什么适合 HDFS:

  • 存储 TB / PB 级原始数据或中间计算结果
  • 结合 Hive、Spark、MapReduce 实现大规模分析任务

✅ 适用于风控系统中的用户信用评分建模、交易异常批量分析等场景。

2.2.3. 机器学习/模型训练数据存储

📁 应用场景:用于训练风控模型、推荐系统、CTR模型等的训练数据。

📌 为什么适合 HDFS:

  • 支持大文件、批量处理
  • 与 Spark ML、TensorFlow on Hadoop 等兼容

✅ 可结合 Spark MLlib、TensorFlow on HDFS 使用。

2.2.4. 视频、图片等大文件归档

📁 应用场景:视频监控数据、图像识别数据、大量媒体内容存储。

📌 为什么适合 HDFS:

  • 文件大(几百 MB 至 GB)
  • 不需要高并发小文件随机读写
  • 存储成本低,可用廉价硬盘搭建

✅ 适合“冷数据”存档、后续批处理。

2.2.5. 数据中台/湖仓一体系统的底层存储

📁 应用场景:大数据中台、数据湖架构中用于统一存储各类结构化、非结构化数据。

📌 为什么适合 HDFS:

    • 与 Hive、Iceberg、Hudi 等表格式存储系统集成
    • 支持数据分区、Schema 管理、演化

✅ 可作为 Data Lake(数据湖)中的底层文件系统。

2.2.6. ETL/数据清洗任务的中间文件存储

📁 应用场景:在数据从业务系统导入、加工、清洗的过程中,作为中间结果文件存储系统。

📌 为什么适合 HDFS:

  • 高吞吐读写
  • 支持批量清洗、转换任务(如 Spark Job)

✅ 通常搭配 Spark、Hive、Oozie 使用。

2.2.7. 企业级风控/征信系统中的大数据底座

📁 应用场景:风控评分引擎、规则引擎的大数据支撑层。

📌 为什么适合 HDFS:

  • 存储来自多渠道的数据源(APP、WEB、第三方接口)
  • 支持跨平台、跨语言的访问(Java、Python、Scala)

2.2.8. 🚫 不适合 HDFS 的场景(谨记)

场景

不推荐使用 HDFS 原因

频繁更新、插入的业务系统(如 OLTP)

HDFS 不支持小文件频繁写入和更新

实时查询、低延迟需求的系统

HDFS 是批处理设计,不支持毫秒级响应

小文件非常多(数千万个 < 1MB 的文件)

小文件会导致 NameNode 元数据压力过大

2.3. HDFS 中NameNode 是怎么管理dataNode,他们是怎么通信的?

在 HDFS(Hadoop Distributed File System)中,NameNode 与 DataNode 之间的通信机制是 HDFS 架构中最核心的部分之一。它实现了文件系统的元数据管理数据块的实际存储的协作。NameNode 负责大脑调度与指挥(元数据、分配 block、恢复副本),DataNode 负责干活(存储数据块)。二者之间通过 心跳、Block 报告、命令下发实现协调合作。 下面详细说明:

2.3.1. 🧠 NameNode 与 DataNode 的职责

角色

作用

NameNode

管理元数据:如文件目录结构、权限、文件到 block 的映射、block 到 DataNode 的映射等

DataNode

存储实际的数据块(block),并定期向 NameNode 汇报其状态

2.3.2. 🔌 通信机制详解

HDFS 中 NameNode 和 DataNode 是通过TCP 协议进行通信的,主要有两种类型的通信:

2.3.2.1. 1️⃣ 心跳(Heartbeat)
  • 目的:让 NameNode 知道哪些 DataNode 还活着;
  • 频率:每 3 秒一次(默认 dfs.heartbeat.interval=3);
  • 通道:DataNode 主动向 NameNode 发送;
  • 携带内容
    • DataNode 的 ID;
    • 当前使用量、剩余空间;
    • 是否处于运行状态;
  • NameNode 响应
    • 是否需要发送 block 报告(Block Report);
    • 是否需要复制、删除某些 block;
    • 启动 block 的复制或删除命令;
2.3.2.2. 2️⃣ Block 报告(Block Report)
  • 目的:告诉 NameNode:这个 DataNode 存储了哪些 block;
  • 频率:每 6 小时(默认 dfs.blockreport.intervalMsec=21600000);
  • 内容:所有 block 的 ID、长度、版本等;
  • 作用:维护 NameNode 的 block-to-DataNode 映射;
2.3.2.3. 3️⃣ 增量 block 报告(Incremental Block Report)
  • 触发时机:当 DataNode 有新的 block 写入、删除或复制;
  • 作用:比 Block 报告更及时,减少元数据滞后;
2.3.2.4. 4️⃣ 客户端读写时的协调(NameNode 作为调度者)
  • 写操作
    • 客户端向 NameNode 请求写入;
    • NameNode 返回可用的若干 DataNode 地址(用于副本);
    • 客户端直接与这些 DataNode 通信写入 block;
  • 读操作
    • 客户端向 NameNode 请求读取文件;
    • NameNode 返回 block 所在的 DataNode 列表;
    • 客户端直接从 DataNode 拉取数据;

2.3.3. 🔄 容错与故障检测机制

  • 超时判定失效节点
    • 如果某个 DataNode 在 10.5 分钟内(默认 3 秒 × 210 次)没有心跳,NameNode 会判定它挂掉(dfs.namenode.heartbeat.recheck-interval);
  • 副本恢复
    • NameNode 会自动触发 block 复制以确保副本数量(dfs.replication);
    • 可通过其他 DataNode 重新恢复副本到健康节点;

2.4. 🧪 可视化示意图

[Client]|                     写/读请求v
[NameNode] <--------- 心跳、Block报告 --------- [DataNode 1]|                                        [DataNode 2]|                                        [DataNode 3]|响应 block 位置信息|
[Client 与 DataNode 通信完成真正的 I/O]

2.5. HDFS中NameNode和DataNode是通过TCP协议进行通信的是通过发送http请求吗?

HDFS中NameNode和DataNode 是通过 TCP 协议通信的,但不是通过 HTTP 请求通信,主要通过以下两种机制:

2.5.1. ✅ 通信协议:HDFS自定义的RPC(远程过程调用)协议

  • NameNode 与 DataNode、Client 之间的通信使用的是 Hadoop 自定义的 RPC 协议,底层是基于 TCP
  • 它不是 HTTP 协议,而是 通过Java 的 Netty/NIO 框架 自定义的高性能传输机制。

2.5.2. ✅ NameNode与DataNode通信流程

2.5.2.1. 📌 启动时注册
  • DataNode 启动后,会向 NameNode 发起注册请求(RPC 形式),发送自己的 IP、端口、存储容量等信息。
2.5.2.2. 📌 定期心跳(默认3秒)
  • DataNode 每隔一段时间(默认 3 秒)向 NameNode 发送心跳包,报告存活状态。
  • 如果 NameNode 超过 10.5 秒(默认值)没收到心跳,就认为该节点挂了。
2.5.2.3. 📌 Block 汇报
  • 每隔一小时或在 Block 变更时,DataNode 会向 NameNode 发送 block 汇报,说明自己当前有哪些 block。

2.5.3. ✅ Client与DataNode的通信

  • 当客户端(Client)读写数据时,会先通过 RPC 向 NameNode 获取数据块位置(block 和 DataNode 的映射信息)。
  • 然后客户端通过 TCP 直接和 DataNode 通信来读写数据,这时候 使用的是 HTTP 协议的子集(叫做 DataTransferProtocol)仍然是基于 TCP

2.5.4. 🔁 NameNode和DataNode总结

通信双方

协议类型

是否基于 TCP

是否 HTTP

NameNode ↔ DataNode

Hadoop RPC

✅ 是

❌ 否

NameNode ↔ Client

Hadoop RPC

✅ 是

❌ 否

Client ↔ DataNode

DataTransfer 协议

✅ 是

✅ 是(部分)

2.6. DataNode 每隔一段时间(默认 3 秒)向 NameNode 发送心跳包,报告存活状态。 是通过定时任务触发吗?

是的,DataNode 向 NameNode 发送心跳包是通过定时任务触发的,具体实现是在 DataNode 的内部线程机制中完成的。

2.6.1. 🔧 DataNode 心跳机制的执行原理

2.6.1.1. ✅ 背景线程:BPServiceActor

DataNode 启动时,会为每一个 Block Pool 启动一个 BPServiceActor(Block Pool Service Actor)线程,这个线程的主要任务包括:

  • 定期向 NameNode 发送心跳(Heartbeat)
  • 汇报 block 列表(Block Report)
  • 发送增量的 block 通知(Incremental Block Report)

这些任务都通过定时机制触发。

2.6.1.2. ✅ 心跳定时任务调度逻辑

在源码中,心跳逻辑大致如下(Hadoop 3.x):

// 每个 BPServiceActor 都维护一个线程,周期性执行:
while (shouldRun) {long startTime = Time.monotonicNow();// 心跳间隔检查if (shouldSendHeartbeat()) {sendHeartBeat(); // 发送心跳}// 处理 Block Report、Command 等等processCommandFromNameNode();long sleepTime = computeNextWaitTime(startTime);Thread.sleep(sleepTime);
}

默认心跳间隔配置项:dfs.heartbeat.interval,默认值是 3 秒。

2.7. 🔍 NameNode如何处理心跳

NameNode 接收到心跳包后,会:

  1. 更新对应 DataNode 的“最后心跳时间”
  2. 检查 DataNode 的状态(健康、存储、负载等)
  3. 向 DataNode 返回指令(如:删除某些 block、副本迁移等)

如果 NameNode 超过 dfs.heartbeat.timeout(默认 10.5 秒 = 3.0 × 3 × 1.5)没有收到心跳,就认为该 DataNode 已失联,触发副本重分配。

2.8. ✅ NameNode心跳总结

项目

内容

心跳机制

是由 DataNode 内部定时线程完成的

实现方式

使用后台线程 + 间隔轮询机制(非 Timer)

默认心跳间隔

dfs.heartbeat.interval = 3s

心跳处理

NameNode 更新状态 + 返回操作指令

2.9. NameNode心跳采用sleep 是不是效率不高? 为啥cronjob 来实现?

下面我从底层线程调度原理、性能考虑以及为什么 HDFS 不用 cronjob 来逐步回答你的问题。

2.9.1. ✅ Thread.sleep() 是否效率不高?

2.9.1.1. ❓ 它的本质是什么?

Thread.sleep(ms) 的本质是:

  • 当前线程主动让出 CPU,进入 TIMED_WAITING 状态。
  • 在指定时间后由系统调度器唤醒,继续运行。
2.9.1.2. ✅ 优点:
  • 低 CPU 占用:线程在 sleep 时不消耗 CPU。
  • 实现简单:只需 sleep 循环即可实现定时行为。
2.9.1.3. ⚠️ 缺点:
  • 不是精准的定时器(受限于系统调度粒度);
  • 无法处理复杂的定时调度(如:每小时整点、每日0点等);
  • 对于大量线程 sleep-wake,系统调度器压力会增加。

但在 HDFS 的这种周期性任务中,这种方式其实是足够轻量且高效的。

2.9.2. ✅ 为什么不用 cron job?

你指的是系统级的 cron(Linux 中的定时任务)吗?HDFS 不用 cron 的原因如下:

2.9.2.1. 🚫 cron job 是系统级进程,不能高频运行
  • cron 最小精度是 分钟级,不适合每 3 秒运行一次;
  • 调用外部命令的方式也会引入启动开销
2.9.2.2. 🚫 Hadoop 是多线程服务进程,不是脚本系统
  • DataNode 是一个长时间运行的 Java 后台服务
  • 使用 cron 等外部定时器调度 Java 内部逻辑是不合适的。

2.9.3. ✅ 为什么不用Java的ScheduledExecutorService

其实 Hadoop 也有一些地方使用了类似 ScheduledExecutorService,但在 DataNode 这种核心、频繁的心跳逻辑中:

  • 为了最大控制权和性能,Hadoop 更倾向使用自己控制的循环 + sleep
  • 它也能更方便地处理异常、网络延迟、自适应重试等高级逻辑。

2.9.4. ✅ NameNode心跳sleep/cron总结

对比点

Thread.sleep

cron job

调度精度

毫秒级(但不准)

分钟级

CPU 占用

无(但需启动子进程)

适合频率

高频调度(如每秒/3秒)

低频调度(如每小时/每天)

适用场景

后台服务内部定时逻辑

系统脚本、任务调度器

Hadoop 是否使用?

✅ 使用

❌ 不使用

在 HDFS 中使用 Thread.sleep() 控制心跳周期,是一种 高效、可控、适合服务进程的方式。相比之下,cron job 不适合这种场景。

3. HDFS+SpringBoot实战示例

下面是一个完整的 Spring Boot + HDFS 实战示例,涵盖以下核心操作:

功能点包括:

  • 上传文件到 HDFS
  • 从 HDFS 下载文件
  • 删除 HDFS 文件
  • 列出目录下文件

3.1. 🧱 引入依赖(pom.xml

<dependencies><!-- Spring Boot 核心依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- Hadoop HDFS 依赖 --><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.3.6</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>3.3.6</version></dependency><!-- Spring Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

🔧 Hadoop 版本请与你的 HDFS 集群保持一致。

3.2. ⚙️ 配置文件 application.yml

hdfs:uri: hdfs://localhost:9000  # 替换为你集群的地址

3.3. 🧩 HDFS 配置类

@Configuration
public class HdfsConfig {@Value("${hdfs.uri}")private String hdfsUri;@Beanpublic FileSystem fileSystem() throws IOException {Configuration config = new Configuration();config.set("fs.defaultFS", hdfsUri);// 如果你使用的是 HA 或 Kerberos,需额外配置return FileSystem.get(URI.create(hdfsUri), config);}
}

3.4. 💼 四、HDFS 操作服务类

@Service
public class HdfsService {@Autowiredprivate FileSystem fileSystem;public void uploadFile(MultipartFile file, String hdfsPath) throws IOException {try (FSDataOutputStream output = fileSystem.create(new Path(hdfsPath));InputStream input = file.getInputStream()) {IOUtils.copyBytes(input, output, 4096, true);}}public byte[] downloadFile(String hdfsPath) throws IOException {try (FSDataInputStream input = fileSystem.open(new Path(hdfsPath));ByteArrayOutputStream output = new ByteArrayOutputStream()) {IOUtils.copyBytes(input, output, 4096, false);return output.toByteArray();}}public boolean deleteFile(String hdfsPath) throws IOException {return fileSystem.delete(new Path(hdfsPath), true);}public List<String> listFiles(String hdfsDir) throws IOException {FileStatus[] statuses = fileSystem.listStatus(new Path(hdfsDir));List<String> files = new ArrayList<>();for (FileStatus status : statuses) {files.add(status.getPath().toString());}return files;}
}

3.5. 📦 控制器层HdfsController

@RestController
@RequestMapping("/hdfs")
public class HdfsController {@Autowiredprivate HdfsService hdfsService;@PostMapping("/upload")public ResponseEntity<String> upload(@RequestParam MultipartFile file,@RequestParam String path) {try {hdfsService.uploadFile(file, path);return ResponseEntity.ok("上传成功: " + path);} catch (IOException e) {return ResponseEntity.status(500).body("上传失败: " + e.getMessage());}}@GetMapping("/download")public ResponseEntity<byte[]> download(@RequestParam String path) {try {byte[] content = hdfsService.downloadFile(path);return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + Paths.get(path).getFileName()).body(content);} catch (IOException e) {return ResponseEntity.status(500).body(null);}}@DeleteMapping("/delete")public ResponseEntity<String> delete(@RequestParam String path) {try {boolean deleted = hdfsService.deleteFile(path);return ResponseEntity.ok(deleted ? "删除成功" : "删除失败");} catch (IOException e) {return ResponseEntity.status(500).body("删除失败: " + e.getMessage());}}@GetMapping("/list")public ResponseEntity<List<String>> list(@RequestParam String dir) {try {return ResponseEntity.ok(hdfsService.listFiles(dir));} catch (IOException e) {return ResponseEntity.status(500).body(Collections.emptyList());}}
}

4. HDFS优化设计

博文参考

《Hadoop原理》

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

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

相关文章

jdk动态代理如何实现

口语化答案好的&#xff0c;面试官。jdk 的动态代理主要是依赖Proxy类 和InvocationHandler 接口。jdk 动态代理要求类必须有接口。在进行实现的时候&#xff0c;首先要定义接口&#xff0c;比如MyService&#xff0c;这个接口就是我们的正常功能的实现。但是希望在不更改MySer…

自然语言处理的相关概念与问题

目录 一、学科的产生与发展 1、什么是自然语言&#xff1f; 2、自然语言处理技术的诞生 二、技术挑战 三、基本方法 1、方法概述 理性主义方法 经验主义方法 2、传统的统计学习方法 3、深度学习方法 词向量表示 词向量学习 开源工具 四、应用举例 1、汉语分词 …

Anthropic MCP架构深度解析:下一代AI工具集成协议的设计哲学

本文深入剖析Anthropic提出的模型通信协议(MCP),揭示其如何重构AI与工具生态的交互范式,打造安全高效的智能体基础设施。 引言:AI工具集成的"巴别塔困境" 当前AI生态面临的核心挑战: #mermaid-svg-lSpYBxzxD5oiYwcL {font-family:"trebuchet ms",verd…

【注意】HCIE-Datacom华为数通考试,第四季度将变题!

最近&#xff0c;数据通信圈子可热闹坏啦&#xff01;好几个渠道都证实了&#xff0c;HCIE - Datacom实验考试马上要有大变化咯&#xff01; 这可不是啥小道消息&#xff0c;也不是那种试点的传言&#xff0c;而是从IE内部技术交流会上得到的确切消息。 这边联系了华为认证的好…

MySql 硬核解析系列 一 MySQL的锁机制

MySQL 的锁机制是其并发控制的核心,直接影响数据库的性能、一致性与可用性。本文将从底层原理、锁的分类、实现机制、锁的粒度、锁的兼容性、死锁处理、InnoDB 的行锁实现、MVCC 与锁的关系等多个维度,进行硬核、深度解析,适用于希望深入理解 MySQL 并发控制机制的开发者与 …

7.软件工程

软件生命周期软件生命周期什么是软件工程&#xff1f;以工程化的原则和方法来开发软件&#xff0c;其目的是提高软件生产率、提高软件质量、降低软件成本。软件工程3大组成部分&#xff1a;方法、工具、过程。什么是软件生命周期&#xff1a;经过开发、使用和维护&#xff0c;直…

C 语言结构体与 Java 类的异同点深度解析

在编程语言的发展历程中,C 语言的结构体与 Java 的类扮演着至关重要的角色。作为面向过程编程的经典代表,C 语言的结构体为数据封装提供了基础形式;而 Java 作为纯面向对象语言,类则是其核心语法结构。二者既存在一脉相承的设计思想,又因编程语言范式的差异呈现出显著区别…

C++、STL面试题总结(二)

1. 必须实现拷贝构造函数的场景 核心问题&#xff1a;默认拷贝构造的缺陷 C 默认的拷贝构造函数&#xff08;浅拷贝&#xff09;&#xff0c;会直接拷贝指针 / 引用成员的地址。若类包含引用成员或指向堆内存的指针&#xff0c;浅拷贝会导致 “多个对象共享同一份资源”&…

IntelliJ IDEA2024 错误‘http://start.spring.io/‘的初始化失败,请检查URL、网络和代理设置。

下载新版本的intellij idea2024创建项目时&#xff0c;服务器URL报错误http://start.spring.io/的初始化失败&#xff0c;请检查URL、网络和代理设置。错误消息&#xff1a;Cannot download http://start.spring.io/:Permission denied:getsockopt&#xff0c;具体如下图&#…

从零开始的云计算生活——第三十八天,避坑落井,Docker容器模块

一.故事背景 在综合使用了之前全部的知识完成项目之后&#xff0c;接下来将学习更简单的方法来对之前的命令进行使用&#xff0c;马上进入容器模块 二. Docker概述 Docker简介 Docker&#xff0c;翻译过来就是码头工人 Docker是一个开源的应用容器引擎&#xff0c;让开发者…

Python与自动化运维:构建智能IT基础设施的终极方案

Python与自动化运维:构建智能IT基础设施的终极方案 引言:运维革命的Python引擎 在DevOps理念席卷全球的今天,企业IT基础设施的复杂度呈指数级增长。某跨国银行的数据显示,采用Python构建的自动化运维体系使其服务器部署效率提升400%,故障响应时间缩短至原来的1/8。本文将…

HarmonyOS应用开发环境搭建以及快速入门介绍

下载并安装DevEco Studio&#xff0c;这是华为官方提供的HarmonyOS应用开发IDE。访问华为开发者联盟官网下载对应操作系统的版本。安装完成后&#xff0c;配置HarmonyOS SDK和必要的工具链。 确保计算机满足开发环境要求&#xff0c;包括Windows 10 64位或macOS 10.14及以上操…

RocketMQ与Kafka 消费者组的‌重平衡操作消息顺序性对比

RocketMQ 的重平衡机制本身不会直接影响消息顺序&#xff0c;但消费模式的选择和使用需注意以下细节&#xff1a;重平衡机制RocketMQ消费者组的重平衡策略是每隔20秒从Broker获取消费组的最新消费进度&#xff0c;并根据订阅信息重新分配消息队列。该策略主要影响消息拉取的均衡…

学习 Android(十四)NDK基础

学习 Android&#xff08;十四&#xff09;NDK基础 Android NDK 是一个工具集&#xff0c;可让我们使用 C 和 C 等语言以原生代码实现应用的各个部分。对于特定类型的应用&#xff0c;这可以帮助我们重复使用以这些语言编写的代码库。 接下来&#xff0c;我们将按照以下步骤进行…

宝塔(免费版9.2.0)的docker拉取仓库失败的加速方法

宝塔docker拉取仓库失败 完美加速方法_宝塔docker加速-CSDN博客 版本&#xff1a;免费版 9.2.0 https://docker.1ms.run 其他的试了很多 都不行 最后不要用宝塔的控制面板(很卡)&#xff0c;直接在linux中用命令行&#xff0c;效果就很好了。

文献解读-生境分析亚区域选择+2D_DL+3D_DL-局部晚期食管鳞状细胞癌新辅助化疗免疫治疗反应预测

研究标题&#xff1a;结合亚区域放射组学与多通道二维或三维深度学习模型预测局部晚期食管鳞状细胞癌&#xff08;LA-ESCC&#xff09;患者对新辅助化疗免疫治疗&#xff08;NACI&#xff09;的反应借鉴点&#xff1a;建模思路&#xff08;看流程图理解就够了&#xff09;引言食…

机器学习第四课之决策树

目录 简介 一.决策树算法简介 二. 决策树分类原理 1.ID3算法 1.1 熵值 1.2 信息增益 1.3 案例分析 ​编辑 2.C4.5 2.1 信息增益率 2.2.案例分析 3.CART决策树 3.1基尼值和基尼指数 3.2案例分析 三、决策树剪枝 四、决策树API 五、电信客户流失 六、回归树 七. 回归…

Java面试题和答案大全

一、Java基础知识 1. Java语言特点 题目: 请说明Java语言的主要特点? 答案: 面向对象:Java是纯面向对象的语言,支持封装、继承、多态 平台无关性:一次编译,到处运行(Write Once, Run Anywhere) 简单性:语法简洁,去掉了C++中的指针、多重继承等复杂特性 安全性:提…

用NAS如何远程访问:详细教程与实用技巧

在信息时代&#xff0c;家用NAS&#xff08;网络附加存储&#xff09;成为家庭数据存储和管理的热门设备。它不仅可以作为家庭照片、视频、工作文件的集中存储中心&#xff0c;还支持远程访问&#xff0c;方便用户随时随地获取数据。那么&#xff0c;如何配置和实现家用NAS的远…

Qt-桌面宠物

目录 一&#xff0c;演示&#xff08;部分功能&#xff09; 二&#xff0c;开发环境准备 三&#xff0c;部分代码实现 1.创建基础窗口 2.实现宠物动画 3.添加交互功能 4.系统托盘集成 5.行为模式实现 6.状态管理系统 7.资源打包部署 四&#xff0c;接受定制 一&…