对于sqoop,我之前只是知道作用,并未对其进行研究。
最近设计基础架构的过程中,其中一环需要用到sqoop,用来导数据,涉及全量和增量,于是花时间学习了一下。
这里讨论sqoop导数据的全量和增量的功能,以及遇到的一些问题。
下面的案例是:使用sqoop将mysql的数据导入hive中,数据来自天气数据。
通过NiFi采集天气数据,保存到mysql。
具体的采集流程并非本文重点,这里就不做描述了,如有兴趣,可参考 NiFi数据流实例二。
由于数据中有中文,防止mysql出现乱码问题,这里需要把mysql的字符集修改成utf8。
根据我的了解,mysql还有一个utf8mb4,具体区别请自行查阅资料。
修改/etc/my.cnf
文件,对应添加如下内容:
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
[mysql]
default-character-set = utf8
[mysql.server]
default-character-set = utf8
[mysqld_safe]
default-character-set = utf8
[client]
default-character-set = utf8
保存之后,重启mysql:systemctl restart mysqld
。
创建数据库:
CREATE DATABASE xwd CHARACTER SET utf8 COLLATE utf8_general_ci;
创建表:
CREATE TABLE IF NOT EXISTS xwd.tianqi (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
insert_time timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
location VARCHAR(100),
loc datetime,
cloud VARCHAR(100),
cond_txt VARCHAR(100),
tmp VARCHAR(100),
wind_dir VARCHAR(100)
)CHARACTER SET utf8 COLLATE utf8_general_ci;
插入数据示例:
INSERT INTO xwd.tianqi(location,loc,cloud,cond_txt,tmp,wind_dir) VALUES('北京','2019-03-09 08:58','91','阴','8','东南风');
这些工作完成后,就可以设计NiFi的数据流了,然后启动数据流,天气数据就会不断的插入mysql的表中了。
到这里,数据源就准备完成了。
创建hive库表,用来存储来自mysql的数据。
sqoop可以自行创建hive表,不过我不太喜欢。
创建数据库:
create database xwd;
创建表:
CREATE TABLE xwd.tianqi(
id int,
insert_time timestamp,
location string,
loc timestamp,
cloud string,
cond_txt string,
tmp string,
wind_dir string)
partitioned by (dt string)
STORED AS TEXTFILE;
这里以日期分区。
全量导入,只在第一次导入数据时使用,也就是说是一次性的。
sqoop命令如下:
sqoop import \
--connect jdbc:mysql://192.168.1.195:3306/xwd \
--username root \
--password xwd123456 \
--table tianqi \
--delete-target-dir \
--hive-import \
--hive-table xwd.tianqi \
--hive-partition-key dt \
--hive-partition-value `date +%F`
注意,使用HDFS的管理员用户执行命令,否则会出现没有权限访问的错误。
参数说明:
参数 | 说明 |
---|---|
--connect |
指定jdbc url |
--username |
数据库用户名,这里是mysql的用户名 |
--password |
数据库用户密码,这里是mysql的用户密码 |
--table |
要导出的表名,这里是mysql表名 |
--delete-target-dir |
删除hdfs上的output目录,否则再次执行导入命令,会报错 |
--hive-import |
指定导入hive |
--hive-table |
要导入的hive表 |
--hive-partition-key |
hive的分区字段 |
--hive-partition-value |
分区字段的值,这里是获取的系统时间 |
增量导入数据,需要定期导入,所以使用sqoop-job功能记录命令,然后,设置定时执行sqoop-job。
创建sqoop-job的命令如下:
sqoop job --create tianqi_incremental_import -- import \
--connect jdbc:mysql://192.168.1.195:3306/xwd \
--username root \
--password xwd123456 \
--table tianqi \
--incremental lastmodified \
--check-column insert_time \
--last-value "2019-03-09 14:59:21" \
--merge-key id \
--hive-import \
--hive-table xwd.tianqi \
--hive-partition-key dt \
--hive-partition-value `date +%F`
执行sqoop-job
sqoop job --exec tianqi_incremental_import
使用HDFS的管理员用户执行命令,否则会出现没有权限访问的错误。
新增参数说明:
参数 | 说明 |
---|---|
--incremental |
指定增量模式,可选append 或者lastmodified ,append 不能用于hive |
--check-column |
指定检查的列,也就是参考的增量列 |
--last-value |
指定增量列的最新数据 |
--merge-key |
指定参考的需要合并的列 |
在执行sqoop-job时,会提示输入密码,这个密码是源数据库的密码,这里就是mysql密码。
想要避免输入密码,有两种方法:
sqoop.metastore.client.record.password
true
If true, allow saved passwords in the metastore.
--password-file
参数,指定密码文件。--last-value
这个参数只需要指定一次即可,也就是说,只需要设置第一次增量导入的位置,一般是最新数据的某个字段(通常是时间戳),然后sqoop会在之后的增量导入自动识别最新的位置,因为sqoop会把信息存储在元数据中。
sqoop的元数据一般在执行用户的用户目录下,名为
.sqoop
。
在使用sqoop时遇到的一些问题记录如下。
hdfs上的output目录已存在。
org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://192.168.1.195:8020/user/hdfs/tianqi already exists
在sqoop命令中追加参数:--delete-target-dir
。
Java jre的问题。
ERROR Could not register mbeans java.security.AccessControlException: access denied ("javax.management.MBeanTrustPermission" "register")
编辑
,在grant {}
里追加内容:
grant {
permission javax.management.MBeanTrustPermission "register";
};
Hadoop的kms问题。
ERROR hdfs.KeyProviderCache: Could not find uri with key [dfs.encryption.key.provider.uri] to create a keyProvider !!
未解决,据说不启用 KMS 的话,不用理会这个问题。
sqoop和hive使用的jar包版本不一致。
ERROR exec.TaskRunner: Error in executeTask
java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.ObjectMapper.readerFor(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/ObjectReader;
有三个jar包版本不一致:jackson-annotations-2.6.0.jar,jackson-core-2.6.5.jar,jackson-databind-2.6.5.jar。
将$SQOOP_HOME/lib/
下的这三个jar文件备份到其他地方,再把$HIVE_HOME/lib/
下的三个对应文件拷贝至 $SQOOP_HOME/lib
目录中,重新运行sqoop 作业,导入成功。