当前位置: 首页 > article >正文

Spark UI中Shuffle dataSize 和shuffle bytes written 指标区别

背景

本文基于Spark 3.1.1
目前在做一些知识回顾的时候,发现了一些很有意思的事情,就是Spark UI中ShuffleExchangeExec 的dataSize和shuffle bytes written指标是不一样的,
那么在AQE阶段的时候,是以哪个指标来作为每个Task分区大小的参考呢

结论

先说结论 dataSzie指标是 是存在内存中的UnsafeRow 的大小的总和,AQE阶段(规则OptimizeSkewedJoin/CoalesceShufflePartitions)用到判断分区是否倾斜或者合并分区的依据是来自于这个值,
shuffle bytes written指的是写入文件的字节数,会区分压缩和非压缩,如果在开启了压缩(也就是spark.shuffle.compress true)和未开启压缩的情况下,该值的大小是不一样的。
开启压缩如下:
在这里插入图片描述
未开启压缩如下:
在这里插入图片描述

先说杂谈

这两个指标的值都在 ShuffleExchangeExec中:

case class ShuffleExchangeExec(
    override val outputPartitioning: Partitioning,
    child: SparkPlan,
    shuffleOrigin: ShuffleOrigin = ENSURE_REQUIREMENTS)
  extends ShuffleExchangeLike {

  private lazy val writeMetrics =
    SQLShuffleWriteMetricsReporter.createShuffleWriteMetrics(sparkContext)
  private[sql] lazy val readMetrics =
    SQLShuffleReadMetricsReporter.createShuffleReadMetrics(sparkContext)
  override lazy val metrics = Map(
    "dataSize" -> SQLMetrics.createSizeMetric(sparkContext, "data size")
  ) ++ readMetrics ++ writeMetrics

dataSize指标来自于哪里

涉及到datasize的数据流是怎么样的如下,一切还是得从ShuffleMapTask这个shuffle的起始操作讲起:

ShuffleMapTask
   ||
   \/
runTask
   ||
   \/
dep.shuffleWriterProcessor.write //这里的shuffleWriterProcessor是来自于 ShuffleExchangeExec中的createShuffleWriteProcessor
   ||
   \/
writer.write()  //这里是writer 是 UnsafeShuffleWriter类型的实例
   ||
   \/
insertRecordIntoSorter
   ||
   \/
UnsafeRowSerializerInstance.writeValue
   ||
   \/
dataSize.add(row.getSizeInBytes)

这里的 rowUnsafeRow的实例,这样就获取到了实际内存中的每个分区的大小,
而ShuffleMapTask runTask 方法最终返回的是MapStatus,而该MapStatus最终是在UnsafeShuffleWriter的closeAndWriteOutput方法中被赋值的:

void closeAndWriteOutput() throws IOException {
    assert(sorter != null);
    updatePeakMemoryUsed();
    serBuffer = null;
    serOutputStream = null;
    final SpillInfo[] spills = sorter.closeAndGetSpills();
    sorter = null;
    final long[] partitionLengths;
    try {
      partitionLengths = mergeSpills(spills);
    } finally {
      for (SpillInfo spill : spills) {
        if (spill.file.exists() && !spill.file.delete()) {
          logger.error("Error while deleting spill file {}", spill.file.getPath());
        }
      }
    }
    mapStatus = MapStatus$.MODULE$.apply(
      blockManager.shuffleServerId(), partitionLengths, mapId);
  }

shuffle bytes written指标来自哪里

基本流程和dataSize 一样,还是来自于ShuffleMapTask

ShuffleMapTask
   ||
   \/
runTask
   ||
   \/
dep.shuffleWriterProcessor.write //这里的shuffleWriterProcessor是来自于 ShuffleExchangeExec中的createShuffleWriteProcessor
   ||
   \/
writer.write()  //这里是writer 是 UnsafeShuffleWriter类型的实例
   ||
   \/
closeAndWriteOutput
   ||
   \/
sorter.closeAndGetSpills() ->  writeSortedFile -> writer.commitAndGet -> writeMetrics.incBytesWritten(committedPosition - reportedPosition) -> serializerManager.wrapStream(blockId, mcs) // 这里进行了压缩
   ||
   \/
mergeSpills
   ||
   \/
mergeSpillsUsingStandardWriter
   ||
   \/
mergeSpillsWithFileStream -> writeMetrics.incBytesWritten(numBytesWritten)
   ||
   \/
writeMetrics.decBytesWritten(spills[spills.length - 1].file.length())


http://www.kler.cn/a/106749.html

相关文章:

  • flink实战 -- flink SQL 实现列转行
  • 问:SQL优化,七条实践总结?
  • 前端学习八股资料CSS(二)
  • 从python源码到可自动更新软件
  • 基于yolov8、yolov5的鱼类检测识别系统(含UI界面、训练好的模型、Python代码、数据集)
  • 实验5:网络设备发现、管理和维护
  • Go实现MapReduce
  • RPA除了和OCR、NLP技术结合,还能和什么技术结合?
  • 39.B树,B+树(王道第7章查找补充知识)
  • APP自动化测试 ---- Appium介绍及运行原理
  • 刷题笔记day02-数组快慢指针
  • Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (三)
  • Hbase基本使用,读写原理,性能优化学习
  • 纵行科技携ZETA亮相世界物联网博览会,助力全球物联网生态合作
  • vue3 项目搭建教程整理
  • 前端 JS 经典:宏任务、微任务、事件循环(EventLoop)
  • 数据结构与算法之矩阵: Leetcode 48. 旋转矩阵 (Typescript版)
  • 计算机网络-应用层(3)
  • Docker Nginx安装使用以及踩坑点总结
  • GCC、g++、gcc的关系
  • 第13期 | GPTSecurity周报
  • p5.js 渐变填充的实现方式
  • yarn install 这个命令安装如何加速
  • 手把手教你通过 AGP + ASM 实现 Android 应用插桩
  • STM32 TIM(四)编码器接口
  • 【Gan教程 】 什么是变分自动编码器VAE?