Skip to content

第10讲:如何通过Hivetez与Hadoop的整合快速实现大数据开发(下) ​

(3)启动 Hiveserver2 服务

如果有程序通过 JDBC/ODBC 接口连接 Hive 的话,就需要启动 Hiveserver2 服务,否则不需要启动。启动后会开启 10000 和 10002 两个端口,10000 端口用于 JDBC、ODBC 远程连接,10002 是 Hive 的 Web UI 界面,可以查看 Hive 执行的 SQL 以及任务运行状态。在 HiveDB 主机上启动 Hiveserver2 服务方式如下:

java
[hadoop@hivedb ~]$ hive --service hiveserver2

Hiveserver2 服务默认也是启动在前台,并且启动过程中可以通过 hiveconf 设置相应的自定义参数和值。要让 Hiveserver2 服务启动到后台,可执行如下命令:

java
[hadoop@hivedb ~]$ nohup hiveserver2 --hiveconf hive.server2.thrift.prot=10000 1>/opt/bigdata/hive/current/hiveserver.log 2> /opt/bigdata/hive/current/hiveserver.err &

通过这个方式,可以指定要启动的端口,并将标准日志和错误日志输出到了不同的文件中。注意,在启动 Hiveserver2 服务之前,Metastore 服务是必须要启动的。

5. Hive 常用 SQL 操作 ​

Hive 服务启动后,就可以在 Hive 的各个客户端执行查询分析操作了。这里以 Hive CLI 为例,介绍下 Hive 中常见的一些 SQL 操作。

(1)创建表、修改表、显示表

要创建一个表,可以执行如下 SQL 命令:

shell
hive> CREATE TABLE A (a INT, b STRING);

还可以创建一个带索引字段 ds 的表:

shell
hive> CREATE TABLE A (a INT, b STRING) PARTITIONED BY (dt STRING);

还可以创建一个分区表:

shell
hive> create table test_table (id string, ip string,pt string) partitioned by (dt string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

要显示所有表,可以执行如下 SQL 命令:

shell
hive> SHOW TABLES;

要更改表名,可以执行如下 SQL 命令:

shell
hive> ALTER TABLE A RENAME TO B

(2)映射数据到表中

Hive 表创建后,可以将本地数据或 HDFS 上的数据加载到 Hive 表中,常见的 load 数据方式有如下几个。

要加载本地文件数据,将本地文件导入 Hive 表中,可执行如下 SQL 命令:

shell
hive> LOAD DATA LOCAL INPATH '/examples/files/kv1.txt' OVERWRITE INTO TABLE A;

其中,/examples/files/kv1.txt 是本地操作系统下的路径。

要加载本地文件数据,将本地文件导入 Hive 表中,同时给定分区信息,可执行如下 SQL 命令:

shell
hive> LOAD DATA LOCAL INPATH '/examples/files/kv2.txt' OVERWRITE INTO TABLE A PARTITION (dt='2020-05-04');

要加载 HDFS 上的数据,将 HDFS 上的文件导入 Hive 表,同时给定分区信息,可执行如下 SQL 命令:

shell
hive> LOAD DATA INPATH '/user/mydata/kv3.txt' OVERWRITE INTO TABLE A PARTITION (dt='2020-05-04');

通过上面执行的 SQL 可知,如果有 local 这个关键字,则这个路径为本地文件系统路径;如果省略掉 local 关键字,那么这个路径是分布式文件系统 HDFS 中的路径。

注意,Hive 中默认的字段分隔符为 ASCII 码的控制符 \001,若在建表的时候没有指明分隔符,那么 load 文件的时候文件的分隔符需要是 '\001';若文件分隔符不是 '001',程序不会报错,但表查询的结果会全部为 'null';如果要造数据测试的话,用 Vi 打开文件,按键 Ctrl+V,然后再 按键 Ctrl+A, 可以输入这个控制符 \001。

要将 Hive 表数据导入到本地 A_table 目录中,可执行如下 SQL 命令:

shell
hive> insert overwrite local directory '/home/hadoop/A_table' row format delimited fields terminated by '\t'   select * from A;

(3)添加、删除、清空分区

要给 Hive 表添加分区,可执行如下 SQL 命令:

shell
hive> alter table test_table add if not exists partition(dt='2020-05-04') ;

要删除 Hive 表分区,可执行如下 SQL 命令:

shell
hive> alter table test_table drop if exists partition(dt='2020-05-04') ;

要清空 Hive 表分区数据,可执行如下 SQL 命令:

shell
hive> truncate table test_table partition(dt='2020-05-04') ;

对 Hive SQL 我先介绍这么多,作为大数据平台的运维工程师,不需要对 Hive SQL 有多么高深的了解,只需要掌握一些基础的操作就可以了,这些操作可以帮助我们排查问题。

6. Beeline 的使用 ​

启动了 Hiveserver2 服务后,就可以使用 Beeline 工具来连接 Hiveserver2 服务。这里我们将 HiveDB 上的 Hive 安装目录复制到 Hiveclient 主机,然后将 Hiveclient 作为运行 hive 命令的客户端。

Beeline 的使用很简单,一般只需要两个参数即可。

  • -n:连接时使用的用户名,这个用户是允许代理的用户,需要经过授权才能连接。
  • -u:用于 JDBC URL 连接的字串。

下面是通过 beeline 连接 hive 的一个例子:

java
[hadoop@hiveclient ~]$ beeline -u jdbc:hive2://yarnserver:10000 -n gaojf

上面命令运行成功后,就会进入 beeline 命令行下,如下图所示:

在这个命令中,我使用了 gaojf 这个用户,这是一个操作系统下的用户,如果不指定 -n 参数,那么 beeline 会默认使用 anonymous 这个用户。由于这里没有开启 beeline 的安全认证机制,所以不需要指定用户的密码。在这个步骤中,可能会出现如下问题:

java
20/05/02 17:56:07 [main]: WARN jdbc.HiveConnection: Failed to connect to yarnserver:10000
Error: Could not open client transport with JDBC Uri: jdbc:hive2://yarnserver:10000: Failed to open new session: java.lang.RuntimeException: org.apache.hadoop.security.AccessControlException: Permission denied: user=gaojf, access=EXECUTE, inode="/tmp":hadoop:supergroup:drwxrwx---

这个错误的意思是 beeline 要在 HDFS 上的 /tmp/hive 目录下以 gaojf 用户身份创建一个 gaojf 目录,但 /tmp 这个目录下只有 hadoop 用户和 supergroup 组的读写执行权限,没有其他用户或组的权限,这是 HDFS 上典型的权限问题。HDFS 文件系统的权限跟 Linux 下文件系统的权限实现机制是一样的,要解决这个问题,最简单的方式是将 HDFS 上 /tmp 目录权限修改为 777 即可,也就是执行如下命令:

java
[hadoop@yarnserver conf]$ hadoop  fs  -chmod 777  /tmp

授权成功后,再次执行 beeline 进入命令行就不会出现此错误了。

还有一种方式,就是在 namenode 上创建 gaojf 这个用户,然后将此用户加入到 supergroup 这个组中,这样,只需要保证 HDFS 上的 /tmp 目录权限是 775 就可以了。由此可知,HDFS 上的权限认证默认走的是 Linux 下的权限认证方法。

此外,Hive 中每个用户在执行分析任务时,还需要用到另一个 HDFS 目录,那就是 /user,每个用户都会在执行分析任务时把相关依赖包放到"/user/用户名"这个路径下。因此,也需要将 /user 目录权限设置为 775,然后将每个用户加到 supergroup 中。

接着, 我们在 beeline 命令行执行一个简单的 SQL 查询,看看是否正常,操作如下图所示:

这是执行一个 select count 操作,统计 test_table 这张表有多少行数据,执行 select count(1) 查询的话,就会走 mapreduce;而如果执行 select * from test_table 的话,是不会走 mapreduce 的,这点需要注意。

上面执行的这个 select 操作,等了好久都没有执行结果,看来应该有问题,于是查看 hive 的日志文件 hive.log(默认路径在 /tmp/hadoop/hive.log),发现了如下异常:

org.apache.hadoop.security.authorize.AuthorizationException: User: hadoop is not allowed to impersonate gaojf

这个错误其实还是一个权限问题,这就要说下 Hadoop 中的 ProxyUser 机制,Hadoop2.0 版本开始支持 ProxyUser,所谓 ProxyUser 就是使用 User A 的用户认证信息,以 User B 的名义去访问 Hadoop 集群,对应 Hadoop 集群来说它认为是 User B 在访问集群,而对集群访问请求的权限验证(如 HDFS 文件系统权限、Yarn 队列权限)也是以 User B 用户的角色实现的,这里的 User A 被认为是 SuperUser,而 User B 就是 ProxyUser。

要实现 ProxyUser 机制,需要在 NameNode 和 ResourceManager 的 core-site.xml 中添加代理权限相关配置,注意添加的配置有如下内容:

html
<property>
<name>hadoop.proxyuser.userA.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.userA.users</name>
<value>user1,user2</value>
</property>
<property>
<name>hadoop.proxyuser.userA. groups</name>
<value>group1,group2</value>
</property>

其中:

  • hadoop.proxyuser.userA.hosts 表示配置 userA 允许通过代理访问的主机节点;
  • hadoop.proxyuser.userA.users 表示配置 userA 允许代理的用户;
  • hadoop.proxyuser.userA. groups 表示配置 userA 允许代理的用户所属组。

这里的 userA 可以理解为上面所说的 SuperUser,而这段配置的含义是允许用户 userA 在任意主机节点,代理用户 user1 和 user2、代理用户组 group1 和 group2,进而实现对集群的访问。

对于 ProxyUser 机制来说,hadoop.proxyuser.userA.hosts 是必须要配置的,hadoop.proxyuser.userA.users 和 hadoop.proxyuser.userA. groups 至少需要配置一个。这几个配置项的值都可以使用"*"来表示允许所有的主机、用户或用户组。

结合上面的报错提示,我们添加如下内容到 NameNode 和 ResourceManager 的 core-site.xml 中。

html
<property>
<name>hadoop.proxyuser.hadoop.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hadoop. groups</name>
<value>hadoop</value>
</property>

这段配置的含义是允许 hadoop 用户在任意主机节点,代理用户组 hadoop 访问集群。这个配置修改后,并不会马上生效,可以执行以下命令,分别将信息更新到 namenode 和 resourcemananger 上。

java
[hadoop@namenodemaster ~]$  hdfs dfsadmin --refreshSuperUserGroupsConfiguration
[hadoop@yarnserver conf]$ yarn rmadmin --refreshSuperUserGroupsConfiguration

最后,还需要做一个操作,那就是将 gaojf 用户加到 Hadoop 这个组中,此操作必须在 Hadoop 集群的 yarnserver 主机上执行,因为 yarn 的权限认证是在 resourcemananger 节点上,执行操作如下:

sql
[root@yarnserver ~]# useradd gaojf
[root@yarnserver ~]# usermod  -G hadoop gaojf
[root@yarnserver ~]# id gaojf
uid=1002(gaojf) gid=1002(gaojf) 组=1002(gaojf),1001(hadoop)

现在,我们再来执行刚才的那个 select 查询 SQL,如下图所示:

可以看到,很快就得到了查询结果,因为这个查询是走了 MapReduce,还可以在 Yarn 的 8088 端口查看执行状态,如下图所示:

从上图中,可以看出这个任务执行的用户是 gaojf,任务类型是 MapReduce,提交在 default 队列中。

Hive 运行引擎 MR、Tez 配置 ​

Tez 是一个构建在 Hive 之上的支持复杂 DAG 任务(有向无环图)的数据处理引擎,它把 MapReduce 的执行过程拆分成若干个子过程。同时可以把多个有依赖的 MapReduce 任务组合成一个较大的 DAG 任务,这种逻辑减少了 MapReduce 中间数据频繁写入 HDFS 上的性能问题,同时,通过合理组合其子过程,进而大幅提升了 MapReduce 作业的性能。

Hive 支持多个计算引擎,常见的有 Hive On MapReduce、Hive On Tez 及 Hive On Spark。Hive On MapReduce 是默认的运行引擎,主要处理离线数据,Hive On Tez 是支持 DAG 作业(有向无环图)的计算引擎,而 Hive On Spark 主要是基于内存计算的引擎。现在 Hive On MapReduce 由于运行效率低下,很少使用了,Hive On Tez 是目前的主流。

Tez 在执行小任务时,速度是 Hive On MapReduce 模式的 2~3 倍,而在执行大型分析任务时,速度是 Hive On MapReduce 的 8~10 倍左右。

1. 源码编译安装 Tez ​

目前 Tez 发布的最新版本是 0.9.2,此版本是基于 Hadoop 2.7.2 的,而我们这里的环境是 Hadoop 3.2.1 及 Hive 3.1.2。所以 Tez 官方发布的二进制版本无法使用,需要通过源码重新编译,经过测试,0.9.x 版本无法兼容 Hadoop3.2.1,主要是 Google Guava 版本冲突,Tez0.9.x 默认的 Guava 11.0.2 版本,而 Hadoop3.2.1 自带的 Guava 版本为 27.0,所以不能兼容。要解决这个问题,需要点击这里下载最新的 Tez 0.10.1 版本,此版本兼容 Hadoop3.2.1,将 Tez 源码下载后,执行下面步骤进行安装:

java
[hadoop@ hivedb  ~]$unzip tez-master.zip
[hadoop@hivedb  ~]$cd tez-master
[hadoop@hivedb tez-master]$/usr/local/maven/bin/mvn install -Dhadoop.version=3.2.1 -DskipTests -Dmaven.javadoc.skip=true

上面的 -Dhadoop.version 是指定 Hadoop 的版本,根据你的环境来指定即可。Tez 下默认的依赖软件版本可通过查看源码目录下的 pom.xml 文件。

要编译 Tez,需要 maven 工具,并且编译安装 Tez 时间会比较长,编译安装完成后,会在源码目录下的 tez-dist/target/ 中找到编译好的 Tez,其中,有两个版本,即 tez-0.10.1-SNAPSHOT-minimal.tar.gz 和 tez-0.10.1-SNAPSHOT.tar.gz,这两个就是我们需要的 Tez 程序。

2. 配置 Tez 与 Hive 整合 ​

Tez 与 Hive 的整合需要三个步骤,分别是上传 Tez 的 jar 包到 HDFS、配置 Hive 及 Hive 中 Tez 包的引入,下面依次说明。

首先,将上面编译好的 tez-0.10.1-SNAPSHOT.tar.gz 包进行解压,然后将解压后的文件放到一个目录下,最后上传到 HDFS 上,操作如下:

java
[hadoop@hivedb  target]$mkdir tez-0.10.1
[hadoop@ hivedb  target]$ tar zxvf tez-0.10.1-SNAPSHOT.tar.gz -C tez-0.10.1
[hadoop@ hivedb  target]$ hadoop  fs  -mkdir  /tez
[hadoop@ hivedb  target]$hadoop  fs -put tez-0.10.1 /tez

接着,在 Hive 配置目录 /opt/bigdata/hive/current/conf 中添加一个 tez-site.xml 文件,内容如下:

html
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
      <name>tez.lib.uris</name>   
      <value>${fs.defaultFS}/tez/tez-0.10.1,${fs.defaultFS}/tez/tez-0.10.1/lib</value>
</property>
<property>
    <name>tez.lib.uris.classpath</name>
    <value>${fs.defaultFS}/tez/tez-0.10.1,${fs.defaultFS}/tez/tez-0.10.1/lib</value>
</property>
<property>
     <name>tez.use.cluster.hadoop-libs</name>
     <value>true</value>
</property>
<property>
     <name>tez.am.resource.memory.mb</name>
     <value>2048</value>
</property>
<property>
     <name>tez.am.resource.cpu.vcores</name>
     <value>2</value>
</property>
</configuration>

在这个配置中,有三个参数需要特别注意,其中,tez.lib.uris 用来指定 Hive 运行依赖的 tez 包,这个路径是 HDFS 上的路径、tez.lib.uris.classpath 用来指定 Hadoop 依赖的相关包,tez.use.cluster.hadoop-libs 表示是否使用 Hadoop 自身的 lib 包,这里设置为 true。

另外,还需要修改 hive-site.xml 文件,添加如下内容:

html
<property>
    <name>hive.execution.engine</name>
    <value>tez</value>
</property>

这个配置是设置 Hive 的默认引擎为 tez,设置完成后,Hive 配置就结束了,最后,还需要在 HiveDB 上部署 Tez 本地程序。将上面源码编译好的 tez-0.10.1-SNAPSHOT-minimal.tar.gz 包解压到 /opt/bigdata/tez 目录下即可,操作如下:

java
[hadoop@hivedb bigdata]$ mkdir  -p /opt/bigdata/tez/tez-0.10.1
[hadoop@hivedb bigdata]$tar zxvf tez-0.10.1-SNAPSHOT-minimal.tar.gz -C /opt/bigdata/tez/tez-0.10.1
[hadoop@hivedb bigdata]$cd /opt/bigdata/tez
[hadoop@hivedb tez]$ ln -s tez-0.10.1 current

Tez 包部署完成后,找到 /opt/bigdata/hive/current/conf/hive-env.sh 文件,添加以下内容,将本地 tez 包引入 hive,内容如下:

java
export HIVE_HOME=/opt/bigdata/hive/current
export TEZ_HOME=/opt/bigdata/tez/current
export TEZ_JARS=""
for jar in `ls $TEZ_HOME |grep jar`; do
    export TEZ_JARS=$TEZ_JARS:$TEZ_HOME/$jar
done
for jar in `ls $TEZ_HOME/lib`; do
    export TEZ_JARS=$TEZ_JARS:$TEZ_HOME/lib/$jar
done
export HADOOP_CLASSPATH=${TEZ_JARS}/*:${TEZ_JARS}/lib/*

到此为止,Tez 整合到 Hive 配置完成了。

3. 测试 Tez 功能 ​

这里我在 Hiveclient 主机上进行Tez 功能测试,由于在 Hive 基础上进行了 Tez 整合,所以还需要将 HiveDB 主机上的 Hive 安装目录以及 Tez 安装目录都复制到 Hiveclient 主机上,然后做如下功能测试。操作如下:

java
[hadoop@hiveclient conf]$ beeline -u jdbc:hive2://yarnserver:10000 -n gaojf
0: jdbc:hive2://yarnserver:10000> create table ad1 (id string, ip string,pt string) partitioned by (dt string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
0: jdbc:hive2://yarnserver:10000> LOAD DATA LOCAL INPATH '/home/hadoop/demo100.txt' OVERWRITE INTO TABLE ad1 PARTITION (dt='2020-05-06');
0: jdbc:hive2://yarnserver:10000> select count(1) from ad1;

这个步骤中通过 Beeline 链接 Hiveserver2,被代理的用户是 gaojf,也可以是任意一个用户;然后创建了一个表 ad1,通过 load 方法将本地文件导入到 ad1 表中;最后执行 select 查询 SQL 获取此表记录数,select 查询过程如下图所示:

上图就是 Tez 的执行过程,可以看到执行这个查询花费了 16.533 秒,而目前的计算引擎是 Tez。可以通过"set hive.execution.engine=mr;"切换计算引擎为 MR,然后再次执行 select 查询,结果如下图所示:

可以看到,通过 MR 引擎执行这个查询花费了 31.201 秒,比 Tez 慢了近一倍,这就是 Tez 的优势。

要查看任务的详细运行状态信息,可查看 yarnserver 的 8088 端口,如下图所示:

从上图可以看出,任务 application_1588733821232_0066 使用的是 Tez 引擎,还有此任务使用的队列、CPU、内存等资源信息。

总结 ​

本课时注意讲解了 Hive 与 Hadoop 的整合,以及如何将 Tez、Beeline 整合到 Hive 中。重点是 Hive 与其他组件的整合实现快速开发,作为大数据运维工程师,Hive 的部署与整合是必须要掌握的内容。