欧洲世界杯_06年世界杯梅西 - hello186.com

sqoop生产常见问题及优化总结

2025-10-05 19:35:33 世界杯经典比赛 3565

Sqoop作为一种重要的数据同步工具,在大数据中具有重要地位。在前期数仓建设中,尤其是DB库(MySQL)数据同步时,对Sqoop生产中遇到的常见问题进行总结并做好记录以便后续查看。

1、Sqoop 空值问题

Hive中的null在底层是以“\N”来存储,而MySQL中的null在底层就是null,这就导致了两边同步数据时存储不一致问题。Sqoop在同步的时候应该严格保证两端的数据格式、数据类型一致,否则会带来异常。

方法1:依赖自身参数

(1)导出数据时采用--input-null-string和--input-null-non-string两个参数。

(2)导入数据时采用--null-string和--null-non-string。

方法2:建表时修改hive底层存储,修改为''(空字符串)

在hive导出时,给需要导出的表创建一张临时表,该表和Mysql同步的表、字段、类型等严格一致,将需要导出的数据插入到该表中,在建立该临时表的时候将hive中Null底层存储“/N”修改为''(空字符串)。具体可添加下面代码

ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' with serdeproperties('serialization.null.format' = '')

例如:

drop table table_name;

CREATE TABLE IF NOT EXISTS table_name(

id int,

name string)

PARTITIONED BY (partition_date string)

ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' with serdeproperties('serialization.null.format' = '')

location 'hdfs://nameservice1/user/hive/warehouse/ods.db/table_name'

;

然后将需要导出的数据插入到该临时表中最后采用sqoop导出命令将数据导出到Mysql导入数据同理

我们sqoop导数任务采用的是第二种方案,虽然比较麻烦,但是能够减少sqoop带来的一些不必要的麻烦,而且也比较容易定位问题,逻辑清晰,sqoop导出的时候只需要写基本的导出命令即可,这样sqoop很容易做成一个通用的脚本来调度。

2、Sqoop 数据一致性问题

(1):如在Sqoop在导出到Mysql时,使用4个Map任务,过程中有2个任务失败,那此时MySQL中存储了另外两个Map任务导入的数据,此时运营正好看到了这个报表数据。而开发工程师发现任务失败后,会调试问题并最终将全部数据正确的导入MySQL,那后面老板再次看报表数据,发现本次看到的数据与之前的不一致,这在生产环境是不允许的。这是由于Sqoop将导出过程分解为多个事务,因此失败的导出作业可能会导致将部分数据提交到数据库。 这可能进一步导致后续作业由于某些情况下的插入冲突而失败,或导致其他作业中的重复数据。 您可以通过--staging-table选项指定登台表来解决此问题,该选项充当用于暂存导出数据的辅助表,分阶段数据最终在单个事务中移动到目标表。

--staging-table方式

(建立临时表,通过sqoop导入到临时表,成功之后再把临时表的数据通过事务导入到mysql的业务数据表,Sqoop在导入导出数据时,通过建立临时表可以解决好多问题,所以要学会巧用临时表),使用--staging-table选项,将hdfs中的数据先导入到临时表中,当hdfs中的数据导出成功后,临时表中的数据在一个事务中导出到目标表中(也就是说这个过程要不完全成功,要不完全失败)。为了能够使用staging这个选项,staging表在运行任务前或者是空的,要不就使用clear-staging-table配置,如果staging表中有数据,并且使用了--clear-staging-table选项,sqoop执行导出任务前会删除staging表中所有的数据。

注意:–direct导入时staging方式是不可用的,使用了—update-key选项时staging方式也不能用。

sqoop export --connect jdbc:mysql://ip:3306/dabases

--username root \

--password pwd \

--table table_name \

--columns id,name,dt \

--fields-terminated-by "\t" \

--export-dir "/user/hive/warehouse/db.ods/table_name_${day}" \

--staging-table table_name_tmp \

--clear-staging-table \

--input-null-string '\N' \

3、数据倾斜问题

sqoop的数据分割策略不够优秀导致的数据倾斜:

sqoop 抽数的并行化主要涉及到两个参数:num-mappers:启动N个map来并行导入数据,默认4个;split-by:按照某一列来切分表的工作单元。要避免数据倾斜,对split-by指定字段的要求是int类型同时数据分布均匀,满足这样的要求的表只有极少数的有自增主键的表才能满足。核心思想就是自己生成一个有序且均匀的自增ID,然后作为map的切分轴,这样每个map就可以分到均匀的数据,可以通过设置map的个数来提高吞吐量。

建议:

数据量500w以下使用4个map即可。

数据量500w以上使用8个map即可,太多会对数据库加压,造成其他场景使用性能降低。如果是为了专门导数据,和下游计算的并行度,可以适当调大。

例如:

通常可以指定split-by 对应的自增ID 列,然后使用–num-mappers或者-m指定map的个数,即并发的抽取进程数量。但是有时候会碰到很多的表没有添加自增ID或者,整数型的主键,或者 主键分布不均,反而会拖慢整个job的进程。

根据sqoop源码的设计,我们可以使用–query语句中添加自增ID,作为split-by的参数,与此同时通过设置的自增ID的范围可以设置boundary。代码:

--query 方式:涉及参数 --query、--split-by、--boundary-query

--query: select col1、 col2、 coln3、 columnN from (select ROWNUM() OVER() AS INC_ID, T.* from table T where xxx ) where $CONDITIONS

--split-by: INC_ID

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

完整语法代码:

password-file通过 echo -n “password content” > passsword-file 方式得到,这样不会包含异常字符。

sqoop import --connect $yourJdbConnectURL \

--username $yourUserName

--password-file file;///localpasswordFile or hdfs relative Path

--query "" \

--split-by "" \

-m 8 \

-boundary-query “select 1 as min , sum(1) as max from table where xx” \

--other parames

参考链接:sqoop 并行抽取数据,同时解决数据倾斜_bymain的博客-CSDN博客

4、Map task并行度设置大于1的问题

并行度导入数据的 时候 需要指定根据哪个字段进行切分 该字段通常是主键或者是自增长不重复的数值类型字段,否则会报下面的错误。

错误日志:

Import failed: No primary key could be found for table. Please specify one with --split-by or perform a sequential import with ‘-m 1’.

就是说当map task并行度大于1时,下面两个参数要同时使用:

–split-by id指定根据id字段进行切分

–m n指定map并行度n个