Sqoop使用笔记

作者: 纳尼2号 | 来源:发表于2016-07-17 17:35 被阅读5547次

    [TOC]

    最近在研究数据采集相关的知识,需要用到Sqoop把关系型数据库的数据导入到Hive里,这里记录下自己的使用心得,更多的是需要注意的地方。

    环境准备

    OS: MacOS
    Hadoop: 2.7.2
    Hive: 1.0.0
    Sqoop: 1.4.6

    根据Sqoop官网说法,Sqoop2 目前还未开发完,不建议在生产环境使用,所以这里选的是Sqoop的稳定版 1.4.6
    Hadoop和Hive的安装与配置可以参考网上的资料,Sqoop环境配置注意修改 ${SQOOP_HOME}/conf/sqoop_env.sh ,如果使用MySQL,还要将MySQL的驱动jar包拷贝到 ${SQOOP_HOME}/lib 目录下

    Sqoop简介

    Sqoop是一个用于Hadoop和关系型数据库或主机之间的数据传输工具。它可以将数据从关系型数据库import到HDFS,也可以从HDFS export到关系型数据库,通过Hadoop的MapReduce实现。

    Sqoop命令

    执行 $sqoop help, 可以看到Sqoop支持的命令:

    Sqoop命令

    具体使用方法参见官方文档, 这里我们主要介绍下 import 命令的注意点

    sqoop-import 注意点

    import 可能会用到的参数:

    Argument Described
    --append Append data to an existing dataset in HDFS
    --as-sequencefile import序列化的文件
    --as-textfile import plain文件 ,默认
    --columns <col,col,col…> 指定列import,逗号分隔,比如:--columns "id,name"
    --delete-target-dir 删除存在的import目标目录
    --direct 直连模式,速度更快(HBase不支持)
    --fetch-size <n> 一次从数据库读取 n 个实例,即n条数据
    -m,--num-mappers <n> 建立 n 个并发执行task import
    -e,--query <statement> 构建表达式<statement>执行
    --split-by <column-name> 根据column分隔实例
    --autoreset-to-one-mappe 如果没有主键和split-by 用one mapper import (split-by 和此选项不共存)
    --table <table-name> 指定表名import
    --target-dir <d> HDFS destination dir
    --warehouse-dir <d> HDFS parent for table destination
    --where <where clause> 指定where从句,如果有双引号,注意转义 \$CONDITIONS,不能用or,子查询,join
    -z,--compress 开启压缩
    --null-string <null-string> string列为空指定为此值
    --null-non-string <null-string> 非string列为空指定为此值,-null这两个参数are optional, 如果不设置,会指定为"null"
    1. 如果是分布式环境,--connect参数不要写成localhost,应该写TaskTracker节点的地址

    2. 数据库登录密码可以指定文件 --password-file ${user.home}/.password这个文件可以放到local或者hdfs上,注意:此文件不能有空格,echo -n "secret" > password.file

    3. 尽量别用 --password,不安全(ps命令可以获取到此参数), 可以用-P输入console方式, 注意:密码可以设置别名:--password-alias

    4. -m <n> 并发数默认是4 task, 并发数n不要超过可用的MapReduce集群数,也不要超过数据库支持限度。并发原理:假定split-column = id,数据库中 id = 0-1000,sqoop默认4个task,切成0-250,251-500 ... 不支持多列 split. (可以看到hdfs里有按并发数切了4个切片)

    5. 当使用Oozie启动Sqoop job时,添加 --skip-dist-cache 参数,Oozie会cache job需要的lib包

    6. --warehouse-dir 可以指定父级目录,与 --target-dir 不共存

    7. --map-column-java, --map-column-hive 指定某几列映射成Java或Hive的列属性

    8. 支持增量 --incremental <mode> mode指定为append或lastmodified,还要指定列增量的值,感觉不是很好用,万一数据是更新怎么办?

    9. 导出数据文件分两种 delimited 和 序列化文件,还可以-z压缩

    10. 如果列含有BLOB或CLOB等大型数据列,--inline-lob-limit 可以限制下,暂时先不研究

    11. 其他涉及到import export特殊字符转义的先不考虑,如果需要可以参见 Table6、7 Format

    12. 数据导入Hive


    • --hive-overwrite: 全表overwrite(需配合--hive-import使用,如果Hive里没有表会先创建之)

    • --create-hive-table: 自动推断表字段类型直接建表,overwrite功能可以完全替代掉了(但hive里此表不能exist,所以在import前要先drop下)

    • --hive-import - -hive-overwrite 这两个参数组合很不错 (直接overwrite也可以,但是考虑到如果表结构有变化,hive里是不会感知到的,所以还是先drop吧)

    • 如果含有特殊字符,需要转义可以用 -detlims 参数,这个参数只能用于hive默认分隔符

    • 默认用"null" 代替 NULL,而Hive \N 标识 NULL值,可以使用--null-string '\\N' --null-non-string '\\N' 解决这个问题, 没什么特殊要求就加上吧

    • Hive也可以使用 --compress 压缩,但是缺点是很多解码器不支持并行任务的split,貌似lzop解压可以,但是要求颇多,不建议使用

    • Hive里不支持 SQL 类型:bit(2),这样是不妥的,应该改成 bit(1)

    1. Sqoop支持import到 HBase,Accumulo 时间关系,暂不研究
    2. 支持额外的参数 conf/sqoop-site.xml 自己配置去(-…-)

    sqoop-import-all-tables 注意点

    1. import-all-tables 可以整库的import,但有以为下限制条件:
    • 每个表都必须有一个单列主键,或者指定--autoreset-to-one-mapper参数
    • 每个表只能import全部列,即不可指定列import
    • 不能使用非默认的分隔符,不能指定 where 从句
    1. --exclude-tables <tables>此参数可以 exlude掉不需要import的表(多个表逗号分隔)
    2. 不可以使用 --table, --split-by, --columns, --where,--delete-target-dir 等等参数
    3. 不支持 --class-name,可以用 --package-name 指定package
    4. 一旦执行过程中有异常抛出,会立即停止

    sqoop-import-mainframe

    直接import主机!这个命令过于暴力,和import-all-tables差别不大,等有需要在研究研究吧。

    sqoop-job 注意点

    Sqoop可以将import任务保存为job,可以理解为起了个别名,这样方便的Sqoop任务的管理。

    参数列表:
    Argument Described
    --create <job-id> 创建一个job,job-id是job名称,
    --delete <job-id> 删除这个job
    --exec <job-id> 执行这个job
    --show <job-id> Show the parameters for a saved job.
    --list List all saved jobs
    --meta-connect <jdbc-uri> Specifies the JDBC connect string used to connect to the metastore
    job存储方案

    job的是有两种存储方案的,通过配置--meta-connect或者在conf/sqoop-site.xml 里配置 sqoop.metastore.client.autoconnect.url 参数来指定是否使用metastore-client

    方案A(推荐):不使用metastore-client

    如果job信息放到 ${HOME}/.sqoop 目录下,此目录下有两个文件:
    metastore.db.properties:metastore的配置信息
    metastore.db.script:job的详细信息,通过sql语句存储

    方案B: 不使用metastore-client

    此时,job的信息会存储到配置的 autoconnect.url 的 SQOOP_SESSION 表里,但是此方案会有个bug,我本地在执行创建job的时候报错:

    ERROR tool.JobTool: I/O error performing job operation: java.io.IOException: Invalid metadata version
    

    上网查了下解决方案,发现 SQOOP_ROOT 表需要插入条数据:

    INSERT INTO SQOOP_ROOT VALUES(NULL,'sqoop.hsqldb.job.storage.version','0');
    

    所以,还是使用方案A吧,这样也不会对数据库造成入侵

    注意: 如果使用Oozie执行sqoop-job的话,务必将sqoop-site.xml 中的 sqoop.metastore.client.record.password参数设置为true

    其他命令

    1. sqoop-export:HDFS export 到关系型数据库,目标table必须存在,可分为insert和update模式
    2. sqoop-metastore:指定metadata仓库,可在配置文件中设置
    3. sqoop-merge:合并两个数据集,一个数据集的记录应该重新旧数据集的条目
    4. sqoop-codegen:将数据集封装成Java类
    5. sqoop-create-hive-table:Sqoop单独提供了针对Hive的命令,可以代替 sqoop import --hive-import, 其他参数一样
    6. sqoop-eval:执行sql语句,结果会打印在控制台,可以用来校验下import的查询条件是否正确
    7. sqoop-list-databases,sqoop-list-tables:列出数据库,列出表

    以上命令暂时没用到或很简单,等以后需要的时候再去研究吧

    HCatalog

    HCatalog提供表和存储管理服务,使不同的Hadoop数据处理工具如:Pig,MapReduce,Hive更容易读取和写入数据网格

    看文档比较复杂,暂时用不到,等以后需要的时候再去研究吧o(╯□╰)o

    需要注意的地方

    1. MySQL
    • MySQL允许Date类型字段出现'0000-00-00',Sqoop有三种方式处理这种情况:1. 转成NULL(默认),2. 抛出异常 3. 置成'0001-01-01', 配置zeroDateTimeBehavior参数设置,跟在connect string后面
    • UNSIGNED 列, MySQL 范围:0 ~ 2^32 ,Sqoop范围:-2^31~ +2^31-1, 注意不要越界
    1. Hive
    • DATE, TIME, TIMESTAMP 类型转换到Hive里会被处理为 String
    • NUMERIC, DECIMAL 类型转换到Hive里会被处理为 DOUBLE
    • Sqoop会打印warn日志警告可能会丢失精度
    1. --direct 参数目前只有MySQL和PostgreSQL(import) 支持,不支持BLOB, CLOB, LONGVARBINARY 列
    2. --direct不支持视图

    最佳实践

    根据我的个人需求,配置了适合我的最佳Sqoop参数(∩_∩)

    单表import到Hive:

    sqoop import  \
      --connect jdbc:mysql://127.0.0.1:3306/database_name \
      --username root \
      --password 123456 \
      --table table_name \
      --outdir \${HOME}/.sqoop/java  \
      --delete-target-dir \
      --hive-import \
      --hive-overwrite \
      --null-string '\\N' \ 
      --null-non-string '\\N' \
      -m 8 \
      --direct
    

    整库import到Hive:

    sqoop import-all-tables \
      --connect jdbc:mysql://127.0.0.1:3306/database_name \
      --username root \
      --password 123456 \
      --outdir \${HOME}/.sqoop/java  \
      --hive-import \
      --hive-overwrite \
      --null-string '\\N' \ 
      --null-non-string '\\N'  \
      -m 8 \
      --direct
    

    说明:
    --out-dir:指定Java文件的路径
    --delete-target-dir:删除HDFS目录
    --hive-import:直接导入的Hive
    --hive-overwrite:全表覆盖(如果表不存在会直接创建表)
    --null-string:指定String列如果为NULL转换到Hive里也为NULL
    --null-non-string:指定String列如果为NULL转换到Hive里也为NULL
    -m 8:8个并发
    --direct:直连模式,使用mysqldump加快速度(本地测试13W条数据,74M, 快了10%左右)

    最后

    通过几天对Sqoop的研究,掌握了Sqoop import的基本用法,更高级的用法还有待探索,最近在写个Sqoop的Java工具类,希望能通过API的形式执行Sqoop命令,以后也会加入Oozie对Sqoop job的管理。

    PS:Sqoop2 有很多新特性, 支持命令行、Web UI、REST API,支持server模式同时也更安全易用,所以很期待Sqoop的 2.0 版!

    相关文章

      网友评论

      • 孙蕴涛Spark:你好,用--direct方式根本不能把数据导入表中啊,dump下来的都是insert语句啊
      • venuslf:你好,今天在用sqoop想把数据从hive导出到mysql的时候,报错ERROR manager.CatalogQueryManager: Failed to list databases
        com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure,可能是因为啥呢,试了网上的一些解决方法都没能成功。
      • royalfeng:你好,我也是用这个版本但是用sqoop向外导出数据时,出现
        WARN mapreduce.Counters: Group FileSystemCounters is deprecated. Use org.apache.hadoop.mapreduce.FileSystemCounter instead
        好像是版本不匹配的错误,你能帮我解答下么?
        royalfeng:@DreamYoung 你好,后面解决了,表结构的问题,但是从HDFS导出到Mysql异常的慢最后直接job死了
        纳尼2号:@royalfeng 你好,你是从哪里导到哪里呢?机器什么环境?或者查看下两边的表结构是否一致 :grin:
      • GK_斯皮利特:谢谢 解决了我一个问题:joy: :joy: 烦了两天了
      • c632bd2db8b4:高大上 :+1: :+1:
        纳尼2号:@道熵 :smiley:
      • 纳尼2号:第一次在简书上发文章,以后要多写写咯 :stuck_out_tongue_closed_eyes:

      本文标题:Sqoop使用笔记

      本文链接:https://www.haomeiwen.com/subject/shtpjttx.html