共计 832 个字符,预计需要花费 3 分钟才能阅读完成。
这周做了一个数据分析,自己也有一段时间没有写spark代码了,一些性能优化的点都忘记差不多了,也可以说对这个还是没有深刻的理解导致的。具体的问题对一批数据聚合,key本身数量还是不多的,只有几千个,但是聚合报错了,核心报错是
Container killed by the ApplicationMaster Exit code is 143
查看原因在于Memory这块分配问题,试着加大executor memory 和 driver 端端,以及java heap space 内存到10g+ 最后勉强可以跑一下,但是这个的确不是最优的,这个设置实太大了,程序本身是有问题的。
ok,回头去看数据,其中一个环节就是groupbykey的操作,实现数据聚合,那么如果一个key 包含几亿的数据,那么聚合在一起就有可能 oom 的问题。现在的问题就在这里,如何优化这个,其实到这一块谷歌搜索一下也能找到答案了。
如果继续看那我就多说几句关于这个优化相关的理论。map-side预聚合闪亮登场。
map-side 预聚合,说的是在每个节点本地对相同的key进行一次聚合操作,类似于MapReduce中的本地combiner。 map-side预聚合之后,每个节点本地就只会有一条相同的key,因为多条相同的key都被聚合起来了。其他节点在拉取所有节点上的相同key时,就 会大大减少需要拉取的数据数量,从而也就减少了磁盘IO以及网络传输开销。
为了说明 map-side预聚合,先看下没有聚合的怎么做的
以上操作问题很大,出现大量的shuffe ,网络io会导致很慢,还有一个问题,在一个进程里某一个key 积累了大量的数据导致oom。这个只有在数据量很大的时候才会有明显的问题,数据少还是感知不到的。
接下来隆重出场的是map-side聚合的操作过程
通过预聚合数据量会急速减少,这样在进行二次聚合的时候数据量很少,速度就更快了。
接下来就直接给结论了:使用reduceByKey/aggregateByKey 替代 groupByKey