Spark学习之路 (十七)Spark分区
《2021年度全新发布大数据面试题集全面升级》
请关注 GitHub 项目《数据时代开挂人生》:[God Of Big Data](https://github.com/wangzhiwubigdata/God Of Big Data)
目录
一、关于分区的定义
二、探讨分区的目的
三、Spark的分区原则与实现方法
3.1 本地模式下的处理策略
3.2 基于YARN的处理策略
四、分块器
正文
一、分区的概念
在RDD内部并行计算中占据重要地位的是一个叫做‘分区’的计算单元。该数据集被划分为多个子集(分片),每个子集被称为‘分区’。具体划分方式直接影响着并行处理 granularity(粒度)。在任务分解的过程中涉及最后一个 RDD 的划分数量将直接决定最终的任务总数。
二、为什么要进行分区
在分布式集群环境中实施数据分区策略时需要注意的是:尽管分布式架构通常具有高可用性和容错能力等优势特性但它也会带来较高的维护成本尤其是针对大规模应用系统而言这种成本可能变得难以承受。因此合理规划系统架构以最大限度地降低资源浪费就显得尤为重要。
MapReduce框架的主要性能消耗源于I/O操作和数据传输环节其中I/O操作由于需要频繁读取和写入文件而产生无法避免的成本但数据传输环节是可以优化的部分通过将大数据块进行压缩编码以减少其体积从而降低数据传输需求然而这会增加CPU处理负担。
Spark 里面io也是不可避免的,但是网络传输spark里面进行了优化:
Spark系统将rdd划分为多个子集(分片),并在集群上实现并行处理以提高效率。一个rdd被划分为100个子集,在10个节点上运行时,默认情况下每个节点负责10个子集的处理任务。对于sum类型的运算而言,在每个子集内部先执行求和运算后将结果传递给主节点完成最终汇总;而针对join类型的运算,则必须对数据进行重新排列以实现关联性,在此过程中会产生较大的通信开销导致较高的通信成本。
spark是如何优化这个问题的呢?
Spark基于key的哈希值对rdd进行分区操作,并通过这种方式确保相同键值项被分配到同一计算节点上。这样一来,在对rdd执行key聚合操作时就无需执行洗牌操作(Shuffle),这也是为何在MapReduce运算过程中需要进行洗牌操作的原因所在:洗牌过程是MapReduce算法中网络传输量最大的阶段。根本原因在于相同的键值项分布在不同的计算节点上,在按键进行聚合时必然需要将这些数据混合传输至网络中。洗牌过程对于网络性能有着至关重要的影响:它将所有的数据混合传输至网络后才能实现相同键值项的聚合并完成高效的计算任务。洗牌操作的根本目的是为了满足存储架构决定的数据处理需求。
在一次实验过程中遇到了一个问题:当处理大量数据时(尤其是超过一定阈值的数据),程序运行变得非常缓慢甚至崩溃。经过深入分析发现:该现象的根本原因在于内存不足导致程序无法完成关键操作(如内存溢出)。于是我们采取了以下措施:首先优化算法以减少内存占用;其次改进缓存策略;最后引入磁盘缓存机制以延长程序运行时间并提升整体性能。
由于key的分布不均衡,在某些分区中键的数量会显著多于其他分区。无法通过精确分区来保证所有区间的键数量完全一致,从而在一定程度上确保各区间键的数量保持相对接近。因此,在MapReduce框架中执行的一些特定操作中,当数据被划分到不同节点时,在这种情况下Spark就不需要进行数据重排。这正是Spark在处理网络传输问题时的核心原理所在。
在执行join操作时(即连接操作),由于两张数据源之间无法实现完全的有效分片策略(即分片优化),因此通常的做法是优先对使用频率较高的那张大表实施分片处理;而对于较小的数据源,则会在与大表关联时完成数据的重新洗牌(或称为shuffling)过程。
大表不需要shuffle。
不同工作节点间的数据混合处理能够得益于分区机制的优化
分区是可配置的,只要RDD是基于键值对的即可 。
三、Spark分区原则及方法
RDD分区的一个分区原则:尽可能是得分区的个数等于集群核心数目
采用本地模式、Standalone模式、YARN模式或Mesos模态中的任意一种方式部署应用时,默认分区个数可通过 spark.default.parallelism参数进行配置。若未指定该参数,则系统会根据实际集群环境自动确定默认值。
3.1 本地模式
(1)默认方式
以下这种默认方式就一个分区

结果

(2)手动设置
设置了几个分区就是几个分区

结果

(3)跟local[n] 有关
n等于几默认就是几个分区
如果n=* 那么分区个数就等于cpu core的个数

结果

本机电脑查看cpu core,我的电脑--》右键管理--》设备管理器--》处理器

(4)参数控制

结果

3.2 YARN模式

进入defaultParallelism方法

继续进入defaultParallelism方法

这个一个trait,其实现类是(Ctrl+h)

进入TaskSchedulerImpl类找到defaultParallelism方法

继续进入defaultParallelism方法,又是一个trait,看其实现类

Ctrl+h看SchedulerBackend类的实现类

进入CoarseGrainedSchedulerBackend找到defaultParallelism

totalCoreCount.get()是所有executor使用的core总数,和2比较去较大值
如果正常的情况下,那你设置了多少就是多少
四、分区器
如果是采用HDFS作为数据源进行读取,则无需配置额外的分区器;由于HDFS系统内部已经实现了数据的预先划分好区块。
分区数我们是可以控制的,但是没必要有分区器。
(2)非key-value RDD分区,没必要设置分区器
**没必要设置,但是非要设置也行。**
(3)Key-value形式的时候,我们就有必要了。
HashPartitioner
RangePartitioner
**注:按照范围进行分区的,如果是字符串,那么就按字典顺序的范围划分。如果是数字,就按数据自的范围划分**
自定义分区
需要实现2个方法
