在讲他们的性能之前,先分析一下 groupByKey 和 reduceByKey 的操作流程:
groupByKey:
groupByKey 会将相同 key 的数据进行分组,对数据进行打乱重组,存在 shuffle 操作。但不会聚合,所以数据量不会减少。
正常不同分区间的数据是并行执行的,互不影响,但因为有 shuffle 阶段,一个分区数据处理好了之后不可能直接就进行下一步操作,而是要等其他分区都处理好了之后再一起进行聚合,但是数据会放在内存中,当数据量越来越大的时候,可能会导致 OOM 内存溢出的问题。
因为不能在内存中等待数据,所以在 Spark 中,shuffle 操作必须落盘处理,也就是先把处理的数据都放到磁盘文件中,处理好了之后再从磁盘中读取,但这就涉及到了 IO 读取,因为数据量没有减少,数据量又大,所以会导致 shuffle 的性能低下。
reduceByKey:
reduceByKey 会将相同 key 的数据进行分组并聚合,跟 groupByKey 的操作流程一样,都是要进行 shuffle 操作,但 reduceByKey 有一点不同的是,reduceByKey 可以在 shuffle 前对分区内相同 key 的数据进行预聚合(combine)功能,这样会减少落盘的数据量,从而提高性能。
所以,综上所述,groupByKey 和 reduceByKey 的区别:
从 shuffle 的角度:reduceByKey 和 groupByKey 都存在 shuffle 的操作,但是 reduceByKey 可以在 shuffle 前对分区内相同 key 的数据进行预聚合(combine)功能,这样会减少落盘的数据量,而 groupByKey 只是进行分组,不存在数据量减少的问题,reduceByKey 性能比较高。
从功能的角度:reduceByKey 其实包含分组和聚合的功能。groupByKey 只能分组,不能聚合,所以在分组聚合的场景下,推荐使用 reduceByKey,但如果仅仅是分组而不需要聚合,那么还是只能使用 groupByKey。