导读:数据倾斜在大数据任务中十分常见,用最通俗易懂的话来说,数据倾斜无非就是大量的相同或取模相同的key被partition分配到一个分区里,造成了'一个人累死,其他人闲死'的情况,这种情况是我们不能接受的,这也违背了并行计算的初衷,首先一个节点要承受着巨大的压力,而其他节点计算完毕后要一直等待这个忙碌的节点,也拖累了整体的计算时间,可以说效率是十分低下的。
本系列文章,模拟数据倾斜场景,探索数据倾斜解决方案。
本文经授权转自公众号DLab数据实验室
作者 | 小舰
出品 | DLab数据实验室(ID:rucdlab)
01
数据准备
1.1准备数据
首先准备一份数据,导入hive表中,类似下表,当然也可以创建一个外表,总之,准备一份足量数据:(以下表只用于描述过程,大家可以根据自己的表做调整)
CREATE TABLE cyj_tmp(
A int,
B int,
C varchar(10)
)
1.2 新增一个有序的id列
CREATE TABLE cyj_tmp(
id int,
A int,
B int,
C varchar(10)
)
insert into cyj_test
select
row_number() over(partition by 1) as id,
A,
B,
C
from cyj_tmp;
1.3 制造数据倾斜
我的数据总共3亿条左右,但是我用不了这么多,就用了前1.2亿条数据,现在做如下处理:
id为1-1亿的数据不做任何处理;
id为1亿-1.2亿的数据将id进行修改,改为模10余8,也就是,如果以并行度为10的时候,这2000万条数据会倾斜到task8里;
INSERT OVERWRITE TABLE cyj_skew
SELECT
CASE WHEN id > 100000000 THEN (100000008 + (CAST (RAND() * 50 AS INT)) * 10 )
ELSE id
END,
A,
B,
C
FROM cyj_test
WHERE id BETWEEN 0 AND 120000000;
02
数据倾斜调优-提高并发
2.1 进行wordcount任务
def skew(spark: SparkSession, repath:String): Unit = {
val db_name = Config.dbnameval
sql = "select * from cyj_skew "
spark.sql(s"use $db_name")
val dfresult = spark.sql(sql)val rddresult = dfresult.rdd
.map(x=>(x.get(0),1))
.groupByKey(10) //并行度参数 = 10
.mapValues(_.size)
rddresult.saveAsTextFile(repath) }
2.2 查看任务运行
我们可以看到,task8里面确实比其他task多了2000w条数据,发生了数据倾斜(ps:由于我自己数据的原因,实际数据总条数是120773171,后面的若干条数据可以无视)
2.3 修改并发度
def skew(spark: SparkSession, repath:String): Unit = {
val db_name = Config.dbnameval
sql = "select * from cyj_skew "
spark.sql(s"use $db_name")
val dfresult = spark.sql(sql)val rddresult = dfresult.rdd
.map(x=>(x.get(0),1))
.groupByKey(20) //并行度参数 = 20
.mapValues(_.size)
rddresult.saveAsTextFile(repath) }
2.4 查看任务运行
发现数据倾斜得到了改善,虽然task数量变多了,但是每个task的数据量变少了,这如果在数据量很大的情况下,是会缓解某个节点的压力的;
03
总结
调整并发度的方式是改善数据倾斜的一个方法,但是优缺点已经很明显了,他会带来task任务数量的增多。而且,试想一些,如果倾斜的key并不是都不相同,而是都相同,这种方法其实并不能起到作用。那应该怎么解决呢?期待下一期吧~
●Spark训练营(一)-- 开发环境搭建及wordCount实战
●Spark训练营(二)-- SparkStreaming流计算组件wordCount实战
●Spark训练营(三)-- GraphX图计算组件最短路算法实战