Hive 入门

Hive 入门

一、准备

1. Java 安装

Hive 是一个基于 Hadoop 的数据仓库,而 Hadoop 是基于 Java 开发的,所以我们需要安装 Java。

yum install -y java-1.8.0-openjdk-devel
[root@iZuf6c82diwquwsq69eqejZ ~]# java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)

2. Hadoop 安装

Hadoop 是分布式文件存储系统,各个机器之间需要开启免密登录。为方便操作,这里我直接用 root 权限。如果是单机,就是自己免密登录自己,需要把生成的 id_rsa.pub 放到 authorized_keys 里面。

ssh-keygen -t rsa

我这里以三台机器为例,已经可以互相免密登录了。

139.196.112.183  hadoop-master
81.68.114.173    hadoop-slave1
47.102.144.35    hadoop-slave2

下载 Hadoop,实例为目前最新版本。(下载网址:https://hadoop.apache.org/releases.html)

wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.2.2/hadoop-3.2.2.tar.gz

解压出来,我这里解压到当前目录。

tar -zxvf hadoop-3.2.2.tar.gz
[root@iZuf6c82diwquwsq69eqejZ hadoop]# pwd
/work/docker/hadoop

修改 hadoop-env.sh 文件,添加 JAVE_HOME。

export JAVA_HOME=/usr

验证 Hadoop 是否安装成功。

[root@iZuf6c82diwquwsq69eqejZ hadoop]# /work/docker/hadoop/hadoop-3.2.2/bin/hadoop version
Hadoop 3.2.2
Source code repository Unknown -r 7a3bc90b05f257c8ace2f76d74264906f0f7a932
Compiled by hexiaoqiao on 2021-01-03T09:26Z
Compiled with protoc 2.5.0
From source with checksum 5a8f564f46624254b27f6a33126ff4
This command was run using /work/docker/hadoop/hadoop-3.2.2/share/hadoop/common/hadoop-common-3.2.2.jar

接着在三台机器上,修改四个 xml 文件。

# core-site.xml 文件,设置 hadoop 临时目录和 master。
<configuration>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/work/docker/hadoop/tmp</value>
    </property>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://hadoop-master:9000</value>
    </property>
</configuration>

# hdfs-site.xml 文件,设置 namenode 目录、datanode 目录和备份数。
<configuration>
    <property>
        <name>dfs.name.dir</name>
        <value>/work/docker/hadoop/hdfs/name</value>
    </property>
    <property>
        <name>dfs.data.dir</name>
        <value>/work/docker/hadoop/hdfs/data</value>
    </property>
    <property>
        <name>dfs.replication</name>
        <value>2</value>
    </property>
</configuration>

# mapred-site.xml 文件,使用 yarn 集群来实现资源分配。
<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>

# yarn-site.xml 文件,设置 ResourceManager 对客户端暴露的地址,mapreduce_shuffle 为 NodeManager 上运行的附属服务,支持运行 MapReduce 程序。
<configuration>
    <property>
        <name>yarn.resourcemanager.hostname</name>
        <value>hadoop-master</value>
    </property>
    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
</configuration>

在 workers 文件中,列出所有节点的主机名或者 IP。

hadoop-master
hadoop-slave1
hadoop-slave2

分别在 sbin/start-dfs.sh, sbin/stop-dfs.sh 文件顶部添加如下配置:

HDFS_DATANODE_USER=root
HDFS_DATANODE_SECURE_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root

分别在 sbin/start-yarn.sh, sbin/stop-yarn.sh 文件顶部添加如下配置:

YARN_RESOURCEMANAGER_USER=root
HDFS_DATANODE_SECURE_USER=yarn
YARN_NODEMANAGER_USER=root

格式化 hdfs

/work/docker/hadoop/hadoop-3.2.2/bin/hdfs namenode -format

全部启动

/work/docker/hadoop/hadoop-3.2.2/sbin/start-all.sh 

注意:以上操作都是在 master 进行,master 的 hosts 需要填内网 IP。

# master
[root@iZuf6c82diwquwsq69eqejZ hadoop]# jps
1241264 DataNode
1241079 NameNode
1242647 Jps
1241737 ResourceManager
1241902 NodeManager
1241484 SecondaryNameNode

# slave1
[root@VM-0-6-centos hadoop]# jps
10724 Jps
10519 NodeManager
10415 DataNode

# slave2
[root@iZuf65lasa7rugxfvzmywrZ hadoop]# jps
550760 Jps
550524 DataNode
550638 NodeManager

image

image

  • NameNode

    在 master 上启动,负责调度。 当上传文件时,NameNode 会将文件分块并且分配到集群的 DataNode 节点上。NameNode 主要是用来保存 HDFS 的元数据信息,比如命名空间、块信息、节点信息等。当它运行的时候,这些信息是存在内存中的,也可以持久化到磁盘上。NameNode 启动的时候,会合并操作日志文件(edit logs)到镜像文件(fsimage)中,并且读取镜像文件。

  • SecondaryNameNode

    只有在 NameNode 重启的时候,操作日志文件才会合并到镜像文件中,而 NameNode 是很少重启的,所以当 NameNode 运行了很长时间后,操作日志文件就会变得很大。这样如果 NameNode 挂了,重启将异常缓慢,并且会丢失内存中未来得及写入操作日志文件的数据。因此 SecondaryNameNode 应运而生,它会定期地获取 edit logs,并更新到自己的 fsimage 上,然后 cp 到 NameNode 中。如此 NameNode 下次重启时就会使用新的 fsimage 文件,减少重启时间。因此 SecondaryNameNode 最好单独放在一台配置和 NameNode 所在机器差不多的机器上。指定 SecondaryNameNode 需在 hdfs-site.xml 文件中配置:

    <property>
    	<name>dfs.secondary.http.address</name>
    	<value>hadoop-slave2:50090</value>
    </property>
    

    注意:如果用的是云服务器,在 hadoop-slave2 机器上,这里得用内网 IP。

  • DataNode

    它是文件系统的工作节点,负责存储数据,并且定期地向 NameNode 发送它们所存储的块的列表。当 DataNode 有写操作的时候,会跟 NameNode 通信,NameNode 会将元数据信息写入 edit logs。

  • NodeManager

    是 YARN 集群每个节点上的代理,它管理 Hadoop 集群中单个计算节点。功能包括与 ResourceManager 保持通信,管理 Container(Container 是 YARN 中资源的抽象,它封装了某个节点上一定量的资源)的生命周期、监控每个 Container 的资源使用(内存、CPU等)情况、追踪节点健康状况、管理日志和不同应用程序用到的附属服务等。

  • ResourceManager

    负责 YARN 集群中所有资源的统一管理和分配,它接收来自各个节点(NodeManager)的资源汇报信息,并把这些信息按照一定的策略分配给各个应用程序。
    更多关于 Yarn 的资料:https://zhuanlan.zhihu.com/p/54192454

3. Hive 安装

因为我们的 Hadoop 版本是 3.2.2,所以 Hive 要下载与之匹配的 3.1.2 版本。下载地址:http://www.apache.org/dyn/closer.cgi/hive/

http://mirrors.tuna.tsinghua.edu.cn/apache/hive/hive-3.1.2/apache-hive-3.1.2-bin.tar.gz

解压到当前目录:

tar -zxvf apache-hive-3.1.2-bin.tar.gz
[root@iZuf6c82diwquwsq69eqejZ hive]# pwd
/work/docker/hive

在 conf 目录下新增 hive-env.sh 配置文件并设置 Hadoop 环境。

HADOOP_HOME=/work/docker/hadoop/hadoop-3.2.2

修改 hive-site.xml 配置文件:

cp hive-default.xml.template hive-site.xml
# 设置 Hive 临时文件目录
<property>
	<name>system:java.io.tmpdir</name>
	<value>/work/docker/hive/tmp</value>
</property>

# 修改文件中所有的 ${system:user.name} 为 ${user.name}
# 如下所示
${system:java.io.tmpdir}/${user.name}

# 设置 metastore 为 MySQL
<property>
  <name>javax.jdo.option.ConnectionURL</name>
  <value>jdbc:mysql://139.224.**.**:3306/hive?createDatabaseIfNotExist=true</value>
</property>

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

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

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

下载对应版本的 MySQL 驱动,下载地址:https://downloads.mysql.com/archives/c-j/

wget https://downloads.mysql.com/archives/get/p/3/file/mysql-connector-java-8.0.22.tar.gz

解压出来复制到 lib 目录下:

cp mysql-connector-java-8.0.22.jar /work/docker/hive/apache-hive-3.1.2-bin/lib

注意: 3.2.2 版本的 Hadoop 和 3.1.2 版本的 Hive 有一个坑,两者的 guava-19.0.jar 版本不一样,启动会报错。我们需要把低版本的删掉,高版本的 cp 过来。

rm -rf /work/docker/hive/apache-hive-3.1.2-bin/lib/guava-19.0.jar
cp /work/docker/hadoop/hadoop-3.2.2/share/hadoop/common/lib/guava-27.0-jre.jar /work/docker/hive/apache-hive-3.1.2-bin/lib

初始化 MySQL 数据库:

/work/docker/hive/apache-hive-3.1.2-bin/bin/schematool -dbType mysql -initSchema

注意: 这里还有一个坑,初始化的时候会报错:

Exception in thread "main" java.lang.RuntimeException: com.ctc.wstx.exc.WstxParsingException: Illegal character entity: expansion character (code 0x8
 at [row,col,system-id]: [3219,96,"file:/work/docker/hive/apache-hive-3.1.2-bin/conf/hive-site.xml"]
	at org.apache.hadoop.conf.Configuration.loadResource(Configuration.java:3040)
	at org.apache.hadoop.conf.Configuration.loadResources(Configuration.java:2989)
	at org.apache.hadoop.conf.Configuration.loadProps(Configuration.java:2864)
	at org.apache.hadoop.conf.Configuration.addResourceObject(Configuration.java:1012)
	at org.apache.hadoop.conf.Configuration.addResource(Configuration.java:917)
	at org.apache.hadoop.hive.conf.HiveConf.initialize(HiveConf.java:5151)
	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)
Caused by: com.ctc.wstx.exc.WstxParsingException: Illegal character entity: expansion character (code 0x8
 at [row,col,system-id]: [3219,96,"file:/work/docker/hive/apache-hive-3.1.2-bin/conf/hive-site.xml"]
	at com.ctc.wstx.sr.StreamScanner.constructWfcException(StreamScanner.java:621)
	at com.ctc.wstx.sr.StreamScanner.throwParseError(StreamScanner.java:491)
	at com.ctc.wstx.sr.StreamScanner.reportIllegalChar(StreamScanner.java:2456)
	at com.ctc.wstx.sr.StreamScanner.validateChar(StreamScanner.java:2403)
	at com.ctc.wstx.sr.StreamScanner.resolveCharEnt(StreamScanner.java:2369)
	at com.ctc.wstx.sr.StreamScanner.fullyResolveEntity(StreamScanner.java:1515)
	at com.ctc.wstx.sr.BasicStreamReader.nextFromTree(BasicStreamReader.java:2828)
	at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1123)
	at org.apache.hadoop.conf.Configuration$Parser.parseNext(Configuration.java:3336)
	at org.apache.hadoop.conf.Configuration$Parser.parse(Configuration.java:3130)
	at org.apache.hadoop.conf.Configuration.loadResource(Configuration.java:3023)
	... 14 more

我们只需要删掉 hive-site.xml 文件中,报错的那一行就行了。(这里我把整个 description 删掉了)

3218     <description>
3219       Ensures commands with OVERWRITE (such as INSERT OVERWRITE) acquire Exclusive locks for&#8;transactional tables.  This ensures that inserts (w/o overwrite) running concurrently
3220       are not hidden by the INSERT OVERWRITE.
3221     </description>

再次初始化数据库,成功。至此,Hive 已经安装完毕。

二、实战

有这样一个业务场景,用户给主播刷礼物,然后主播查看每天的礼物报表。

如此经典的情形,我们可以在服务端按照一定的格式打点,然后推送到 HDFS,再由 Hive 读取。这里有个很重要的概念,就是分区,在 HDFS 里面,分区体现在多个目录 。Hive 里面,分区体现在创表的时候的 PARTITIONED BY 语句。

先在 Hadoop 里面创建好对应的目录:

./hadoop fs -mkdir -p /dclett/tv_gift
[root@iZuf6c82diwquwsq69eqejZ bin]# ./hadoop fs -ls /dclett
Found 1 items
drwxr-xr-x   - root supergroup          0 2021-05-05 17:31 /dclett/tv_gift

打点日志文件:

# /work/dclett/tv_gift/210505/gift.log
1,Dick,1001,17,101,apple,10,1620207298
2,Erick,1001,17,102,banana,12,1620207345
3,Alicia,1002,18,103,lipstick,1,1620207394
# /work/dclett/tv_gift/210506/gift.log
4,Dick,1002,18,104,candy,99,1620293698
5,Alicia,1002,18,105,donut,99,1620293758
[root@iZuf6c82diwquwsq69eqejZ dclett]# tree
.
└── tv_gift
    ├── 210505
    │   └── gift.log
    └── 210506
        └── gift.log

分别将两天的日志文件推送到 HDFS:

./hadoop fs -mkdir /dclett/tv_gift/dt=210505; ./hadoop fs -put -f /work/dclett/tv_gift/210505/gift.log /dclett/tv_gift/dt=210505
./hadoop fs -mkdir /dclett/tv_gift/dt=210506; ./hadoop fs -put -f /work/dclett/tv_gift/210506/gift.log /dclett/tv_gift/dt=210506
[root@iZuf6c82diwquwsq69eqejZ bin]# ./hadoop fs -ls /dclett/tv_gift
Found 2 items
drwxr-xr-x   - root supergroup          0 2021-05-05 17:47 /dclett/tv_gift/dt=210505
drwxr-xr-x   - root supergroup          0 2021-05-05 17:48 /dclett/tv_gift/dt=210506

创建 Hive 数据库和表(使用 dt 字段作为分区):

create database dclett;
use dclett;
create table tv_gift(
id int,
name string,
room_id int,
anchor_id int,
goods_id int,
goods_name string,
goods_num int,
create_time int
)
PARTITIONED BY (
  `dt` string)
row format delimited fields terminated by ','
location 'hdfs://hadoop-master:9000/dclett/tv_gift';

如此一来,貌似已经大功告成了。然而当我 select 的时候,却发现没有数据。

hive> select * from tv_gift;
OK
Time taken: 0.489 seconds

难道分区没有成功?

hive> show partitions tv_gift;
OK
Time taken: 0.447 seconds

可以说是分区没有成功,因为我们还少了一步操作:将分区信息写入 metastore。

hive> msck repair table tv_gift;
OK
Partitions not in metastore:	tv_gift:dt=210505	tv_gift:dt=210506
Repair: Added partition to metastore tv_gift:dt=210505
Repair: Added partition to metastore tv_gift:dt=210506
Time taken: 0.672 seconds, Fetched: 3 row(s)
hive> show partitions tv_gift;
OK
dt=210505
dt=210506
Time taken: 0.739 seconds, Fetched: 2 row(s)

MySQL 查看分区信息:

mysql> select * from PARTITIONS;
+---------+-------------+------------------+-----------+-------+--------+
| PART_ID | CREATE_TIME | LAST_ACCESS_TIME | PART_NAME | SD_ID | TBL_ID |
+---------+-------------+------------------+-----------+-------+--------+
|       3 |  1620209674 |                0 | dt=210505 |    26 |     23 |
|       4 |  1620209674 |                0 | dt=210506 |    27 |     23 |
+---------+-------------+------------------+-----------+-------+--------+
2 rows in set (0.00 sec)

Hive 中现在有数据了:

hive> select * from tv_gift;
OK
1	Dick	1001	17	101	apple	10	1620207298	210505
2	Erick	1001	17	102	banana	12	1620207345	210505
3	Alicia	1002	18	103	lipstick	1	1620207394	210505
4	Dick	1002	18	104	candy	99	1620293698	210506
5	Alicia	1002	18	105	donut	99	1620293758	210506
Time taken: 0.503 seconds, Fetched: 5 row(s)

如此才是大功告成,记得每次 put 新分区的时候在 Hive 执行下 msck repair table TableName 命令。

原文地址:https://www.cnblogs.com/74percent/p/14732376.html