Spark 从HDFS读取时,通常按文件块(block)数量决定初始partition数,这是怎么实现的?

在 Spark 中,从 HDFS 读取数据时按文件块(block)数量决定初始 partition 数 ,这一机制是通过 Hadoop InputFormat 的分片(split)策略实现的。具体流程如下:


1. HDFS 文件块(Block)与 Spark Partition 的对应关系

  • HDFS 默认块大小(如 128MB/256MB)决定了文件的物理存储分布。

  • Spark 在读取 HDFS 文件时 ,会调用 Hadoop 的 InputFormat(如 TextInputFormatSequenceFileInputFormat)来生成数据分片(InputSplit)。

  • 每个 InputSplit 会映射为一个 Spark Partition ,因此:
    初始 Partition 数 ≈ HDFS 文件块数

    (假设文件未被压缩且未手动指定分区数)。


2. 底层实现机制

(1) 调用 Hadoop API

Spark 通过 HadoopRDDNewHadoopRDD 读取 HDFS 数据时,会使用 Hadoop 的 InputFormat.getSplits() 方法生成分片。

  • 关键类

    • org.apache.hadoop.mapreduce.InputFormat

    • org.apache.spark.rdd.HadoopRDD

(2) 分片(Split)生成逻辑

TextInputFormat 为例:

  1. 按文件块切分

    • 每个 HDFS 文件块(block)默认生成一个 FileSplit(即一个 InputSplit)。

    • 例如:一个 1GB 的文件(128MB/block)会生成 8 个 FileSplit → 对应 8 个 Spark Partition

  2. 处理跨行问题

    • 如果某一行数据跨越两个 block,Hadoop 会通过 网络读取下一个 block 的开头部分,确保数据完整性。
(3) Spark 的 Partition 分配
  • 生成的 InputSplit 会被封装为 HadoopPartition,最终构成 RDD 的分区:

    Scala 复制代码
    // HadoopRDD 中的分区生成逻辑
    override def getPartitions: Array[Partition] = {
      val inputSplits = inputFormat.getSplits(jobConf, minPartitions)
      inputSplits.map(split => new HadoopPartition(id, split.index, split))
    }
    • 这里的 minPartitions 是用户指定的最小分区数(默认不指定时等于 inputSplits.size)。

3. 特殊情况处理

(1) 压缩文件
  • 如果文件是 不可分割的压缩格式 (如 GZIP),整个文件会被视为 一个 InputSplit → 仅生成 1 个 Partition

  • 可分割压缩格式(如 BZip2)仍按 block 切分。

(2) 手动指定分区数
  • 通过 sc.textFile(path, minPartitions) 指定最小分区数时:

    • Spark 会尝试合并或拆分 InputSplit 以满足 minPartitions 要求。

    • 但最终分区数可能 大于 minPartitions(因为不能拆分单个 block)。

(3) 小文件合并
  • 大量小文件会导致 Partition 数过多(每个小文件至少 1 个 Partition),可通过以下方式优化:

    • 使用 coalesce 减少分区。

    • 读取时指定 minPartitions(如 sc.textFile("hdfs://path/*.txt", 100))。


4. 验证方法

(1) 查看 RDD 的分区数
Scala 复制代码
val rdd = sc.textFile("hdfs://path/file.txt")
println(rdd.partitions.size)  // 输出实际分区数
(2) 调试 Hadoop InputSplits
Scala 复制代码
val hadoopConf = sc.hadoopConfiguration
val path = new org.apache.hadoop.fs.Path("hdfs://path/file.txt")
val inputFormat = new org.apache.hadoop.mapreduce.lib.input.TextInputFormat
val splits = inputFormat.getSplits(new org.apache.hadoop.mapreduce.JobContext(hadoopConf, null))
println(splits.size)  // 输出Hadoop生成的InputSplit数

5. 总结

关键点 说明
默认规则 1 个 HDFS block → 1 个 InputSplit → 1 个 Spark Partition
压缩文件 不可分割压缩格式(如 GZIP)→ 仅 1 个 Partition
手动控制 sc.textFile(path, minPartitions) 可调整分区数下限
优化建议 避免大量小文件,合理设置 minPartitions

通过这一机制,Spark 天然适配 HDFS 的分布式存储特性,实现数据本地化(Data Locality),减少网络传输开销。

相关推荐
多年小白1 小时前
紫光国微(002049) 分析
大数据·科技·深度学习·ai
小杨互联网2 小时前
你的旧 Kindle 还能用,但平台说它该退休了
大数据·经验分享·科技·ai
泰迪智能科技2 小时前
高校人工智能与大数据产品体系及解决方案介绍
大数据·人工智能
沪漂阿龙2 小时前
面试题详解:Agent 记忆管理全解析——历史对话获取、摘要记忆、事实记忆、知识图谱记忆一次讲透
大数据·人工智能·知识图谱
逸Y 仙X2 小时前
文章三十一:ElasticSearch 管道聚合
java·大数据·elasticsearch·搜索引擎·全文检索
纽格立科技3 小时前
AI让广播过时,还是让广播稀缺?
大数据·服务器·人工智能·车载系统·信息与通信·传媒
一切皆是因缘际会3 小时前
AI工程化落地指南:
大数据·人工智能·机器学习·架构
闲人编程4 小时前
Agent的评估体系(AgentEval):如何判断一个Agent好坏?
大数据·人工智能·python·算法·agent·智能体·swe
hnult4 小时前
知识竞赛考试平台怎么选?2026 考试云全功能选型与实践指南
大数据·人工智能