sqoop-import 并行抽数及数据倾斜解决

最近在数据中台的数据抽数优化工作,由於单表数据量太大(每天千万级别)导致sqoop抽数使用单实例报内存溢出以及抽数时间过长,决定采用sqoop的多实例并行抽数,参考了一些文档,但同时遇到了一些问题,趁有点时间把遇到问题的解决方法写下来供大家借鉴。 

并行化

sqoop-常用命令及参数:https://www.yuque.com/shanyu-aqvcy/hkqgb7/vngsox

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-100),同时也会分成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中的数据进行导入工作。

            image.png

看到这里大家应该会明白:我们通过num-mappers  参数控制并行度,split-by参数控制数据分割字段,就可以做到抽数并行化。

数据倾斜

问题分析及阐述

但是并行化后,问题随之而来那就是sqoop的数据分割策略不够优秀导致的数据倾斜。打断下,在具体阐述数据倾斜以及解决方法之前,先提一个知识点后面会用到。

sqoop import 抽数查询愿数据的时候主要有两者方式:--table  方式:全量数据抽取  --query 方式:增加检索条件部分数据抽数,当然也可以where 1=1 进行全量操作,有很多人应该注意到 --query 语句后面必须要加一个 "and $CONDITIONS" 字符串,不加还报错。那$CONDITIONS 到底是干什么用的呢?其实它的作用是数据分割条件的占位符,也就是说最终数据查询语句中的$CONDITIONS 会被split-by>=501 and split-by<=1000  这样的分割条件替换。

数据倾斜是啥呢?在说数据倾斜之前,我们设想数据并行抽数最理想的情况就是所有的并行实例同时完成,木桶原理,数据抽数时间的长短取决于耗时最长的那个实例。由于各个实例被分配的数据量不均而导致分配到数据量较少的实例早早完成,而被分配大量数据的实例迟迟无法完成,导致整个作业运行时间很长的现象就是数据倾斜导致的。数据倾斜概括为一句话:数据分配不均。

从上面的具体原理了解到数据的分割方法是根据数据表的某个字段去分割的,但是从大量的实践经验来sqoop split-by 的数据切分策略对字符串类型字段支持及其不好,不但有严重的数据倾斜现象,同时还存在数据重复抽取、数据漏抽的现象,数据质量都没有办法保障肯定是允许的。那么切分策略对int(整数)类型的支持呢?如果数据分布不均同样会造成数据倾斜的问题?

阐述下切分策略对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类型同时数据分布均匀,满足这样的要求的表只有极少数的有自增主键的表才能满足,我相信大多数的表不会满足这样的要求,临时增加字段肯定是不现实的。

数据倾斜解决方法

在了解数据切分策略之后,在数据表没有符合要求的字段的情况下,我们需要自己临时简单创建理想的字段。

这里需要使用--query 方式:涉及参数  --query、--split-by、--boundary-query

--query: select column1、 column2、 column3、 columnN from (select ROWNUM() OVER() AS ETL_ID, T.* from table T where xxx )  where $CONDITIONS

--split-by: ETL_ID

--boundary-query: select 1 as MIN , sum(1) as MAX from table where xxx

具体原理就是通过ROWNUM() 生成一个严格均匀分布的字段,然后指定为分割字段。

ok,就是这么简单,是不是恍然大悟

实测一张1500w左右数据量 30多字段 表开30 mappers 耗时大概3分钟。

如有问题欢迎留言,共同探讨。

发布了7 篇原创文章 · 获赞 2 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章