spark中的shuffle简述 那些会导致shuffle的算子

shuffle操作说白了就是重分区操作

在Apache Spark中,任务之间的依赖关系主要分为两类:宽依赖(Wide Dependency)和窄依赖(Narrow Dependency)。这两者之间的主要区别在于它们对任务之间数据的依赖性以及执行方式的不同。

窄依赖意味着任务可以在内存中的管道上迭代并行运行,而不需要等待前一阶段的运行结果。相比之下,宽依赖涉及到shuffle操作,需要等待上一阶段的运行结果才能继续执行程序。

理解和掌握宽窄依赖对于优化Spark作业的性能至关重要。**在设计Spark作业时,尽量使用窄依赖,以减少Shuffle的开销。**通过合理的分区策略和选择适当的转换操作,可以有效地减少宽依赖的出现。

那么现在让我们来介绍一下spark中那些会导致shuffle的算子:

🧨

1、**repartition类的操作:**比如repartition、repartitionAndSortWithinPartitions、coalesce等

重分区: 一般会shuffle,因为需要在整个集群中,对之前所有的分区的数据进行随机,均匀的打乱,然后把数据放入下游新的指定数量的分区内

2、**byKey类的操作:**比如reduceByKey、groupByKey、sortByKey等

byKey类的操作:因为你要对一个key,进行聚合操作,那么肯定要保证集群中,所有节点上的,相同的key,一定是到同一个节点上进行处理

3、**join类的操作:**比如join、cogroup等join类的操作:两个rdd进行join,就必须将相同join key的数据,shuffle到同一个节点上,然后进行相同key的两个rdd数据的笛卡尔乘积

理解了上述内容,现在让我们来上机实践一下:

这里我们使用 toDebugString() 这个方法 返回该RDD及其用于调试的递归依赖项的描述。

代码如下 这里我们先用repartition算子举例:

python 复制代码
from pyspark import SparkContext

#  repartition 算子
data = [2, 3, 1, 4, 5, 6, 7, 8, 9, 10]
rdd = sc.parallelize(data, 3)
repartitioned_rdd = rdd.repartition(5)
print(repartitioned_rdd.glom().collect())
print(repartitioned_rdd.toDebugString().decode())

我们来看看运行结果:

可以发现这段程序经历了shuffle

现在让我们将上述算子都运行一下,看看是否都经历了shuffle

代码如下,各位读者可自行实验:

python 复制代码
from pyspark import SparkContext

sc = SparkContext("local", "apple1")

# 那些会导致shuffle的算子

# =======================================================================================

# 1、分区类算子
# TODO
#  repartition 算子
data = [2, 3, 1, 4, 5, 6, 7, 8, 9, 10]
rdd = sc.parallelize(data, 3)
repartitioned_rdd = rdd.repartition(5)
print(repartitioned_rdd.glom().collect())
print(repartitioned_rdd.toDebugString().decode())

# TODO
#  repartitionAndSortWithinPartitions 它会在每个分区内对数据进行排序 分区先排序 提高性能嘛
# data = [(1, "apple"), (6, "banana"), (3, "banana"),  (2, "orange"), (4, "grape")]
# rdd = sc.parallelize(data, 2)  # 创建一个有2个分区的键值对RDD
#
# repartitioned_sorted_rdd = rdd.repartitionAndSortWithinPartitions(numPartitions=2)
# # print(repartitioned_sorted_rdd.glom().collect())
# print(repartitioned_sorted_rdd.toDebugString().decode())

# TODO
#  coalesce 减少分区 可以设置是否进行shuffle
# data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# rdd = sc.parallelize(data, 5)  # 创建一个有5个分区的RDD
#
# coalesced_rdd = rdd.coalesce(2, shuffle=True)  # 将RDD合并到2个分区
# # print(coalesced_rdd.glom().collect())
# print(coalesced_rdd.toDebugString().decode())

# =======================================================================================

# TODO
#  reduceByKey
# data = ["apple", "banana", "orange", "banana", "grape", "apple", "orange"]
# rdd = sc.parallelize(data)
# rdd = rdd.map(lambda x: (x, 1))
# rdd2 = rdd.reduceByKey(lambda x, y: x+y)
# # print(rdd2.collect())
# print(rdd2.toDebugString().decode() + '\n')

# TODO
#  groupByKey
# rdd3 = rdd.groupByKey()
# print(rdd3.toDebugString().decode() + '\n')

# TODO
#  sortByKey 当分区大于1时才有shuffle 因为sortbykey涉及重分区 按照key分组 然后排序
# 如果 RDD 使用了默认的分区器(即 HashPartitioner),并且你要求对 key 进行排序,那么就会发生 shuffle。
# 这是因为默认情况下,HashPartitioner 使用 key 的 hash 值来确定数据所在的分区,
# 这可能导致相同 key 的数据散布在不同的分区中,而进行排序时需要将相同 key 的数据聚合在一起。
# rdd = sc.parallelize(data, 2)
#
# rdd = rdd.map(lambda x: (x, 1))
# print(rdd.glom().collect())
#
# rdd4 = rdd.sortByKey()
# print(rdd4.glom().collect())
# print(rdd4.toDebugString().decode() + '\n')

# =======================================================================================

# TODO
#  join 操作
# rdd1 = sc.parallelize([(1, "apple"), (2, "banana"), (3, "orange")])
# rdd2 = sc.parallelize([(1, 5), (2, 3), (3, 8), (1, 6)])
#
# joined_rdd = rdd1.join(rdd2)
# # print(joined_rdd.collect())
# print(joined_rdd.toDebugString().decode() + '\n')


# TODO
#  cogroup
# rdd1 = sc.parallelize([(1, "apple"), (2, "banana"), (3, "orange")])
# rdd2 = sc.parallelize([(1, 5), (2, 3), (3, 8), (1, 9)])
#
# cogrouped_rdd = rdd1.cogroup(rdd2)
# result = cogrouped_rdd.collect()
# # map 函数: map 是 Python 内置函数,用于对一个可迭代对象的每个元素应用一个指定的函数。在这里,map 的目标是 list 函数。
# # list 函数: list 是 Python 内置函数,用于将一个可迭代对象转换为列表。
# for k, v in result:
#     print(k, tuple(map(list, v)))
# print(cogrouped_rdd.toDebugString().decode() + '\n')
相关推荐
Elastic 中国社区官方博客24 分钟前
如何将数据从 AWS S3 导入到 Elastic Cloud - 第 3 部分:Elastic S3 连接器
大数据·elasticsearch·搜索引擎·云计算·全文检索·可用性测试·aws
Aloudata1 小时前
从Apache Atlas到Aloudata BIG,数据血缘解析有何改变?
大数据·apache·数据血缘·主动元数据·数据链路
不能再留遗憾了1 小时前
RabbitMQ 高级特性——消息分发
分布式·rabbitmq·ruby
水豚AI课代表2 小时前
分析报告、调研报告、工作方案等的提示词
大数据·人工智能·学习·chatgpt·aigc
茶馆大橘2 小时前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud
材料苦逼不会梦到计算机白富美4 小时前
golang分布式缓存项目 Day 1
分布式·缓存·golang
拓端研究室TRL5 小时前
【梯度提升专题】XGBoost、Adaboost、CatBoost预测合集:抗乳腺癌药物优化、信贷风控、比特币应用|附数据代码...
大数据
黄焖鸡能干四碗5 小时前
信息化运维方案,实施方案,开发方案,信息中心安全运维资料(软件资料word)
大数据·人工智能·软件需求·设计规范·规格说明书
想进大厂的小王5 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
Java 第一深情5 小时前
高性能分布式缓存Redis-数据管理与性能提升之道
redis·分布式·缓存