Sqoop导数据时的数据倾和斜解决办法

1. 当时是怎么发现mapreduce任务出现数据倾斜的?

  • 使用sqoop从oracle导出数据到hive的时候发现,控制台打印的日志卡在了75%,很长时间没有动过,怀疑是出现数据倾斜或者数据量太大。

2. 数据倾斜的确认

  • 于是到Yarn的日志中查看,看到map中仅剩最后一个任务没有跑完,并且其他map任务早早结束(要么是空跑,要么是处理的数据量很少),忙的忙死,闲的闲死。

 3. 为什么会出现数据倾斜

第一个是数据分布的不均匀,如果只有1个map来跑当然不会出现数据分配不均的问题。但是当涉及到多个map任务的时候,势必有数据分配不均的可能,下面先看看sqoop划分map的原理。

map数等于1时可以不指定--split-by,多个map时默认是主键,如果没有主键会报错!

举例:如果是split-by的id字段是一个数字类型,首先sqoop会执行这么一条sql,select min(id), max(id) from table_name  也就是先确定字段的范围,再对这个范围根据map数量划分出等宽的区间(范围是1-1000,如果有4个map,就会分成 1-250,260-500,501-750,751-1000)

如果数据大量分布到其中一个区间时,就会出现数据倾斜。


第二个是当split-by的字段是字符串时,可能出现数据倾斜。因为sqoop的split-by对字符串类型的支持很差,无法进行map划分,可能导致数据都集中在一个map上。 

这里如果非得要用字符串作为划分依据还需要加上下面的参数

-Dorg.apache.sqoop.splitter.allow_text_splitter=true 

4. 出现数据倾斜怎么解决

最容易想到的就是,根据分布较为均匀的字段来划分map,但这需要对原表的数据比较了解。

使用--query参数加上一些小方法解决,比如:

--query select ... from (select rownum as etl_id, t.* from table_name) t1 where $CONDITION

这里做了一个子查询,在原表记录基础上,加上一个行序号(该行序号从1开始),split-by 指定该字段即可解决 !

注意:

1. rownum 一定要起一个别名,不然还是会数据倾斜

2. 还需要加上下面的参数,否则会报 invalid identifier 的错误

--boundary-query "select 1 as MIn, sum(1) as Max from xxx"

因为这个字段在原表不存在,我们自己造出来的

最后跑出来的map处理的数据量都非常平均了~ 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值