热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

昨天的一个问题及答案(关键字Gzip、MapReduce、Spark)

点击上方蓝色字体,选择“设为星标”回复”面试“获取更多惊喜问题是这样的:HDFS上存储了一个大小10G不可分割压缩格式的文件(gzip格式)࿰

点击上方蓝色字体,选择“设为星标”

回复”面试“获取更多惊喜

e81675c4d85b64dc6b381574d24d7489.png

问题是这样的:

HDFS上存储了一个大小10G不可分割压缩格式的文件(gzip格式),当有一个mr任务去读取这个文件的时候会产生多少个map task?spark去读取这种不可分割格式的大文件时是怎么处理的呢?

关于这个问题,大家应该都看过这个:

Hadoop所支持的几种压缩格式

gzip文件最大的特点在于:不可分割。

OK,我们知道gzip不可分割了。那么一个10G的gzip文件在HDFS是怎么存储的呢?

首先,一个10G的gzip文件在HDFS是放在一个DataNode上,但是blocks=ceil(10G/128M),副本还是3份(hadoop2.0 默认),因为gzip不可分割。

意思就是,这个gzip文件会被存储在一个DataNode上,但是占用的block数量还是 10G/每个block的大小(假设是128M),并且向上取整。

其次,MapReduce在读gzip文件的时候要指定解压方法,就是GzipCodec。然后用InputStream方法去读,MapTask的个数和读取一般文件的个数是一样的。

关于Hadoop Maptask个数,有一个计算公式。代码逻辑和计算公式如下:

作业从JobClient端的submitJobInternal()方法提交作业的同时,调用InputFormat接口的getSplits()方法来创建split。默认是使用InputFormat的子类FileInputFormat来计算分片,而split的默认实现为FileSplit(其父接口为InputSplit)。这里要注意,split只是逻辑上的概念,并不对文件做实际的切分。一个split记录了一个Map Task要处理的文件区间,所以分片要记录其对应的文件偏移量以及长度等。每个split由一个Map Task来处理,所以有多少split,就有多少Map Task。下面着重分析这个方法:

public List getSplits(JobContext job) throws IOException {//getFormatMinSplitSize():始终返回1//getMinSplitSize(job):获取” mapred.min.split.size”的值,默认为1long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));//getMaxSplitSize(job):获取"mapred.max.split.size"的值,//默认配置文件中并没有这一项,所以其默认值为” Long.MAX_VALUE”,即2^63 – 1long maxSize = getMaxSplitSize(job);// generate splitsList splits = new ArrayList();Listfiles = listStatus(job);for (FileStatus file: files) {Path path = file.getPath();FileSystem fs = path.getFileSystem(job.getConfiguration());long length = file.getLen();BlockLocation[] blkLocations = fs.getFileBlockLocations(file, 0, length);if ((length != 0) && isSplitable(job, path)) {long blockSize = file.getBlockSize();//计算split大小long splitSize = computeSplitSize(blockSize, minSize, maxSize);//计算split个数long bytesRemaining = length;    //bytesRemaining表示剩余字节数while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) { //SPLIT_SLOP=1.1int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);splits.add(new FileSplit(path, length-bytesRemaining, splitSize,blkLocations[blkIndex].getHosts()));bytesRemaining -= splitSize;}if (bytesRemaining != 0) {splits.add(new FileSplit(path, length-bytesRemaining, bytesRemaining,blkLocations[blkLocations.length-1].getHosts()));}} else if (length != 0) {splits.add(new FileSplit(path, 0, length, blkLocations[0].getHosts()));} else {//Create empty hosts array for zero length filessplits.add(new FileSplit(path, 0, length, new String[0]));}}// Save the number of input files in the job-confjob.getConfiguration().setLong(NUM_INPUT_FILES, files.size());LOG.debug("Total # of splits: " + splits.size());return splits;}

首先计算分片的下限和上限:minSize和maxSize,具体的过程在注释中已经说清楚了。接下来用这两个值再加上blockSize来计算实际的split大小,过程也很简单,具体代码如下:

protected long computeSplitSize(long blockSize, long minSize, long maxSize) {return Math.max(minSize, Math.min(maxSize, blockSize));
}

接下来就是计算实际的分片个数了。针对每个输入文件,计算input split的个数。while循环的含义如下:

  • 文件剩余字节数/splitSize > 1.1,创建一个split,这个split的字节数=splitSize,文件剩余字节数=文件大小 - splitSize;

  • 文件剩余字节数/splitSize <1.1&#xff0c;剩余的部分全都作为一个split(这主要是考虑到&#xff0c;不用为剩余的很少的字节数一些启动一个Map Task)

我们发现&#xff0c;在默认配置下&#xff0c;split大小和block大小是相同的。这是不是为了防止这种情况&#xff1a;

一个split如果对应的多个block&#xff0c;若这些block大多不在本地&#xff0c;则会降低Map Task的本地性&#xff0c;降低效率。到这里split的划分就介绍完了&#xff0c;但是有两个问题需要考虑&#xff1a;

  1. 如果一个record跨越了两个block该怎么办&#xff1f;

这个可以看到&#xff0c;在Map Task读取block的时候&#xff0c;每次是读取一行的&#xff0c;如果发现块的开头不是上一个文件的结束&#xff0c;那么抛弃第一条record&#xff0c;因为这个record会被上一个block对应的Map Task来处理。那么&#xff0c;第二个问题来了&#xff1a;

  1. 上一个block对应的Map Task并没有最后一条完整的record&#xff0c;它又该怎么办&#xff1f;

一般来说&#xff0c;Map Task在读block的时候都会多读后续的几个block&#xff0c;以处理上面的这种情况。

最后&#xff0c;Spark在读取gzip这种不可分割文件的时候&#xff0c;就退化成从单个task读取、单个core执行任务&#xff0c;很容易产生性能瓶颈。你可以做个测试。在spark的页面上可以看到效果。

基于以上所以&#xff0c;gzip格式最好提前进行分割成小文件或者换格式&#xff0c;因多个文件可以并行读取。另一个办法是read文件后调用repartition操作强制将读取多数据重新均匀分配到不同的executor上&#xff0c;但这个操作会导致大量单节点性能占用&#xff0c;因此该格式建议不在spark上使用。

gzip问题这么多&#xff0c;常用的场景我能想到的只有一个&#xff0c;就是每天的日志文件。单个日志文件不太大&#xff0c;百兆以内。其他的场景暂时想不到。

03d87a1b6205701a48b36db1b9b60780.png

八千里路云和月 | 从零到大数据专家学习路径指南

我们在学习Flink的时候&#xff0c;到底在学习什么&#xff1f;

193篇文章暴揍Flink&#xff0c;这个合集你需要关注一下

Flink生产环境TOP难题与优化&#xff0c;阿里巴巴藏经阁YYDS

Flink CDC我吃定了耶稣也留不住他&#xff01;| Flink CDC线上问题小盘点

我们在学习Spark的时候&#xff0c;到底在学习什么&#xff1f;

在所有Spark模块中&#xff0c;我愿称SparkSQL为最强&#xff01;

硬刚Hive | 4万字基础调优面试小总结

数据治理方法论和实践小百科全书

标签体系下的用户画像建设小指南

4万字长文 | ClickHouse基础&实践&调优全视角解析

【面试&个人成长】2021年过半&#xff0c;社招和校招的经验之谈

大数据方向另一个十年开启 |《硬刚系列》第一版完结

我写过的关于成长/面试/职场进阶的文章

当我们在学习Hive的时候在学习什么&#xff1f;「硬刚Hive续集」

你好&#xff0c;我是王知无&#xff0c;一个大数据领域的硬核原创作者。

做过后端架构、数据中间件、数据平台&架构、算法工程化。

专注大数据领域实时动态&技术提升&个人成长&职场进阶&#xff0c;欢迎关注。



推荐阅读
  • oracle c3p0 dword 60,web_day10 dbcp c3p0 dbutils
    createdatabasemydbcharactersetutf8;alertdatabasemydbcharactersetutf8;1.自定义连接池为了不去经常创建连接和释放 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 在分析Android的Audio系统时,我们对mpAudioPolicy->get_input进行了详细探讨,发现其背后涉及的机制相当复杂。本文将详细介绍这一过程及其背后的实现细节。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 字节流(InputStream和OutputStream),字节流读写文件,字节流的缓冲区,字节缓冲流
    字节流抽象类InputStream和OutputStream是字节流的顶级父类所有的字节输入流都继承自InputStream,所有的输出流都继承子OutputStreamInput ... [详细]
  • 在PHP中如何正确调用JavaScript变量及定义PHP变量的方法详解 ... [详细]
  • Flowable 流程图路径与节点展示:已执行节点高亮红色标记,增强可视化效果
    在Flowable流程图中,通常仅显示当前节点,而路径则需自行获取。特别是在多次驳回的情况下,节点可能会出现混乱。本文重点探讨了如何准确地展示流程图效果,包括已结束的流程和正在执行的流程。具体实现方法包括生成带有高亮红色标记的图片,以增强可视化效果,确保用户能够清晰地了解每个节点的状态。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 【问题】在Android开发中,当为EditText添加TextWatcher并实现onTextChanged方法时,会遇到一个问题:即使只对EditText进行一次修改(例如使用删除键删除一个字符),该方法也会被频繁触发。这不仅影响性能,还可能导致逻辑错误。本文将探讨这一问题的原因,并提供有效的解决方案,包括使用Handler或计时器来限制方法的调用频率,以及通过自定义TextWatcher来优化事件处理,从而提高应用的稳定性和用户体验。 ... [详细]
  • 本文详细解析了 Android 系统启动过程中的核心文件 `init.c`,探讨了其在系统初始化阶段的关键作用。通过对 `init.c` 的源代码进行深入分析,揭示了其如何管理进程、解析配置文件以及执行系统启动脚本。此外,文章还介绍了 `init` 进程的生命周期及其与内核的交互方式,为开发者提供了深入了解 Android 启动机制的宝贵资料。 ... [详细]
  • 在《ChartData类详解》一文中,我们将深入探讨 MPAndroidChart 中的 ChartData 类。本文将详细介绍如何设置图表颜色(Setting Colors)以及如何格式化数据值(Formatting Data Values),通过 ValueFormatter 的使用来提升图表的可读性和美观度。此外,我们还将介绍一些高级配置选项,帮助开发者更好地定制和优化图表展示效果。 ... [详细]
  • Spring框架中枚举参数的正确使用方法与技巧
    本文详细阐述了在Spring Boot框架中正确使用枚举参数的方法与技巧,旨在帮助开发者更高效地掌握和应用枚举类型的数据传递,适合对Spring Boot感兴趣的读者深入学习。 ... [详细]
  • 本文深入解析了WCF Binding模型中的绑定元素,详细介绍了信道、信道管理器、信道监听器和信道工厂的概念与作用。从对象创建的角度来看,信道管理器负责信道的生成。具体而言,客户端的信道通过信道工厂进行实例化,而服务端则通过信道监听器来接收请求。文章还探讨了这些组件之间的交互机制及其在WCF通信中的重要性。 ... [详细]
author-avatar
wang-zhiwen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有