Sqoop数据迁移工具从入门到精通
一、前言在大数据开发的学习过程中我们经常会遇到这样的场景关系型数据库MySQL、Oracle等中存储着大量的业务数据需要将这些数据迁移到Hadoop生态HDFS、Hive、HBase中进行离线分析或者将Hadoop中分析后的结果数据导回关系型数据库供业务系统使用。手动编写JDBC代码进行数据迁移效率太低且容易出错。这时候就需要一款专业的数据迁移工具——Sqoop。本文将结合我在大数据创新编程课程中的学习经验从Sqoop的安装配置讲起深入讲解RDBMS与Hadoop之间的双向数据迁移涵盖全部导入、查询导入、增量导入、Hive/HBase导入、数据导出以及脚本打包等完整实战案例。二、Sqoop概述2.1 什么是SqoopSqoopSQL To Hadoop是一款开源的数据迁移工具主要用于在HadoopHive与传统的关系型数据库MySQL、Oracle、PostgreSQL等之间进行数据的传递。✅ 可以将关系型数据库中的数据导入到Hadoop的HDFS中✅ 可以将HDFS中的数据导出到关系型数据库中2.2 Sqoop的发展历史Sqoop项目始于2009年最早作为Hadoop的一个第三方模块存在。后来为了便于使用者快速部署和开发人员快速迭代Sqoop独立成为Apache顶级项目。⚠️重要提示Sqoop2的最新版本是1.99.7但2与1不兼容且特征不完整不建议用于生产环境。本文及生产环境均使用Sqoop 1.4.6版本。2.3 Sqoop工作原理Sqoop的核心原理非常简单将导入或导出命令翻译成MapReduce程序来实现。┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 用户输入命令 │────▶│ Sqoop解析命令 │────▶│ 生成MapReduce │ │ (import/export)│ │ (翻译为MR程序) │ │ Job并提交执行 │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ▼ ┌─────────────────┐ │ 定制InputFormat │ │ (从MySQL读取) │ │ 定制OutputFormat│ │ (写入HDFS/MySQL)│ └─────────────────┘在翻译出的MapReduce中主要是对InputFormat从MySQL读取到Hive/HBase和OutputFormat从HDFS读取到MySQL进行定制。三、Sqoop安装与环境配置3.1 安装前提安装Sqoop前必须确保以下环境已就绪依赖版本要求说明JavaJDK 1.8Sqoop基于Java开发Hadoop2.x / 3.x需要Hadoop环境支持MapReduceHive3.x可选如需导入Hive则需要HBase2.x可选如需导入HBase则需要注意Sqoop类似于Flume它不需要常驻进程没有bin/sbin启动文件只有在执行任务时才启动执行完就退出。3.2 下载并解压# 1. 下载地址以1.4.6版本为例wgethttp://mirrors.hust.edu.cn/apache/sqoop/1.4.6/sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz# 2. 上传安装包到虚拟机并解压到指定目录tar-zxfsqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz-C/opt/module/3.3 修改配置文件Sqoop的配置文件位于安装目录下的conf文件夹中。步骤1重命名配置文件cd/opt/module/sqoop-1.4.6.bin__hadoop-2.0.4-alpha/conf/mvsqoop-env-template.sh sqoop-env.sh步骤2修改sqoop-env.shvimsqoop-env.sh根据你的实际环境路径添加以下内容# # Sqoop环境变量配置# # Hadoop Common模块路径exportHADOOP_COMMON_HOME/opt/module/hadoop-3.1.3# Hadoop MapReduce模块路径通常与HADOOP_COMMON_HOME相同exportHADOOP_MAPRED_HOME/opt/module/hadoop-3.1.3# Hive安装路径如需要导入HiveexportHIVE_HOME/opt/module/hive-3.1.2/# ZooKeeper安装路径如需要exportZOOKEEPER_HOME/opt/module/zookeeper-3.7.1/exportZOOCFGDIR/opt/module/zookeeper-3.7.1/# HBase安装路径如需要导入HBaseexportHBASE_HOME/opt/module/hbase-2.4.15/3.4 拷贝JDBC驱动Sqoop需要通过JDBC连接MySQL因此需要将MySQL的JDBC驱动包拷贝到Sqoop的lib目录cpmysql-connector-java-5.1.27-bin.jar /opt/module/sqoop-1.4.6.bin__hadoop-2.0.4-alpha/lib/3.5 验证安装3.5.1 查看帮助命令cd/opt/module/sqoop-1.4.6.bin__hadoop-2.0.4-alpha/ bin/sqoophelp预期输出部分Available commands: codegen Generate code to interact with database records create-hive-table Import a table definition into Hive eval Evaluate a SQL statement and display the results export Export an HDFS directory to a database table help List available commands import Import a table from a database to HDFS import-all-tables Import tables from a database to HDFS import-mainframe Import datasets from a mainframe server to HDFS job Work with saved jobs list-databases List available databases on a server list-tables List available tables in a database merge Merge results of incremental imports metastore Run a standalone Sqoop metastore version Display version information3.5.2 测试数据库连接# 测试连接MySQL列出所有数据库bin/sqoop list-databases\--connectjdbc:mysql://hadoop102:3306/\--usernameroot\--password123456预期输出information_schema metastore mysql oozie performance_schema如果能看到数据库列表说明Sqoop安装配置成功四、数据导入ImportRDBMS → Hadoop在Sqoop中**“导入”**指的是从非大数据集群RDBMS向大数据集群HDFS、Hive、HBase中传输数据使用import关键字。4.1 RDBMS导入到HDFS4.1.1 准备测试数据首先在MySQL中创建测试数据库和表-- 登录MySQLmysql-uroot-p000000-- 创建数据库CREATEDATABASEcompany;-- 创建员工表CREATETABLEcompany.staff(idINT(4)PRIMARYKEYNOTNULLAUTO_INCREMENT,nameVARCHAR(255),sexVARCHAR(255));-- 插入测试数据INSERTINTOcompany.staff(name,sex)VALUES(Thomas,Male);INSERTINTOcompany.staff(name,sex)VALUES(Catalina,FeMale);INSERTINTOcompany.staff(name,sex)VALUES(Mike,Male);4.1.2 全部导入将MySQL表中的全部数据导入到HDFS指定目录bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff\--target-dir /user/company\--delete-target-dir\--num-mappers1\--fields-terminated-by\t参数详解参数说明--connectJDBC连接URL--username/--password数据库用户名/密码--table要导入的表名--target-dirHDFS目标目录--delete-target-dir如果目标目录已存在先删除避免报错--num-mappers 1启动1个MapTask默认4个--fields-terminated-by \t字段分隔符为制表符技巧命令中的反斜杠\用于换行防止Linux直接执行命令。运行结果验证hdfs dfs-ls/user/company/user/company/_SUCCESS # MapReduce执行成功标记 /user/company/part-m-00000 # 实际数据文件hdfs dfs-cat/user/company/part-m-000001 Thomas Male 2 Catalina FeMale 3 Mike Male4.1.3 查询导入Query Import通过SQL查询语句导入指定条件的数据bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--target-dir /user/company\--delete-target-dir\--num-mappers1\--fields-terminated-by\t\--querySELECT name, sex FROM staff WHERE id 2 AND $CONDITIONS;⚠️ 重要注意事项必须包含$CONDITIONS这是Sqoop用于数据分片的占位符保证最终导入数据的顺序和原始数据一致使用单引号如果SQL语句用双引号则$CONDITIONS前必须加反斜杠转义\$CONDITIONS防止Shell识别为变量查询结果不能包含重复字段错误示例双引号未转义--querySELECT name,sex FROM staff WHERE name mike AND \$CONDITIONS;4.1.4 导入指定列只导入表中的部分字段bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff\--columnsid,sex\--target-dir /user/company\--delete-target-dir\--num-mappers1\--fields-terminated-by\t注意--columns中多列用逗号分隔不要添加空格运行结果只有id和sex两列1 Male 2 FeMale 3 Male4.1.5 使用WHERE条件筛选导入bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--target-dir /user/company\--delete-target-dir\--num-mappers1\--fields-terminated-by\t\--tablestaff\--whereid1where可以与columns搭配使用实现更灵活的数据筛选。4.2 RDBMS导入到HiveSqoop可以直接将MySQL数据导入到Hive表中无需手动创建Hive表Sqoop会自动创建。bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff\--num-mappers1\--hive-import\--fields-terminated-by\t\--hive-overwrite\--hive-table staff_hive参数详解参数说明--hive-import将数据导入到Hive--hive-overwrite覆盖Hive表中已存在的数据--hive-table指定导入到Hive的表名默认使用MySQL表名执行过程解析Step 1: MySQL ──import──▶ HDFS临时目录 (/user/用户名/staff/) Step 2: HDFS临时目录 ──move──▶ Hive仓库目录 (/user/hive/warehouse/staff_hive/) Step 3: 删除HDFS临时目录验证hiveSELECT*FROMstaff_hive;4.3 RDBMS导入到HBaseSqoop可以直接将MySQL数据导入到HBase中通过MapReduce直接写入HBase表不需要中间结果写入HDFS临时目录。bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff\--columnsid,name,sex\--column-familyinfo\--hbase-create-table\--hbase-row-keyid\--hbase-tablehbase_staff\--num-mappers1\--split-byid参数详解参数说明--columns指定要导入的列--column-familyHBase列族名--hbase-create-table自动创建HBase表Sqoop 1.4.6仅支持HBase 1.0.1之前版本--hbase-row-key指定HBase行键RowKey--hbase-tableHBase目标表名--split-by指定分片列提高并行导入效率⚠️版本兼容性注意Sqoop 1.4.6只支持HBase 1.0.1之前版本的自动创建表功能。如果使用更高版本HBase需要手动创建表hbase shell hbasecreatehbase_staff,infohbasescanhbase_staff如果遇到NoSuchMethodError: org.apache.hadoop.hbase.client.HBaseAdmin.init报错建议下载一个低版本的HBase将其lib目录下的所有jar包复制到Sqoop的lib目录下遇到重名文件不要替换。运行结果ROW COLUMNCELL 1 columninfo:name, timestamp2023-10-07T17:35:59.519, valueThomas 1 columninfo:sex, timestamp2023-10-07T17:35:59.519, valueMale 2 columninfo:name, timestamp2023-10-07T17:35:59.519, valueCatalina 2 columninfo:sex, timestamp2023-10-07T17:35:59.519, valueFeMale 3 columninfo:name, timestamp2023-10-07T17:35:59.519, valueMike 3 columninfo:sex, timestamp2023-10-07T17:35:59.519, valueMale 3 row(s)五、数据导出ExportHadoop → RDBMS在Sqoop中**“导出”**指的是从大数据集群HDFS、Hive、HBase向非大数据集群RDBMS中传输数据使用export关键字。5.1 Hive/HDFS导出到RDBMSbin/sqoopexport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff\--num-mappers1\--export-dir /user/hive/warehouse/staff_hive\--input-fields-terminated-by\t参数详解参数说明--export-dir要导出的HDFS源目录--input-fields-terminated-byHDFS数据文件的字段分隔符必须与导入时一致--tableMySQL目标表名⚠️重要MySQL中如果表不存在不会自动创建需要提前在MySQL中创建好目标表。防止主键冲突-- 清空MySQL表数据mysqlTRUNCATETABLEstaff;验证导出结果mysqlSELECT*FROMstaff;---------------------- | id | name | sex | ---------------------- | 1 | Thomas | Male | | 2 | Catalina | FeMale | | 3 | Mike | Male | ----------------------⚠️如果不加--input-fields-terminated-by参数整个数据将会被当做一个字符串存到MySQL表中的第一个字段六、增量导入Incremental Import在实际生产环境中数据是持续增长的。全量导入效率太低Sqoop支持增量导入只导入新增或修改的数据。6.1 Append模式基于自增ID适用于表中有自增主键只追加新数据。bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff\--num-mappers1\--fields-terminated-by\t\--target-dir /user/hive/warehouse/staff_hive\--check-columnid\--incrementalappend\--last-value3参数详解参数说明--check-column作为增量判断的列名通常是自增主键--incremental append增量模式追加--last-value上次导入的最大值只导入大于该值的数据⚠️注意append不能与--hive-*参数同时使用Append mode for hive imports is not yet supported6.2 LastModified模式基于时间戳适用于表中有更新时间戳字段导入新增和修改的数据。Step 1创建带时间戳的表CREATETABLEcompany.staff_timestamp(idINT(4),nameVARCHAR(255),sexVARCHAR(255),last_modifiedTIMESTAMPDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP);INSERTINTOcompany.staff_timestamp(id,name,sex)VALUES(1,AAA,female);INSERTINTOcompany.staff_timestamp(id,name,sex)VALUES(2,BBB,female);Step 2首次全量导入bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff_timestamp\--delete-target-dir\--m1Step 3MySQL中新增数据INSERTINTOcompany.staff_timestamp(id,name,sex)VALUES(3,CCC,female);Step 4增量导入bin/sqoopimport\--connectjdbc:mysql://hadoop102:3306/company\--usernameroot\--password000000\--tablestaff_timestamp\--check-column last_modified\--incrementallastmodified\--last-value2023-09-28 22:20:38\--m1\--append⚠️注意使用lastmodified方式需要指定增量数据是--append追加还是--merge-key合并--last-value指定的值会包含于增量导入的数据中即包含边界值七、Sqoop脚本打包Job自动化在实际项目中Sqoop命令通常需要定时执行如每天凌晨同步数据。将命令打包为脚本文件可以方便地交给Oozie、Azkaban等任务调度框架执行。7.1 创建opt脚本文件# 创建存放脚本的目录mkdir-p/opt/module/sqoop-1.4.6.bin__hadoop-2.0.4-alpha/opt/# 创建脚本文件vim/opt/module/sqoop-1.4.6.bin__hadoop-2.0.4-alpha/opt/job_HDFS2RDBMS.opt脚本内容每行一个参数不能有空格export --connect jdbc:mysql://hadoop102:3306/company --username root --password 000000 --table staff --num-mappers 1 --export-dir /user/hive/warehouse/staff_hive --input-fields-terminated-by \t7.2 执行脚本bin/sqoop --options-file opt/job_HDFS2RDBMS.opt执行前清空MySQL表TRUNCATETABLEstaff;验证结果SELECT*FROMstaff;类似Hive的hql文件可以通过hive -f命令执行hql文件中的命令Sqoop的opt文件同理。八、Sqoop常用命令与参数速查表8.1 常用命令一览序号命令类说明1importImportTool将数据导入到集群2exportExportTool将集群数据导出3codegenCodeGenTool获取数据库表数据生成Java并打包Jar4create-hive-tableCreateHiveTableTool创建Hive表5evalEvalSqlTool查看SQL执行结果6import-all-tablesImportAllTablesTool导入数据库下所有表到HDFS7jobJobTool生成Sqoop任务不立即执行8list-databasesListDatabasesTool列出所有数据库名9list-tablesListTablesTool列出数据库下所有表10mergeMergeTool合并HDFS不同目录的数据11metastoreMetastoreTool记录Sqoop job的元数据信息12helpHelpTool打印帮助信息13versionVersionTool打印版本信息8.2 公用参数数据库连接参数说明--connect连接关系型数据库的URL--connection-manager指定要使用的连接管理类--driverJDBC驱动类--username连接数据库的用户名--password连接数据库的密码--verbose在控制台打印详细信息8.3 Import特有参数参数说明--append将数据追加到HDFS已存在的DataSet中--as-avrodatafile导入到Avro数据文件--as-sequencefile导入到Sequence文件--as-textfile导入到普通文本文件默认--columns col1,col2指定要导入的字段--m/--num-mappers n启动N个Map并行导入默认4个--query/--e sql通过SQL查询导入必须含$CONDITIONS--split-by column按指定列分片不能与--autoreset-to-one-mapper连用--table table关系数据库表名--target-dir dir指定HDFS目标路径--where condition导入时的WHERE条件--check-column col增量导入的判断列--incremental mode增量模式append或lastmodified--last-value value增量导入的起始标记值8.4 Export特有参数参数说明--export-dir dir要导出的HDFS源目录--update-key col对指定列进行更新操作--update-mode modeupdateonly/allowinsert默认--staging-table table创建临时表存放事务结果防错误--clear-staging-table导出前清空临时表8.5 Hive相关参数参数说明--hive-import将数据导入到Hive表--hive-overwrite覆盖Hive表中已存在的数据--create-hive-table如果目标表已存在则创建失败默认false--hive-table table指定Hive目标表名--hive-partition-key创建分区后跟分区名--hive-partition-value v导入时指定分区值九、常见问题与解决方案9.1 缺少JDBC驱动报错java.lang.ClassNotFoundException: com.mysql.jdbc.Driver解决cpmysql-connector-java-*.jar /opt/module/sqoop-1.4.6.bin__hadoop-2.0.4-alpha/lib/9.2 HBase版本不兼容报错NoSuchMethodError: org.apache.hadoop.hbase.client.HBaseAdmin.init解决下载低版本HBase的lib目录jar包复制到Sqoop的lib目录重名文件不要替换。9.3 目标目录已存在报错Target directory already exists解决添加--delete-target-dir参数或手动删除HDFS目录hdfs dfs-rm-r/user/company9.4 导出时主键冲突报错Duplicate entry 1 for key PRIMARY解决导出前清空MySQL表TRUNCATETABLEstaff;9.5 分隔符不匹配现象导出后MySQL中所有数据挤在一个字段解决确保--fields-terminated-by导入和--input-fields-terminated-by导出参数一致。十、完整数据链路总结在实际的大数据项目中Sqoop通常处于数据链路的关键位置十一、总结本文从Sqoop的安装配置出发系统讲解了RDBMS与Hadoop之间的双向数据迁移方向场景核心命令导入MySQL → HDFSsqoop import--target-dir导入MySQL → Hivesqoop import--hive-import导入MySQL → HBasesqoop import--hbase-table导出HDFS/Hive → MySQLsqoop export--export-dir增量追加新数据--incremental append增量按时间更新--incremental lastmodified自动化定时任务.opt脚本 调度框架核心要点回顾✅ Sqoop将命令翻译为MapReduce程序高效并行处理✅ 导入时注意$CONDITIONS占位符和分隔符设置✅ 导出时确保MySQL表已存在且分隔符匹配✅ 增量导入支持append和lastmodified两种模式✅ 使用.opt脚本打包命令便于任务调度