用Sqoop进行关系型数据库与Hadoop生态的数据传输:从MySQL到HBase

Task:

建立2个节点,每个节点都运行一个mysql实例,并分别将附件里面的imdb和烂番茄的数据导入到mysql中。在建立一个包括5个节点的Hbase,通过sqoop把mysql的内容都导入到Hbase中,成为唯一的一张表。

因为imdb和烂番茄的表定义是不一样的。

IMDB:

1
2
>"Id","Name","YearRange","ReleaseDate","Director","Creator","Cast","Duration","RatingValue","ContentRating","Genre","Url","Description"
>

烂番茄

1
2
>"Id","Name","Year","Release Date","Director","Creator","Actors","Cast","Language","Country","Duration","RatingValue","RatingCount","ReviewCount","Genre","Filming Locations","Description"
>

请使用sqoop/hadoop进行schema matching,不需要record matching,转化为统一的表结构(自行定义)。

Sqoop配置

服务器环境:

  • Ubuntu 16.04
  • Hadoop: 2.7.6
  • hbase: 1.4.8

配置参考tutorialspoint.

安装Sqoop

下载解压

Sqoop官网找到镜像下载压缩包, 解压到/usr/local,并重命名.

1
2
tar zxvf sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /usr/local
mv /usr/local/sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz /usr/local/sqoop

修改环境

修改~/.bashrc, 添加相关的路径.

1
2
#Sqoop
export SQOOP_HOME=/usr/lib/sqoop export PATH=$PATH:$SQOOP_HOME/bin

修改配置

根据模板创建并修改conf/sqoop-env.sh, 添加相关的路径.

1
2
3
cd $SQOOP_HOME
# 创建sqoop-env.sh
mv sqoop-env-template.sh sqoop-env.sh

打开文件, 添加下列路径.

1
2
3
export HADOOP_COMMON_HOME=/usr/local/hadoop 
export HADOOP_MAPRED_HOME=/usr/local/hadoop
export HBASE_HOME=/usr/local/hbase

下载mysql connector

NTU的镜像下载最新的java connector并解压, 将解压后文件中的jar包复制到$SQOOP_HOME/lib.

安装MySQL

通过apt下载mysql的server和client.

1
2
3
apt-get install mysql-server
apt install mysql-client
apt install libmysqlclient-dev

Sqoop数据传输

将数据导入MySQL

导入mysql的过程主要有两部分: 其一是根据csv的header去建表;其二是导入csv文件到表中.

通过csv自动生成table scheme

mysql不支持从一个data scheme的文件自动识别对应的table scheme, 所以在导入csv文件之前,必须先手动创建能和csv文件的header对应的表. 好在通过stackoverflow的帖子找到了一个可以根据csv生成table schema的工具.

建表并导入csv

建表

  • 创建imdb的表
1
create table `imdb` (`id` varchar(153), `name` varchar(146), `yearrange` varchar(14), `releasedate` varchar(39), `director` text, `creator` varchar(103) null, `cast` text null, `duration` varchar(13) null, `ratingvalue` varchar(13) null, `contentrating` varchar(135), `genre` varchar(130) null, `url` varchar(127), `description` text null);
  • 创建烂番茄的表
1
create table `rt` (`id` varchar(153), `name` varchar(146) null, `year` int null, `releasedate` varchar(39) null, `director` varchar(325) null, `creator` varchar(103) null, `actors` varchar(126) null, `cast` text null, `language` varchar(86) null, `country` varchar(102) null, `duration` varchar(13) null, `ratingvalue` float(8, 2) null, `ratingcount` varchar(10) null, `reviewcount` varchar(21) null, `genre` varchar(130) null, `filming_locations` varchar(137) null, `description` text null);

导入csv

:bug: 遇到报错不能导入csv, 后来查明是mysql文件权限的问题,将csv文件移到/var/lib/mysql-files/下, 解决.

  • 导入imdb
1
load data infile '/var/lib/mysql-files/data/imdb.csv' into table imdb fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\n';
  • 导入烂番茄
1
load data infile '/var/lib/mysql-files/data/rotten_tomatoes.csv' into table rt fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\n';

从mysql导入hbase

sqoop传输

我们用sqoop import将数据从mysql导入hbase中. 就这么一个命令的事儿除了很多差错.

1
sqoop import --connect jdbc:mysql://localhost/hw1 --username root -P --table imdb --m 1 --hbase-create-table

最开始,我们遇到了无法接受包的错误, 具体报错如下:

参考网上的解答, 我们尝试修改了wait_timeoutbind_address这两个流传度最广泛的解决方案, 均没有效果.

后来开始想到也许是我的sqoop命令错了, 想到sqoop会将数据送到hbase集群, 我将localhost改成了ip名:

1
sqoop import --connect jdbc:mysql://host0/hw1 --username root -P --table imdb --m 1 --hbase-create-table

这时换了个报错:

这个mysql的权限问题很好解决, 我们修改了user表:

1
2
mysql>update user set host = '%' where user = 'root';
mysql>select host, user from user;

修改结果如下:

并成功完成了传输.

用sqoop的query进行合并

我们在sqoop命令中添加了–query的参数, 通过它来实现schema match的需求:

1
2
3
4
5
6
7
8
9
10
11
sqoop import \
--connect jdbc:mysql://host0/hw1 \
--username root \
--password '000000' \
--query "select imdb.*, rt.* from imdb join rt on (imdb.name = rt.name) where \$CONDITIONS" \
--split-by id \
--hbase-table movie \
--hbase-create-table \
--hbase-row-key name \
--column-family name \
--m 1

:bug: 不过这样会遇到报错:

也就是出现了重复列, 无奈只能手动将*挨个替换成不重复的列:

1
2
3
4
5
6
7
8
9
10
11
sqoop import \
--connect jdbc:mysql://host0/hw1 \
--username root \
--password '000000' \
--query "select imdb.id as iid,imdb.name,imdb.yearrange,imdb.releasedate,imdb.director,imdb.creator,imdb.cast,imdb.duration,imdb.ratingValue,imdb.contentRating,imdb.genre,imdb.url,imdb.description,rt.id,rt.year,rt.actors,rt.language,rt.country,rt.ratingCount,rt.reviewCount,rt.filming_locations from imdb join rt on (imdb.name = rt.name) where \$CONDITIONS" \
--split-by iid \
--hbase-table movie \
--hbase-create-table \
--hbase-row-key name \
--column-family region \
--m 1

:bug: 不过命令修改之后我们还是遇到了reconnect的错误:

参考cloudera上的帖子, 我们重启了yarn:

1
start-yarn.sh

sqoop顺利执行, 完成任务:

If it helps, you may buy me a cup of coffee plz.
0%