注:本文是对 https://www.bilibili.com/video/BV1CU4y1N7Sh 的实践。

关于如何搭建Hadoop集群,请参考我另一篇文档。

环境

  • CentOS 7.7
  • JDK 8
  • Hadoop 3.3.0
  • Hive 3.1.2

准备

确认Hadoop的 etc/hadoop/core-site.xml 文件包含如下配置:

<!-- 整合hive 用户代理设置 -->
<property>
    <name>hadoop.proxyuser.root.hosts</name>
    <value>*</value>
</property>

<property>
    <name>hadoop.proxyuser.root.groups</name>
    <value>*</value>
</property>

确认Hadoop集群运行良好。

安装MySQL

只需在node1上安装。步骤如下:

查询并卸载Centos7自带的mariadb:

[root@node1 ~]# rpm -qa|grep mariadb
mariadb-libs-5.5.64-1.el7.x86_64
[root@node1 ~]# rpm -e mariadb-libs-5.5.64-1.el7.x86_64 --nodeps
[root@node1 ~]# 

再次查询,确认已卸载。

把MySQL的压缩包 mysql-5.7.29-1.el7.x86_64.rpm-bundle.tar 放到 /export/software/mysql 目录下,并解压:

tar -xvf mysql-5.7.29-1.el7.x86_64.rpm-bundle.tar

安装 libaio

yum -y install libaio

安装MySQL:

rpm -ivh mysql-community-common-5.7.29-1.el7.x86_64.rpm mysql-community-libs-5.7.29-1.el7.x86_64.rpm mysql-community-client-5.7.29-1.el7.x86_64.rpm mysql-community-server-5.7.29-1.el7.x86_64.rpm 

初始化MySQL:

mysqld --initialize

更改属性:

chown mysql:mysql /var/lib/mysql -R

启动MySQL:

systemctl start mysqld.service

查看密码:

cat  /var/log/mysqld.log

在结果中查找如下内容:

2022-12-12T06:21:57.689895Z 1 [Note] A temporary password is generated for root@localhost: d&O_ayymf5eA

本例中,密码为 d&O_ayymf5eA

登录MySQL:

mysql -u root -p

输入刚才的密码,进入MySQL命令行。

更改密码为 hadoop

alter user user() identified by "hadoop";

授权远程访问:

use mysql;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'hadoop' WITH GRANT OPTION;
FLUSH PRIVILEGES;

退出MySQL命令行:

 exit;

注:启动/停止/查看mysqld状态:

systemctl stop mysqld
systemctl status mysqld
systemctl start mysqld

设置开机自启动:

systemctl enable  mysqld

查看设置开机自启动是否成功:

[root@node1 mysql]# systemctl list-unit-files | grep mysqld
mysqld.service                                enabled 
mysqld@.service                               disabled

部署

把Hive的压缩包放到node1的 /export/server 目录并解压:

tar -zxvf apache-hive-3.1.2-bin.tar.gz 

解决Hive与Hadoop之间guava版本差异:

cd /export/server/apache-hive-3.1.2-bin/
rm -rf lib/guava-19.0.jar
cp /export/server/hadoop-3.3.0/share/hadoop/common/lib/guava-27.0-jre.jar ./lib/

apache-hive-3.1.2-bin/conf 目录下的 hive-env.sh.template 文件改名为 hive-env.sh ,并修改该文件,添加如下内容:

export HADOOP_HOME=/export/server/hadoop-3.3.0
export HIVE_CONF_DIR=/export/server/apache-hive-3.1.2-bin/conf
export HIVE_AUX_JARS_PATH=/export/server/apache-hive-3.1.2-bin/lib

在同一目录下新建 hive-site.xml 文件,内容如下:

<configuration>
<!-- 存储元数据mysql相关配置 -->
<property>
	<name>javax.jdo.option.ConnectionURL</name>
	<value>jdbc:mysql://node1:3306/hive3?createDatabaseIfNotExist=true&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8</value>
</property>

<property>
	<name>javax.jdo.option.ConnectionDriverName</name>
	<value>com.mysql.jdbc.Driver</value>
</property>

<property>
	<name>javax.jdo.option.ConnectionUserName</name>
	<value>root</value>
</property>

<property>
	<name>javax.jdo.option.ConnectionPassword</name>
	<value>hadoop</value>
</property>

<!-- H2S运行绑定host -->
<property>
    <name>hive.server2.thrift.bind.host</name>
    <value>node1</value>
</property>

<!-- 远程模式部署metastore metastore地址 -->
<property>
    <name>hive.metastore.uris</name>
    <value>thrift://node1:9083</value>
</property>

<!-- 关闭元数据存储授权  --> 
<property>
    <name>hive.metastore.event.db.notification.api.auth</name>
    <value>false</value>
</property>
</configuration>

把MySQL的JDBC驱动 mysql-connector-java-5.1.32.jar 放到Hive的 lib 目录下。

初始化元数据:

bin/schematool -initSchema -dbType mysql -verbos

注:如果前一步里没有更新 guava-19.0.jarguava-27.0-jre.jar ,则这里会报一个 NoSuchMethodError 的错误,如下:

[root@node1 apache-hive-3.1.2-bin]# bin/schematool -initSchema -dbType mysql -verbos
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/export/server/apache-hive-3.1.2-bin/lib/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/export/server/hadoop-3.3.0/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Exception in thread "main" java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;Ljava/lang/Object;)V
        at org.apache.hadoop.conf.Configuration.set(Configuration.java:1380)
        at org.apache.hadoop.conf.Configuration.set(Configuration.java:1361)
        at org.apache.hadoop.mapred.JobConf.setJar(JobConf.java:536)
        at org.apache.hadoop.mapred.JobConf.setJarByClass(JobConf.java:554)
        at org.apache.hadoop.mapred.JobConf.<init>(JobConf.java:448)
        at org.apache.hadoop.hive.conf.HiveConf.initialize(HiveConf.java:5141)
        at org.apache.hadoop.hive.conf.HiveConf.<init>(HiveConf.java:5104)
        at org.apache.hive.beeline.HiveSchemaTool.<init>(HiveSchemaTool.java:96)
        at org.apache.hive.beeline.HiveSchemaTool.main(HiveSchemaTool.java:1473)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:323)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:236)

初始化成功后,MySQL里会生成 hive3 数据库,其中有74张表:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hive3              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
mysql> use hive3;
mysql> show tables;
+-------------------------------+
| Tables_in_hive3               |
+-------------------------------+
| AUX_TABLE                     |
| BUCKETING_COLS                |
......
| WM_TRIGGER                    |
| WRITE_SET                     |
+-------------------------------+
74 rows in set (0.00 sec)

在HDFS创建Hive的存储目录:

hadoop fs -mkdir /tmp
hadoop fs -mkdir -p /user/hive/warehouse
hadoop fs -chmod g+w /tmp
hadoop fs -chmod g+w /user/hive/warehouse

注:这一步我没做。后来看了一下, /tmp 是已有的。 /user/hive/warehouse 会在创建第一个DB的时候自动创建。

启动metastore服务:

nohup /export/server/apache-hive-3.1.2-bin/bin/hive --service metastore &

注:如果想要设置log为debug级别,则加上 --hiveconf hive.root.logger=DEBUG,console

启动hiveserver2服务:

nohup /export/server/apache-hive-3.1.2-bin/bin/hive --service hiveserver2 &

注:启动metastore服务后,等一会儿再启动hiveserver2服务。

两个服务都启动后,可以通过 jps 查看Java进程:

[root@node1 apache-hive-3.1.2-bin]# jps
128897 RunJar
129121 Jps
91060 DataNode
126459 RunJar
92090 ResourceManager
92284 NodeManager
90863 NameNode

可见,多了两个 RunJar 进程。之后可随时检查,确保这两个进程还在工作。

以上操作都是在node1上进行的。

Hive可以直接通过命令行连接metastore,但是不推荐这么做,官方推荐做法是通过 beeline 客户端连接hiveserver2,后者再连接到metastore。

虽然Hive是部署在node1上的,但是通过 beeline 客户端,也可以在其它机器上连接。比如,我们把node1上的Hive目录复制到node3上(主要是为了复制 beeline 客户端)。

scp -r /export/server/apache-hive-3.1.2-bin/ node3:/export/server/

然后在node3上,通过 beeline 客户端来连接node1上的Hive:

/export/server/apache-hive-3.1.2-bin/bin/beeline

命令行提示符如下:

beeline> 

在命令行通过以下命令,连接到node1的Hive上:

! connect jdbc:hive2://node1:10000

输入用户名 root ,密码为空(直接回车):

命令行提示符如下:

0: jdbc:hive2://node1:10000> 

现在,就可以运行各种数据库命令了,比如:

show databases;
use <DB name>;
show tables;

当然,也可以用第三方工具来连接Hive数据库,比如 DataGridDbeaverSQuirrel SQL Client 等,和连接MySQL、Db2等数据库类似,不再赘述。

Hive数据库操作

创建数据库和表

创建数据库:

create database test1212;

注:其对应的HDFS目录为 /user/hive/warehouse/test1212.db ,如果之前没有手工创建 /user/hive/warehouse 目录,此时就会自动创建。

使用该数据库:

use test1212;

创建表:

create table t1(name string, sex string, age int) row format delimited fields terminated by "\t";

注:其对应的HDFS目录为 /user/hive/warehouse/test1212.db/t1

注意,本例中指定使用 \t (制表符)作为字段之间的分隔符。如果没有指定分隔符,则默认使用 \001 字符。

查询表:

select * from t1;
......
+----------+---------+---------+
| t1.name  | t1.sex  | t1.age  |
+----------+---------+---------+
+----------+---------+---------+
No rows selected (1.663 seconds)

此时表为空。

向表中导入数据

方法1:直接通过HDFS传文件

例如,文本文件 t1.txt 内容如下:

zhangsan	male	20
lisi	female	19
wangwu	male	33

注意,各个字段之间是用 \t 分隔的。

把该文件传到HDFS中表 t1 对应的目录下,即 /user/hive/warehouse/test1212.db/t1

hadoop fs -put /export/data/t1.txt /user/hive/warehouse/test1212.db/t1/

如下图:

CentOS虚拟机搭建Hive环境-LMLPHP
查询表 t1

select * from t1;
......
+-----------+---------+---------+
|  t1.name  | t1.sex  | t1.age  |
+-----------+---------+---------+
| zhangsan  | male    | 20      |
| lisi      | female  | 19      |
| wangwu    | male    | 33      |
+-----------+---------+---------+
3 rows selected (1.007 seconds)

可见,表和文件已经关联了。

注:该方法比较暴力,一般不推荐直接这么做。

方法2:通过LOAD命令传文件

LOAD 命令的语法为:

LOAD DATA [LOCAL] INPATH '<path>' [OVERWRITE] INTO TABLE <tablename>;

需要注意的是 LOCAL 关键字。

指定LOCAL关键字

若指定 LOCAL 关键字,则是从hiveserver2服务器端的本地文件系统加载。比如:

创建表 t2

create table t2(name string, sex string, age int) row format delimited fields terminated by "\t";

通过LOAD命令,加载本地文件:

LOAD DATA LOCAL INPATH '/export/data/t1.txt' INTO TABLE t2;

查询表 t2

select * from t2;
......
+-----------+---------+---------+
|  t2.name  | t2.sex  | t2.age  |
+-----------+---------+---------+
| zhangsan  | male    | 20      |
| lisi      | female  | 19      |
| wangwu    | male    | 33      |
+-----------+---------+---------+
3 rows selected (0.218 seconds)

需要注意的是,我们是在node3的beeline客户端运行命令的,beeline客户端连接的是node1的hiveserver2服务,所以这里的 LOCAL 指定的是node1的本地文件系统。也就是说, /export/data/t1.txt 是node1的文件系统路径。

不指定LOCAL关键字

如果不指定 LOCAL ,则默认是从HDFS文件系统加载。比如:

创建表 t3

create table t3(name string, sex string, age int) row format delimited fields terminated by "\t";

上传文件到HDFS的根目录下:

hadoop fs -put /export/data/t1.txt /

此时,该文件在HDFS的路径为 /t1.txt

通过LOAD命令,加载HDFS文件:

LOAD DATA INPATH '/t1.txt' INTO TABLE t3;

查询表 t3

select * from t3;
......
+-----------+---------+---------+
|  t3.name  | t3.sex  | t3.age  |
+-----------+---------+---------+
| zhangsan  | male    | 20      |
| lisi      | female  | 19      |
| wangwu    | male    | 33      |
+-----------+---------+---------+
3 rows selected (0.203 seconds)

注意:加载HDFS文件是移动操作,原来的文件就没了。

方法3:插入数据

通过SQL语句,可以直接向表中插入数据,例如:

insert into t3 values ('zhaoliu', 'female', 22);

但是,这么做的成本很高,我试了一下,该操作花了246秒。

通过 http://192.168.88.151:8088 ,可以看到实际上底层是一个MapReduce的任务:

CentOS虚拟机搭建Hive环境-LMLPHP

插入单条记录的成本非常高,因此更常见的操作是 insert into xxx select xxx from xxx where xxxcreate table xxx as select xxx from xxx where xxx (即CTAS)。

查询数据

SELECT xxx FROM xxx WHERE xxx

其它像 distinctgroup byhavingorder bylimitjoin 等关键字,也都一样,不再赘述。

12-13 13:31