Hadoop之Sqoop

x33g5p2x  于2020-10-30 发布在 Sqoop  
字(7.7k)|赞(0)|评价(0)|浏览(826)

1**、Sqoop概述**

通常在一个组织中,有价值的数据都要存储在关系型数据库系统中,以方便应用于各种业务系统。但是为了进一步进行处理,有些数据需要抽取出来,通过MapReduce程序进行再次加工。为了能够和HDFS系统之外的数据库系统进行交互,MapReduce程序需要使用外部API来访问数据。

Sqoop(全称SQL-TO-Hadoop)就是一款开源的工具,主要用于在Hadoop系统与传统的数据库系统(如MySQL、Oracle等)间进行数据的传递,可以将数据从关系型数据库中抽取到Hadoop中,也可以把Hadoop中MapReduce处理完的数据导回到关系型数据库中。Sqoop专为大数据批量传输设计,能够分割数据集并创建Hadoop任务来处理每个区块。类似于其他ETL工具,使用元数据模型来判断数据类型,并在数据从数据源转移到Hadoop时确保类型安全的数据处理。

Sqoop项目开始于2009年,最早是作为Hadoop的一个第三方模块存在,后来为了让使用者能够快速部署,也为了让开发人员能够更快速地迭代开发,Sqoop便独立出来成为了一个Apache项目。当大数据存储和Hadoop生态系统的MapReduce,Hive,HBase,Cassandra,Pig等分析器出现时,它们需要一种工具来与关系型数据库服务器进行交互,以导入和导出驻留在其中的大数据。在这里,Sqoop在Hadoop生态系统中占据一席之地,以便在关系型数据库服务器和HDFS之间提供可行的交互。

2**、Sqoop工作机制**

下图简单描述了Sqoop的工作流程:

Sqoop****导入

从RDBMS向HDFS导入单独的表,表中的每一行都被视为HDFS中的记录,所有记录都以文本形式存储在文本文件中或作为Avro和Sequence文件中的二进制数据存储。

Sqoop****导出

将一组文件从HDFS导出到RDBMS。往Sqoop输入的文件包含记录,这些记录对应于关系型数据库表中的行,这些文件被Sqoop读取,然后解析成一组记录,并使用用户指定的分隔符进行分隔。

3**、Sqoop的安装和配置**

Sqoop的安装和配置非常简单,首先,将Sqoop的安装包上传到主机hadoop221的/root/tools目录下,然后运行命令tar -zxvf sqoop-1.4.5.bin__hadoop-0.23.tar.gz -C /root/training/,将Sqoop安装包解压到/root/training目录下,接着为Sqoop配置环境变量,运行命令vi /root/.bash_profile,在文件末尾添加如下内容:

SQOOP_HOME=/root/training/sqoop-1.4.5.bin__hadoop-0.23

export SQOOP_HOME

PATH=$SQOOP_HOME/bin:$PATH

export PATH

保存退出,并运行命令source/root/.bash_profile,使环境变量生效。需要注意的是,由于Sqoop是基于JDBC的方式将关系型数据库表中的数据导入到HDFS,本文又是采用的Oracle数据库,因此需要将Oracle数据库的驱动jar包拷贝到Sqoop的安装目录下的lib目录中。这里是将Oracle 10g版本的数据库安装在虚拟机的Window XP系统中,在其C:\oracle\product\10.2.0\db_1\jdbc\lib目录下可以找到对应的jar包——ojdbc14.jar,将该jar拷贝到主机hadoop221的/root/training/sqoop-1.4.5.bin__hadoop-0.23/lib目录下即可。

至此,Sqoop的安装和配置完成。现在来检查下Sqoop是否配置成功,运行命令sqoop version,查看当前安装的Sqoop版本信息,如下图所示:

如何得知Sqoop可以完成哪些任务?Sqoop提供了一个帮助命令help,用于查看Sqoop都提供了哪些服务,运行命令sqoop help,可以看到如下图所示的内容。

针对每个具体的服务,同样可以通过help命令,查看到该服务详细的使用说明信息,如查看codegen服务的使用说明信息,运行命令sqoop codegen --help即可,如下图所示,非常详细,其中Common arguments对应通用的参数,Code generationarguments对应codegen命令可以使用的参数等等。

针对Sqoop提供的服务,这里简单做了个总结,并简单阐述了每个服务的作用,如下表所示:
服务

功能说明codegen

将关系型数据库表映射为一个Java文件、Java Class类以及相关的jar包create-hive-table

生成与关系型数据库表的表结构相对应的HIVE表eval

快速地使用SQL语句对关系型数据库进行操作,这可以使得在使用import这种服务进行数据导入的时候,可以预先了解相关的SQL语句是否正确,并能将结果显示在控制台。export

从HDFS中导出数据到关系型数据库表中help

查看Sqoop服务的使用说明import

将关系型数据库表中的数据导入到HDFS中import-all-tables

将关系型数据库所有表中的数据导入到HDFS中job

用来生成一个Sqoop的任务,生成后,该任务并不执行,除非使用命令执行该任务。list-databases

打印出关系型数据库中所有的数据库名(或用户名)list-tables

打印出关系型数据库某一个数据库中的所有表名merge

将HDFS中不同目录下面的数据合在一起,并存放在指定的目录中metastore

记录sqoop job的元数据信息version

显示sqoop版本信息

4**、Sqoop的基本使用**

Sqoop是一个工具,它提供了很多非常实用的服务,通过这些服务可以方便地将数据在RDBMS与HDFS之间转移,下面将简单讲述这些服务的基本使用。准备工作,进入主机hadoop221的/root目录下,新建sqoop目录,专门用于存放sqoop相关的数据文件。这里需要注意的是,本文使用的关系型数据库是Oracle,因此在使用sqoop相关命令时,涉及到Oracle数据库的用户名、表名以及列名都需要大写,如果使用的是其他关系型数据库(如MySQL),则没有这个要求。

A**、codegen服务**

该服务能够根据关系型数据库表的结构,自动生成Java Class(实体类,即Java Bean)及对应的jar包,免去了自己编写这部分代码的繁琐工作。运行命令:

sqoop codegen --connectjdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT --password tiger--table EMP --outdir /root/sqoop

输出的log如下图所示,同时Sqoop在指定的/root/sqoop目录下生成了EMP.java类文件,在目录/tmp/sqoop-root/compile/f05f0312341c5373a24e6a617ba4a5cc下生成了EMP.jar包。

B**、create-hive-table服务**

该服务能够根据Oracle数据库中指定表的结构,在Hive中自动创建对应的表,运行命令:

sqoop create-hive-table --connectjdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT --password tiger--table EMP --hive-table emphive --fields-terminated-by ' '

--hive-table参数用于指定创建的Hive表的名称,--fields-terminated-by参数用于指定Hive表中每行数据的分隔符,这里以空格进行分隔。输出的log信息及在Hive中创建的表结构信息如下图所示。

C**、eval服务**

该服务用于在Sqoop中执行SQL语句,对指定的数据表进行查询操作,注意,只能进行查询操作,不能进行增、删、改等操作,运行命令:

sqoop eval --connectjdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT --password tiger --query"select empno,ename,deptno from emp where deptno=20"

--query参数用于指定相应的SQL查询语句,输出的log信息及查询结果如下图所示。

运行如下命令,执行多表查询:

sqoop eval --connectjdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT --password tiger--query "select ename,dname from emp,dept whereemp.deptno=dept.deptno"

输出的log信息及查询结果,如下图所示:

D**、import服务**

该服务把关系型数据库指定表中的数据导入到HDFS中,其本质就是运行一个MapReduce程序来完成该操作。运行命令:

sqoop import --connectjdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT --password tiger--table EMP --target-dir /sqoop/emp

输出的部分Log信息及在HDFS上生成的文件内容,如下图所示。

运行如下命令,将关系型数据库emp表中的指定列数据,导入到HDFS中:

sqoop import --connectjdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT --password tiger--table EMP --columns empno,ename,deptno --target-dir /sqoop/emp1

运行结果如下图所示:

E**、import-all-tables服务**

该服务将关系型数据库当前连接用户下的所有数据表中的数据导入到HDFS中,注意,该命令不能指定目标目录,默认将数据导入到/user/root目录下,运行命令:

sqoop import-all-tables --connectjdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT --password tiger -m1

-m参数用于指定MapReduce任务只启动一个map进程,对应也就只在HDFS上建立一个分区,最终在HDFS上就只会产生一个文件。从产生的log信息可以看到,在执行该命令的过程中,连续产生了多个MapReduce任务,最终在HDFS上生成的文件内容如下图所示。可以看出,针对数据库中的每张表,都会在HDFS指定目录下生成一个目录,并将各张表中的数据保存到对应目录下。

F**、list-databases服务**

该服务针对不同的关系型数据库,其功能有所区别,对于Oracle数据库,它将数据库中所有的用户名列举出来,而对于MySQL数据库,它则是将MySQL中所有的数据库名列举出来,运行命令:

sqoop list-databases --connectjdbc:oracle:thin:@192.168.12.142:1521/orcl --username SYSTEM --passwordpassword

这里需要注意,由于是将Oracle数据库中的所有用户名列举出来,需要使用管理员用户SYSTEM进行连接,运行结果如下图所示:

G**、list-tables服务**

该命令将当前连接数据库中所有数据表列举出来,运行命令:

sqoop list-tables--connect jdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT--password tiger

输出结果如下图所示:

H**、将数据导入HBase(import服务)**

import服务还有个比较特别的作用,它能够将数据从关系型数据库表中导入到HBase中,不过在导入数据到HBase之前,需要先在HBase中创建好相应的数据表,如下图所示:

运行命令:

sqoop import--connect jdbc:oracle:thin:@192.168.12.142:1521:orcl --username SCOTT--password tiger --table EMP --columns empno,ename,sal,deptno --hbase-table emp--hbase-row-key empno --column-family empinfo

其中,参数--table用于指定导出数据的关系型数据库表,参数--columns用于指定导出的数据列,参数--hbase-table用于指定导入数据的HBase表,--hbase-row-key用于指定HBase表的行键,参数--column-family用于指定导入数据的HBase表的列族。命令执行完后,输出的部分log如下图所示,可以看出Sqoop执行该命令时,最终被转换为一个MapReduce任务来执行。

查看HBase中的emp表,部分内容如下图所示:

5**、深入了解数据库导入(import)**

在深入理解之前,需要先考虑一个问题:Sqoop是通过一个MapReduce作业从数据库中导入一个表,这个作业从表中抽取一行行的记录,然后写入到HDFS。MapReduce是如何记录的?

下图是Sqoop从数据库中导入表数据到HDFS的原理图:

在导入开始之前,Sqoop使用JDBC来检查将要导入的表,它检索出表中所有的列以及列的SQL数据类型,这些SQL类型(如VARCHAR、INTEGER)被映射到Java数据类型(如String、Integer等),在MapReduce程序中将使用这些对应的Java类型来保存字段的值。Sqoop的代码生成器使用这些信息来创建对应表的类,用于保存从表中抽取的记录。

对于导入来说,更关键的是DBWritable接口的序列化方法,这些方法能使Widget类和JDBC进行交互:

public void readFields(resultSet _dbResults) throwsSQLException;

public void write(PreparedStatement _dbstmt) throwsSQLException;

JDBC的ResultSet接口提供了一个用户从查询结果中检索记录的游标;这里的readFields()方法将用ResultSet中一行数据的列来填充相应对象的字段。

Sqoop启动的MapReduce作业用到一个InputFormat,它可以通过JDBC从一个数据库表中读取部分内容。Hadoop提供的DataDriverDBInputFormat能够为几个Map任务对查询结果进行划分。为了获得更好的导入性能,查询会根据一个“划分列”来进行划分,Sqoop会选择一个合适的列作为划分列(通常是表的主键)。

在生成反序列化代码和配置InputFormat之后,Sqoop将作业发送到MapReduce集群。Map任务将执行查询并将ResultSet中的数据反序列化到生成类的实例,这些数据要么直接保存在SequenceFile文件中,要么在写到HDFS之前被转换成分割的文本。

Sqoop不需要每次都导入整张表,用户也可以在查询中加入where子句,以此来限定需要导入的记录。

导入和一致性:在向HDFS导入数据时,最重要的是要确保访问的是数据源的一致性快照。从一个数据库中并行读取数据的Map任务分别运行在不同的进程中。因此,他们不能共享一个数据库任务。保证一致性的最好方法就是在导入时不允许执行任何对表中现有数据进行更新的操作。

6**、深入了解数据库导出(export)**

Sqoop导出功能的架构与其导入功能非常相似,在执行导出操作之前,Sqoop会根据数据库连接字符串来选择一个导出方法,一般为JDBC。然后,Sqoop会根据目标表的定义生成一个Java类,这个生成的类能够从文本文件中解析记录,并能够向表中插入类型合适的值。接着会启动一个MapReduce作业,从HDFS中读取源数据文件,使用生成的类解析记录,并且执行选定的导出方法。

基于JDBC的导出方法会产生一批insert语句,每条语句都会向目标表中插入多条记录。多个单独的线程被用于从HDFS读取数据并与数据库进行通信,以确保涉及不同系统的I/O操作能够尽可能并行执行。

虽然HDFS读取数据的MapReduce作业大多根据所处理文件的数量和大小来选择并行度(map任务的数量),但Sqoop的导出工具允许用户明确设定任务的数量。由于导出性能会受并行的数据库写入线程数量的影响,所以Sqoop使用combinefileinput类将输入文件分组分配给少数几个map任务去执行。

导出与事务

进程的并行特性,导致导出操作往往不是原子操作,Sqoop会采用多个并行的任务进行导出,并且数据库系统使用固定大小的缓冲区来存储事务数据,这时一个任务中的所有操作不可能在一个事务中完成。因此,在导出操作进行的过程中,提交过的中间结果都是可见的。在导出过程完成前,不要启动那些使用导出结果的应用程序,否则这些应用会看到不完整的导出结果。

更容易出现问题的是,如果任务失败,它会从头开始重新导入自己负责的那部分数据,因此可能会插入重复的记录。当前Sqoop还不能避免这种可能性,在启动导出作业前,应当在数据库中设置表的约束(如定义一个主键列)以保证数据行的唯一性。

导出与SequenceFile

Sqoop还可以将存储在SequenceFile中的记录导出到输出表,不过有一些限制。SequenceFile中可以保存任意类型的记录,Sqoop的导出工具从SequenceFile中读取对象,然后直接发送到OutputCollector,由它将这些对象传递给数据库导出OutputFormat。为了能让Sqoop使用,记录必须被保存在SequenceFile键值对格式的值部分,并且必须继承抽象类com.cloudera.sqoop.lib.SqoopRecord。

参考文献:

——《百度百科》

——《CSDN其他博文》

——《潭州大数据课程课件》

转自https://mp.weixin.qq.com/s/0goJd-vkSppWNGUWlwOElA

相关文章

最新文章

更多