sqoop抽取mysql数据到hive

对于sqoop,我之前只是知道作用,并未对其进行研究。

最近设计基础架构的过程中,其中一环需要用到sqoop,用来导数据,涉及全量和增量,于是花时间学习了一下。

这里讨论sqoop导数据的全量和增量的功能,以及遇到的一些问题。

下面的案例是:使用sqoop将mysql的数据导入hive中,数据来自天气数据。

制造数据源

通过NiFi采集天气数据,保存到mysql。

具体的采集流程并非本文重点,这里就不做描述了,如有兴趣,可参考 NiFi数据流实例二。

创建mysql库表

修改mysql字符集

由于数据中有中文,防止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库表

创建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命令如下:

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或者lastmodifiedappend不能用于hive
--check-column 指定检查的列,也就是参考的增量列
--last-value 指定增量列的最新数据
--merge-key 指定参考的需要合并的列

注意一

在执行sqoop-job时,会提示输入密码,这个密码是源数据库的密码,这里就是mysql密码。

想要避免输入密码,有两种方法:

  1. 添加sqoop配置,在sqoop元数据中记录密码,这样就只需要在第一次执行sqoop-job的时候输入密码了,配置如下:

    sqoop.metastore.client.record.password
    true
    If true, allow saved passwords in the metastore.
    

  1. 使用--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")

解决

编辑/lib/security/java.policy,在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 作业,导入成功。

你可能感兴趣的:(Bigdata,mysql,hive,sqoop)