大数据之sqoop:sqoop-import 并行抽数原理及数据倾斜解决方案

前言:

我们一般用sqoop抽取数据,可是有时由于单表数据量太大(每天千万级别)导致sqoop抽数使用单实例报内存溢出以及抽数时间过长,这时我们该怎么办?现总结方法如下供借鉴。

一.sqoop参数

示例:

/opt/module/sqoop/bin/sqoop import \
--connect \
--username \
--password \
--target-dir \
--delete-target-dir \
--fields-terminated-by \
--query "$2" and $CONDITIONS
--mum-mappers \
--null-string "\\N" \
--null-non-string "\\N" \
--split-by 

二.并行化

sqoop 抽数的并行化主要涉及到两个参数:num-mappers:启动N个map来并行导入数据,默认4个;split-by:按照某一列来切分表的工作单元。
具体原理:
Sqoop在import时,需要制定split-by参数。Sqoop根据不同的split-by参数值来进行切分,然后将切分出来的区域分配到不同map中。每个map中再处理数据库中获取的一行一行的值,写入到HDFS中。同时split-by根据不同的参数类型有不同的切分方法,如比较简单的int型,Sqoop会取最大和最小split-by字段值,然后根据传入的num-mappers来确定划分几个区域。比如select max(split_by),min(split-by) from得到的max(split-by)和min(split-by)分别为1000和1,而num-mappers为2的话,则会分成两个区域(1,500)和(501-1000),同时也会分成2个sql给2个map去进行导入操作,分别为select XXX from table where split-by>=1 and split-by<500和select XXX from table where split-by>=501 and split-by<=1000。最后每个map各自获取各自SQL中的数据进行导入工作。
--query "$2" and $CONDITIONS中,$CONDITIONS 到底是干什么用的呢?其实它的作用是数据分割条件的占位符,也就是说最终数据查询语句中的$CONDITIONS 会被split-by>=501 and split-by<=1000 这样的分割条件替换。
在这里插入图片描述
我们通过num-mappers 参数控制并行度,split-by参数控制数据分割字段,就可以做到抽数并行化。

三.数据倾斜是怎么产生的?

数据倾斜是啥呢?在说数据倾斜之前,我们设想数据并行抽数最理想的情况就是所有的并行实例同时完成,木桶原理,数据抽数时间的长短取决于耗时最长的那个实例。由于各个实例被分配的数据量不均而导致分配到数据量较少的实例早早完成,而被分配大量数据的实例迟迟无法完成,导致整个作业运行时间很长的现象就是数据倾斜导致的。数据倾斜概括为一句话:数据分配不均。
那它是如何产生的呢?
阐述下切分策略对int类型的切分机制。在指定好int的split-by 字段后(这里用id代替,注意这里的id就是一个普通的int 字段,不是大家想的数据主键id)如果不设定–boundary-query 参数,默认使用(select MIN(id) , MAX(id) FROM table)确定数据的上下界,确定总体数量 除以num-mappers 确定每个实例数据量

例如:MIN(id) =100 MAX(id)=500 num-mappers 为 4

select * from table where id >= 100 and id < 200;

select * from table where id >= 200 and id < 300;

select * from table where id >= 300 and id < 400;

select * from table where id >= 400 and id <= 500;
如果id数据分布不均及id重复同样会出现数据倾斜,例如:100到200有10条数据,400到500有10000条数据。

从此得出结论想要避免数据倾斜,对split-by指定字段的要求是 int类型同时数据分布均匀。

四.解决方案:

方案一:提高并行度,尽量不要用全量的方式导入,采集增量,新增或变化导入,减少导入数据量
补充:sqoop import 抽数查询愿数据的时候主要有两者方式:
–table 方式:全量数据抽取
–query 方式:增加检索条件部分数据抽数,当然也可以where 1=1 进行全量操作
我们可以用sqoop,以–query的方式导入新增数据,如果要求是全量可以full join 上一天的数据;
如:

select
nvl(new.id,old.id),
......
from (
select * from ods_user_info where dt=2021-06-05)old
full outer join
user_info_inc new
on old.id = new.id 

方案二: 换一个–split-by字段,一般来说,我们可以用update_time;
如:

--query "select use_id,user_name,sex,id_card,create_time,updated_time from finc.user_info where updated_time >=2021-06-06 00:00:00 and updated_time <=2021-06-07 00:00:00"  and $CONDITIONS
--split-by updated_time \
--mum-mappers 6

方案三:使用–query 方式,对查询到数据进行编号,最后–split-by选用编号的字段

--query "select use_id,user_name,sex,id_card,create_time,updated_time from (select f.* ,row_number() over() as rank from finc.user_info f where updated_time >=2021-06-06 00:00:00 and updated_time <=2021-06-07 00:00:00)m"  where $CONDITIONS
--split-by rank \
--mum-mappers 6

总结

综上:我们解决数据倾斜的方法推荐使用第三种,把数据排序,然后–split-by选用排序的字段,可以完美解决问题。

参考:https://blog.csdn.net/lizhiguo18/article/details/103969906

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值