Sqoop安装、导入导出HDFS/HBase操作详解

一、安装Sqoop

环境准备

Sqoop是一款基于Hadoop系统的数据转移工具,因此在安装Sqoop之前需要先安装好Hadoop。
本文使用的各软件版本如下:
操作系统:ubuntu-14.04.1-desktop-amd64
Hadoop版本:hadoop-2.7.1
MySQL版本:5.5.54
MySQL驱动:mysql-connector-java-5.1.20-bin.jar
Sqoop版本:sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz

安装步骤

1. 下载Sqoop

从Apache官网下载Sqoop的最新稳定版本,下载网址为:https://sqoop.apache.org
本文例子使用的是sqoop-1.4.6版本。

2. 安装Sqoop

1)将下载的Sqoop安装文件上传到Ubuntu系统合适目录(例如usr/local),然后进行解压。解压命令如下:

tar -zxvf sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz

2)将解压后的文件夹sqoop-1.4.6.bin__hadoop-2.0.4-alpha进行重命名为sqoop-1.4.6,代码如下:

mv sqoop-1.4.6.bin__hadoop-2.0.4-alpha sqoop-1.4.6

3)为了以后的操作方便,对Sqoop的环境变量进行配置,在/etc/profile文件中加入以下内容:

export SQOOP_HOME=/usr/local/sqoop-1.4.6
export PATH=$SQOOP_HOME/bin:$PATH

加入后执行source /etc/profile命令对环境变量文件进行刷新。
4)拷贝${SQOOP_HOME}/conf/sqoop-env-template.sh 到${SQOOP_HOME}/conf/sqoop-env.sh,然后修改sqoop-env.sh,加入HADOOP_COMMON_HOME和HADOOP_MAPRED_HOME,指定Hadoop安装目录,如下:

export HADOOP_COMMON_HOME=/usr/local/hadoop-2.7.1
export HADOOP_MAPRED_HOME=/usr/local/hadoop-2.7.1

5)测试是否安装成功,执行列出mysql中的数据库命令:

sqoop list-databases --connect jdbc:mysql://192.168.1.69:3306/test --username root --password 123456

注意:
--connect参数为MySQL数据库的连接地址。
--username参数为MySQL数据库的用户名。
--password参数为MySQL数据库的密码。

本例执行的操作结果如下:
输出结果为:

information_schema
im
mysql
oa
performance_schema
score
test

如果能成功列出MySQL中的数据库列表,说明安装成功。

二、使用Sqoop将MySQL中的表数据导入到HDFS

案例描述

将MySQL 中数据库test中的表user_info导入到HDFS中,表user_info中有两条数据,截图如下:


表user_info

操作步骤

  1. 启动Hadoop
start-all.sh
  1. 执行导入命令
sqoop import \
--connect jdbc:mysql://192.168.1.69/test?characterEncoding=UTF-8 \
--username root --password 123456 \
--table user_info \
--columns userId,userName,password,trueName,addedTime \
--target-dir /sqoop/mysql

从命令中可以看出,导入的HDFS目录为/sqoop/mysql。如果HDFS不存在此目录,则会新建该目录。

执行过程如下图:


image.png

图中出现的警告信息我们先忽略不计。从图中可以看出,导入过程只使用了map任务,没有使用reduce。其中输出了一句SQL语句:SELECT MIN(userId), MAX(userId) FROM user_info,至于为什么会这样输出,将在后续讲解。

  1. 查看导入结果
    执行下面命令,查看/sqoop/mysql目录下生成的文件:
hadoop fs -ls /sqoop/mysql

显示结果如下:

root@master:~# hadoop fs -ls /sqoop/mysql
Found 3 items
-rw-r--r--   2 root supergroup          0 2017-11-16 17:23 /sqoop/mysql/_SUCCESS
-rw-r--r--   2 root supergroup         33 2017-11-16 17:23 /sqoop/mysql/part-m-00000
-rw-r--r--   2 root supergroup         34 2017-11-16 17:23 /sqoop/mysql/part-m-00001

说明在HDFS文件系统中生成了三个文件_SUCCESS、part-m-00000、part-m-00001,而我们的数据正是存在后两个文件中。分别查看生成的后两个文件中的内容,可以看到MySQL中的每一行数据生成了一个文件:


查看每一个文件中的数据

执行下面命令,查看/sqoop/mysql/文件夹下所有文件的内容:

hadoop fs -cat /sqoop/mysql/*

显示结果如下:


image.png

三、使用Sqoop将HDFS中的数据导出到MySQL表

  1. 在MySQL数据库test中新建表user_info_2,字段如下:


    表user_info_2
  2. 将HDFS文件系统/sqoop/mysql/part-m-00000文件中的内容导出到表user_info_2中,导出命令如下:
sqoop export \
--connect jdbc:mysql://192.168.1.69:3306/test?characterEncoding=UTF-8 \
--username root \
--password 123456 \
--table user_info_2 \
--export-dir /sqoop/mysql/part-m-00000

导出成功后,刷新表user_info_2,查看其中的数据:


表user_info_2

可以看到,多了一条数据。当然,也可以将HDFS中/sqoop/mysql目录下的所有文件一起导出到表user_info_2中,只需将上述导出命令中的/sqoop/mysql/part-m-00000替换为/sqoop/mysql/*即可。

四、使用Sqoop将Mysql表数据导入到HBase

Mysql中的表user_info有两条数据,如下:


表user_info

1.启动hbase

start-hbase.sh

2.在hbase中新建表user_info,列族baseinfo

create 'user_info','baseinfo'

3.执行导入命令:

sqoop import \
--connect jdbc:mysql://192.168.1.69/test?characterEncoding=UTF-8 \
--username root --password 123456 \
--query "SELECT * FROM user_info WHERE 1=1 AND \$CONDITIONS" \
--hbase-table user_info \
--column-family baseinfo \
--hbase-row-key userId \
--split-by addedTime \
--m 2

反斜杠后面紧跟回车,表示下一行是当前行的续行。
参数说明:
--hbase-table 指定要导入的HBase中的表名。
--column-family 指定要导入的HBase表的列族。
--hbase-row-key 指定mysql中的某一列作为HBase表中的rowkey。
--split-by 指定mysql中的某一列作为分区导入。默认是主键。
--m 指定复制过程使用的map作业的数量。

sqoop是如何根据--split-by进行分区的?
假设有一张表test,sqoop命令中--split-by id --m 10。首先,sqoop会去查表的元数据,sqoop会向关系型数据库比如mysql发送一个命令:select max(id),min(id) from test。然后会把max、min之间的区间平均分为10分,最后10个并行的map去找数据库,导数据就正式开始了。

  1. 查看导入结果
    进入hbase shell,扫描user_info表中的数据,命令及执行效果如下:
hbase(main):001:0> scan 'user_info'
ROW                                       COLUMN+CELL                                                                                                             
 1                                        column=baseinfo:addedTime, timestamp=1510887550010, value=2017-06-21                                                    
 1                                        column=baseinfo:password, timestamp=1510887550010, value=123456                                                         
 1                                        column=baseinfo:trueName, timestamp=1510887550010, value=zhangsan                                                       
 1                                        column=baseinfo:userName, timestamp=1510887550010, value=hello                                                          
 2                                        column=baseinfo:addedTime, timestamp=1510887550110, value=2017-06-10                                                    
 2                                        column=baseinfo:password, timestamp=1510887550110, value=123456                                                         
 2                                        column=baseinfo:trueName, timestamp=1510887550110, value=lisi                                                           
 2                                        column=baseinfo:userName, timestamp=1510887550110, value=hello2                                                         
2 row(s) in 0.6870 seconds

可以看到,两条数据已经成功导入。
如果修改user_info中的数据,重新导入,则会更新替换hbase中相同rowkey对应行的数据。
注意的问题:如果mysql表中存在中文,导入到hbase表中的结果如下:
MySQL表:

表user_info

导入hbase后的结果:
image.png

中文变成了十六进制字符,我们把其中一个trueName值\xE5\xBC\xA0\xE4\xB8\x89转成中文,结果如下:
image.png

说明中文确实是转成了十六进制,我们从HBase中取数据时,将十六进制转成中文即可。

上方操作是提前在HBase中创建了相应的表,当然也可以提前不创建hbase表,在导入命令中指定创建表参数,如果表不存在则会创建表,如下:

sqoop import \
--connect jdbc:mysql://192.168.1.69/test \
--username root --password 123456 \
--query "SELECT * FROM user_info WHERE 1=1 AND \$CONDITIONS" \
--hbase-table user_info \
--column-family baseinfo \
--hbase-create-table \
--hbase-row-key userId \
--split-by addedTime \
--m 2

但是这种方式经过测试,出现bug,创建表不成功,原因是hbase中缺少Sqoop需要的API类。说明当前Sqoop版本与HBase版本不兼容。HBase我使用的是1.2.4版本。

如果大家有其它好的意见,欢迎在下方留言。

推荐阅读更多精彩内容