sqoop学习总结

1985 查看

sqoop是Apache的一个开源项目,属于Hadoop家族成员,核心功能是关系型数据库和Hadoop之间的数据转换与传输,从名字大概能够看出来:sql+hadoop=sqoop。sqoop目前发展处两个主版本,分别是sqoop1和sqoop2,sqoop1的版本号是1.4.x,sqoop2的版本号是1.99.x,这个编号有点儿意思,尚不清楚为什么这么遍。sqoop2和sqoop1是完全不兼容的,从软件构架到使用方法都是完全不同的。

sqoop1没有server的概念,其本身作为hadoop集群的client调用mapreduce完成工作,sqoop2则多了一层server的构架,其中集成了tomcat。用户通过client登录到sqoop2 shell,在这个shell中可以创建link,link是基于connector的,connector不需要创建,是sqoop2本身提供的,常用的connector包括hdfs-connector和jdbc-connector,分别对应HDFS和关系型数据库的链接,目前最新的1.99.6版本记得也支持kafka等connector。创建link的过程相当于是connector的实例化,将指定链接的地址、用户名密码等信息。有了link之后就可以创建job,job对应两个link,一个连接数据源一个连接数据目的地。job创建完成后并没有实际执行数据的传输,可以在任意时间启动创建成功的job。sqoop2的简单操作可以参考官方的这个小Demo:Sqoop5MinutesDemo

我的理解是:sqoop2 server的作用主要是保存和管理数据源连接信息、数据传输任务等,当然也提供了通过REST接口操作任务这样的高级功能。与sqoop1相比,sqoop2由于多了一个server层,在配置上要麻烦一些,启动server时经常会遇到一些奇怪的报错,即使成功启动server,后面的操作也可能遇到问题。目前我遇到一个问题是:成功创建link,成功创建job,启动job后卡死,不提示任何错误信息,日志文件中也看不到报错信息。这个问题最终也没有解决,所以我转向了sqoop1。

sqoop1要简单很多,减压到指定目录,/etc/profile中配置好HADOOP_COMMON_HOME和HADOOP_MAPRED_HOME环境变量就可以了,如果使用Hbase和Hive,也需要配置相应的环境变量。sqoop1使用上也很简单,就是shell命令的一般用法:命令行里敲sqoop+一些参数。我的使用场景是:把一台Postgresql数据库里的所有数据导入HDFS,下面是shell脚本:

#!/bin/bash
# transport data from PG to HDFS

# parse database names 
psql -h 10.192.33.55 -p 5432 -U postgres -c '\l' > ./database_info
cut -f 1 -d '|'  ./database_info | grep '^\s[a-zA-Z]' | sed s/[[:space:]]//g > database_names
rm -f  ./database_info

# get one database name every time and conduct the transformation by sqoop
cat ./database_names | while read DBNAME
do
if [[ $DBNAME != "postgres" && $DBNAME != "template0" && $DBNAME != "template1" ]]
then
  # make dir on HDFS for each database
  hadoop fs -mkdir /pgdata/$DBNAME
  # make code dir for each database
  mkdir ./gencode/$DBNAME
  SCHEMA=`echo $DBNAME | tr a-z A-Z`
  echo "start working on the database $DBNAME ********************************** "
  sqoop-import-all-tables --connect jdbc:postgresql://10.192.33.55:5432/$DBNAME \
        --direct --username postgres --password postgres --fields-terminated-by '|' \
        --enclosed-by "'" --escaped-by '\' --warehouse-dir /pgdata/$DBNAME -m 1 \
        --outdir ./gencode/$DBNAME   -- --schema $SCHEMA
  echo "finished working on database $DBNAME ==================================="
fi
done

我这里用的是sqoop-import-all-tables,用于导入(入是相对Hadoop来说的)一个库的所有表,如果需要导入单个表,可以用sqoop-import,然后用--table tablename指定要导入的表。除了导入整个表,sqoop也支持按照一定条件过滤导入数据,通过--where选项实现。下面解释下用脚本中用到的几个参数:

--connect: JDBC链接字符串
--username: 数据库用户名
--password: 数据库登录密码,这是显式指定密码的方式,也可以用-P实现交互式指定密码,还可以通过--password-file通过指定存有密码的文件加载密码。
--direct: 如果可以,绕过普通的jdbc方式链接,使用数据库各自特有的直接链接方式导数据,比如mysql的mysqldump,PG的psql。不是所有数据库产品都支持这种方式。
--fields-terminated-by: 字段之间的分隔符,默认为逗号。
--enclosed-by: 用来将各个字段包起来的字符,模式为空。 
--escaped-by: 转义符,比如我这里指定了分隔符'|'转义符'\',若字段内部出现'|'这个字符,就需要将其转义写成'\|'。
--warehouse-dir: 导入HDFS的文件存储目录
 -m: map任务数,一些表由于没有主键或者其他原因不能拆分用于多个map任务,我这里为了方便就全部指定了1个map任务。
--outdir: 导入过程中生成的java类保存目录
--schema: PG数据库模式,注意这类参数是传递给特定数据库连接工具的(不是sqoop),比如这里的是psql,所以需要出现在一个单独的“--”后面。

需要了解更多参数,请参考官方文档:SqoopUserGuide
导入的结果像下面这样,数据库里的每条记录对应文件里的一行:

'3663684'|'2016-05-12 08:06:00'|'2016-05-13 11:00:00'|'3'|'669'|'62.24'|'2016051200'|'187'
'3663685'|'2016-05-12 08:06:00'|'2016-05-13 17:00:00'|'3'|'669'|'9.71'|'2016051200'|'187'
'3663686'|'2016-05-12 08:06:00'|'2016-05-13 10:00:00'|'3'|'669'|'72.50'|'2016051200'|'187'
'3663687'|'2016-05-12 08:06:00'|'2016-05-13 04:00:00'|'3'|'669'|'1.00'|'2016051200'|'187'
'3663688'|'2016-05-12 08:06:00'|'2016-05-13 00:00:00'|'3'|'669'|'1.00'|'2016051200'|'187'
'3663689'|'2016-05-12 08:06:00'|'2016-05-13 09:00:00'|'3'|'669'|'110.57'|'2016051200'|'187'
'3663690'|'2016-05-12 08:06:00'|'2016-05-13 22:00:00'|'3'|'669'|'13.86'|'2016051200'|'187'
'3663691'|'2016-05-12 08:06:00'|'2016-05-13 08:00:00'|'3'|'669'|'109.19'|'2016051200'|'187'
'3663692'|'2016-05-12 08:06:00'|'2016-05-13 07:00:00'|'3'|'669'|'104.67'|'2016051200'|'187'

本篇就到此,后续再写一写导入Hbase以及Hive的方法,以及从Hadoop到sql的导出过程。