一、虚拟机环境
1.1 校园网 NAT 配置静态 IP
参考:
需要注意的是:共享网卡时无法开启热点,可以选择在有开启热点需求的时候取消网卡共享,之后再重新启用网卡共享。
教主 VMnet8 网卡分配到的 IP 为 192.168.137.1/24
,因此将虚拟机的 VMnet8 子网网段设置为 192.168.137.0/24
,并且习惯性的选择将网关 IP 设置为和宿主机的 VMnet8 网卡相同。
1.2 安装 ubuntu-20.04
镜像源选择:http://mirrors.aliyun.com/ubuntu
。
尽量在安装阶段就配置好静态 IP、hostname、镜像源等,可以方便后续的修改。
静态 IP
ip addr
vim /etc/netplan/00-installer-config.yaml
network:
ethernets:
ens33:
addresses:
- 192.168.137.100/24
gateway4: 192.168.137.1
nameservers:
addresses:
- 192.168.137.1
search: []
version: 2
需要注意的是:VIM 对 YAML 的默认格式化效果不是特别理想,可以考虑手动调整缩进。
netplan apply
hostname
hostnamectl set-hostname ubuntu
# 重新登录
镜像源
vim /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu focal-backports main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu focal-security main restricted universe multiverse
启用 root SSH
# 设置 root 密码
sudo passwd root
# 取消 PermitRootLogin 的注释并将其值改为 yes
sudo vim /etc/ssh/sshd_config
# 重启 sshd
sudo systemctl restart sshd
root 用户没有 bash 颜色高亮:
sudo cp /etc/skel/.bashrc /root
# 取消 force_color_prompt=yes 的注释
sudo vim /root/.bashrc
# 重新登录
hosts
vim /etc/hosts
# ...
192.168.137.1 win10
192.168.137.101 node101
192.168.137.102 node102
192.168.137.103 node103
需要注意的是:为了通过网页正常访问 HDFS 也需要在宿主机(C:\Windows\System32\drivers\etc\hosts
)配置域名的解析。
SSH 免密登录
# node101 node102 node103
ssh-keygen -t rsa
ssh-copy-id root@node101
ssh-copy-id root@node102
ssh-copy-id root@node103
安装 open-jdk8
apt install openjdk-8-jdk
默认安装位置在 usr/lib/jvm/java-8-openjdk-amd64
。
vim /etc/profile
# ...
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
source /etc/profile && source ~/.bashrc
1.3 SSH 和 FTP 方案
Windows Terminal
文档:Windows / 开发环境 / Windows 终端 / 概述
Cascadia Code 字体:https://github.com/microsoft/cascadia-code
为了弥补 “将命令发送到所有窗口” 的功能缺失,可以拿一些脚本来替代:
vim ~/bin/cluster.sh
#!/bin/bash
case $1 in
exec)
for host in node101 node102 node103; do
echo "========== ${host} =========="
ssh "${host}" "${@:2}"
done
;;
rsync)
for host in node101 node102 node103; do
if [[ "$(hostname)" != "${host}" ]]; then
echo "========== ${host} =========="
rsync -a -r -v "$2" "${host}":"$2/../"
fi
done
;;
esac
chmod 777 ~/bin/cluster.sh
~/bin/cluster.sh exec "jps"
~/bin/cluster.sh rsync "$HADOOP_HOME/etc"
需要宿主机和虚拟机传输文件的时候可能就不得不借助一些工具了,比如 XFTP、MobaXterm 等。不过当然也可以有一些其它的办法。
sftp
cd <local_dir>
sftp <user>@<host>
cd <remote_dir>
put -r <local_dir>
get -r <remote_file>
Nginx 文件服务器 + curl
# ...
http {
# ...
server {
# ...
root /usr/share/nginx/html;
charset utf-8;
# ...
location /public {
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}
}
}
curl <url> -o <filename>
Docker
docker cp <local_file> <container_id | container_name>:<container_dir>
docker cp <container_id | container_name>:<container_file> <local_dir>
1.4 其它
VIM
vim /etc/vim/vimrc
" ...
filetype plugin indent on
set showcmd
set showmatch
set ignorecase
set smartcase
set incsearch
set autowrite
set hidden
set number
set ruler
set expandtab
set tabstop=4
set cursorline
set confirm
set hlsearch
时区
timedatectl set-timezone Asia/Shanghai
timedatectl
二、Hadoop
2.1 安装 hadoop-3.2.2
文档:
curl https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.2.2/hadoop-3.2.2.tar.gz -o hadoop-3.2.2.tar.gz
mkdir /opt/hadoop
tar -zxvf hadoop-3.2.2.tar.gz -C /opt/hadoop
vim /etc/profile
# ...
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export HADOOP_HOME=/opt/hadoop/hadoop-3.2.2
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
2.2 Zookeeper 集群
可以直接在宿主机启动一份 docker-compose:
version: '3'
services:
zk1:
image: zookeeper:3.7
hostname: zk1
ports:
- 2181:2181
volumes:
- ./zk1/data/:/data/
- ./zk1/datalog/:/datalog/
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181
zk2:
image: zookeeper:3.7
hostname: zk2
ports:
- 2182:2181
volumes:
- ./zk2/data/:/data/
- ./zk2/datalog/:/datalog/
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zk3:2888:3888;2181
zk3:
image: zookeeper:3.7
hostname: zk3
ports:
- 2183:2181
volumes:
- ./zk3/data/:/data/
- ./zk3/datalog/:/datalog/
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181
networks:
default:
external: true
name: local_net
docker network create local_net
docker-compose up -d
2.3 Hadoop 集群
配置文件
默认配置文件:
参考:
hadoop-env.sh
vim $HADOOP_HOME/etc/hadoop/hadoop-env.sh
# ...
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
# ...
export HDFS_NAMENODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_JOURNALNODE_USER=root
export HDFS_ZKFC_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
workers
vim $HADOOP_HOME/etc/hadoop/workers
node101
node102
node103
core-site.xml
vim $HADOOP_HOME/etc/hadoop/core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hdfs-cluster</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/hadoop/hadoop-3.2.2/tmp</value>
</property>
<property>
<name>hadoop.http.staticuser.user</name>
<value>root</value>
</property>
<!-- HDFS zookeeper 地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>win10:2181,win10:8182,win10:2183</value>
</property>
<!-- YARN zookeeper 地址 -->
<property>
<name>hadoop.zk.address</name>
<value>win10:2181,win10:2182,win10:2183</value>
</property>
</configuration>
需要注意的是:hadoop.tmp.dir
不能引用环境变量。
hdfs-site.xml
vim $HADOOP_HOME/etc/hadoop/hdfs-site.xml
<configuration>
<!-- HDFS HA -->
<property>
<name>dfs.nameservices</name>
<value>hdfs-cluster</value>
</property>
<property>
<name>dfs.ha.namenodes.hdfs-cluster</name>
<value>nn1,nn2,nn3</value>
</property>
<!-- NameNode RPC 通信地址 -->
<property>
<name>dfs.namenode.rpc-address.hdfs-cluster.nn1</name>
<value>node101:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.hdfs-cluster.nn2</name>
<value>node102:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.hdfs-cluster.nn3</name>
<value>node103:8020</value>
</property>
<!-- NameNode HTTP 通信地址 -->
<property>
<name>dfs.namenode.http-address.hdfs-cluster.nn1</name>
<value>node101:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.hdfs-cluster.nn2</name>
<value>node102:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.hdfs-cluster.nn3</name>
<value>node103:9870</value>
</property>
<!-- JournalNode -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node101:8485;node102:8485;node103:8485/hdfs-cluster</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/opt/hadoop/hadoop-3.2.2/tmp/dfs/journalnode/</value>
</property>
<!-- 脑裂问题隔离机制 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
<!-- HDFS 自动故障转移 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.hdfs-cluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
</configuration>
mapred-site.xml
vim $HADOOP_HOME/etc/hadoop/mapred-site.xml
<configuration>
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml
vim $HADOOP_HOME/etc/hadoop/yarn-site.xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!-- ResourceManager HA -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yarn-cluster</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2,rm3</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>node101</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>node102</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm3</name>
<value>node103</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>node101:8088</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>node102:8088</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm3</name>
<value>node103:8088</value>
</property>
<!-- ResourceManager 自动恢复 -->
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
</configuration>
日志聚集
mapred-site.xml
<configuration>
<!-- ... -->
<!-- JobHistoryServer -->
<property>
<name>mapreduce.jobhistory.address</name>
<value>node101:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>node101:19888</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<!-- ... -->
<!-- 日志聚集 -->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log.server.url</name>
<value>http://node101:19888/jobhistory/logs</value>
</property>
<!-- 3600 * 24 * 7 -->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
</configuration>
同步配置文件
# node101
rsync -a -r -v $HADOOP_HOME/etc node102:$HADOOP_HOME
rsync -a -r -v $HADOOP_HOME/etc node103:$HADOOP_HOME
初始化集群
# 启动 JournalNode
# node101 node102 node103
hdfs --daemon start journalnode
# 格式化 NameNode
# node101
hdfs namenode -format
# 同步 NameNode 元数据
# node101
hdfs --daemon start namenode
# node102 node103
hdfs namenode -bootstrapStandby
# 格式化 ZookeeperFailoverController
# node101
hdfs zkfc -formatZK
需要注意的:重新格式化前需要先删除 tmp 和 logs 目录:
rm -rf $HADOOP_HOME/tmp $HADOOP_HOME/logs
启动集群
参考:hadoop ha模式下,kill active的namenode节点后,standby的namenode节点没能自动启动
# node101
start-dfs.sh
start-yarn.sh
mapred --daemon start historyserver
单独启动:
hdfs --daemon <start|stop> namenode
hdfs --daemon <start|stop> secondarynamenode
hdfs --daemon <start|stop> datanode
yarn --daemon <start|stop> resourcemanager
yarn --daemon <start|stop> nodemanager
mapred --daemon <start|stop> historyserver
查看 HA 状态:
hdfs haadmin -getAllServiceState
yarn rmadmin -getAllServiceState
WordCount
cd $HADOOP_HOME
mkdir input
echo -e "i keep saying no\nthis can not be the way it was supposed to be\ni keep saying no\nthere has gotta be a way to get you close to me" > input/word.txt
hadoop fs -mkdir /input
hadoop fs -put input/word.txt /input
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.2.jar wordcount /input /output
2.4 HDFS
HDFS 组成架构
NameNode
- 管理 HDFS 的名称空间
- 配置副本策略
- 管理数据块映射信息
- 处理客户端读写请求
DataNode
- 存储实际的数据块
- 执行数据块(Block)的读 / 写操作
SecondaryNameNode
- 复制 NameNode,分担其工作量,比如定期合并 Fsimage 和 Edits,并推送给 NameNode
- 在紧急情况下,可辅助恢复 NameNode
Client
- 文件切分:文件上传到 HDFS 的时候,Client 将文件切分成一个一个的 Block,然后进行上传
- 与 NameNode 交互,获取文件的位置信息
- 与 DataNode 交互,读取或者写入数据
- Client 提供一些命令来管理 HDFS,比如 NameNode 格式化
- Client 可以通过一些命令来访问 HDFS,比如对 HDFS 的增删改查操作
HDFS 常用命令
# 剪切上传
hadoop fs -moveFromLocal <local_file> <hdfs_dir>
# 复制上传
hadoop fs -copyFromLocal <local_file> <hdfs_dir>
hadoop fs -put <local_file> <hdfs_dir>
# 追加上传
hadoop fs -appendToFile <local_file> <hdfs_file>
# 下载
hadoop fs -copyToLocal <hdfs_file> <local_dir>
hadoop fs -get <hdfs_file> <local_dir>
# 设置副本数量
hadoop fs -setrep <replication> <hdfs_file>
HDFS Java API
pom.xml
:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.2.2</version>
</dependency>
查看文件状态:
public static void main(String[] args) throws IOException, InterruptedException {
FileSystem fs = FileSystem.get(URI.create("hdfs://node101:8020"), new Configuration(), "root");
FileStatus status = fs.getFileStatus(new Path("/input/word.txt"));
System.out.println(status);
fs.close();
}
2.5 MapReduce
MapReduce 进程
一个完整的 MapReduce 程序在分布式运行时有三类实例进程:
- ApplicationMaster:负责整个程序的过程调度及状态协调
- MapTask:负责 Map 阶段的整个数据处理流程
- ReduceTask:负责 Reduce 阶段的整个数据处理流程
MapTask 工作机制
-
Read 阶段
MapTask 通过
InputFormat
获得的RecordReader
从InputSplit
中解析出一个个 KV。 -
Map 阶段
该阶段主要是将解析出的 KV 交给用户编写的
map()
函数处理,并产生一系列新的 KV。 -
Collect 阶段
在用户编写的
map()
函数中,当数据处理完成后,一般会调用OutputCollector.collect()
输出结果。在该函数内部,它会将生成的 KV 进行分区,并写入到一个环形缓冲区中。
-
Spill 阶段
即溢写,当环形缓存区满后,MapReduce 会将数据写到本地磁盘上,生成一个临时文件。
需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。
ReduceTask 工作机制
-
Copy 阶段
ReduceTask 从各个 MapTask 上远程拷贝一片数据,如果其大小超过一定阈值则写到磁盘上,否则直接放到内存中。
-
Sort 阶段
在远程拷贝数据的同时,ReduceTask 启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
按照 MapReduce 语义,用户编写的
reduce()
函数输入数据是按 Key 进行聚集的一组数据。为了将 Key 相同的疏忽聚在一起,Hadoop 采用了基于排序的策略。
由于各个 MapTask 已经实现对自己的处理结果进行了局部排序,因此 ReduceTask 只需对所有数据进行一次归并排序即可。
-
Reduce 阶段
reduce()
函数将计算结果写到 HDFS 中。
WordCount
public class WordCount {
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
Job job = Job.getInstance();
job.setJarByClass(WordCount.class);
job.setMapperClass(WordCount.WordCountMapper.class);
job.setReducerClass(WordCount.WordCountReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
boolean successful = job.waitForCompletion(true);
System.exit(successful ? 0 : 1);
}
public static class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] words = line.split(" ");
for (String word : words) {
context.write(new Text(word), new IntWritable(1));
}
}
}
public static class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int count = 0;
for (IntWritable value : values) {
count += value.get();
}
context.write(key, new IntWritable(count));
}
}
}
打包上传执行:
# 删除 /output 目录
hadoop fs -rmdir --ignore-fail-on-non-empty /output
# 执行
hadoop jar word-count-0.0.1.jar xyz.icefery.mr.wc.WordCount /input/word.txt /output
2.6 YARN
YARN 组成架构
ResourceManager
- 处理客户端请求
- 监控 NodeManager
- 启动或监控 ApplicationMaster
- 资源的分配与调度
NodeManager
- 管理单个节点上的资源
- 处理来自 ResourceManager 的命令
- 处理来自 ApplicationMaster 的命令
ApplicationMaster
- 为应用程序申请资源并分配给内部的任务
- 任务的监控与容错
Container
- Container 是 YARN 中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等
YARN 工作机制
- MR 程序提交到客户端所在的节点
- YarnRunner 向 ResourceManager 申请一个 Application
- ResourceManager 将该应用程序的资源路径返回给 YarnRunner
- 该程序将运行所需资源提交到 HDFS 上
- 程序资源提交完毕后,申请运行 ApplicationMaster
- ResourceManager 将用户的请求初始化成一个 Task
- 其中一个 NodeManager 领取到 Task 任务
- 该 NodeManager 创建容器 Container,并产生 ApplicationMaster
- Container 从 HDFS 上拷贝资源到本地
- ApplicationMaster 向 ResourceManager 申请运行 MapTask 资源
- ResourceManager 将运行 MapTask 任务分配给另外两个 NodeManager,另外两个 NodeManager 分别领取任务并创建容器
- MR 向两个接收到任务的 NodeManager 发送程序启动脚本,这两个 NodeManager 分别启动 MapTask,MapTask 对数据进行分区排序
- ApplicationMaster 等待所有 MapTask 运行完毕后,向 ResourceManager 申请容器,运行 ReduceTask
- ReduceTask 从 MapTask 获取相应分区的数据
- 程序运行完毕后, MR 会向 ResourceManager 申请注销自己
三、Hive
3.1 安装 hive-3.1.2
参考:Hive启动报错:java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument
curl https://mirrors.tuna.tsinghua.edu.cn/apache/hive/hive-3.1.2/apache-hive-3.1.2-bin.tar.gz -o apache-hive-3.1.2-bin.tar.gz
mkdir /opt/hive
tar -zxvf apache-hive-3.1.2-bin.tar.gz -C /opt/hive
环境变量:
# ...
export HIVE_HOME=/opt/hive/apache-hive-3.1.2-bin
export PATH=$PATH:$HIVE_HOME/bin
Jar 包冲突:
rm -rf $HIVE_HOME/lib/guava-19.0.jar
cp $HADOOP_HOME/share/hadoop/common/lib/guava-27.0-jre.jar $HIVE_HOME/lib
3.2 QuickStart
MySQL
可以直接在宿主机启动一份 MySQL 并创建 hive 元数据数据库:
create database hive;
在 Hive 的 lib 目录添加驱动:
curl https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.24/mysql-connector-java-8.0.24.jar -o $HIVE_HOME/lib/mysql-connector-java-8.0.24.jar
配置文件
参考:
core-site.xml
vim $HADOOP_HOME/etc/hadoop/core-site.xml
<configuraiton>
<!-- ... -->
<property>
<name>hadoop.proxyuser.root.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.groups</name>
<value>*</value>
</property>
</configuraiton>
hive-site.xml
vim $HIVE_HOME/conf/hive-site.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.cj.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://win10:3306/hive</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>root</value>
</property>
<property>
<name>hive.metastore.uris</name>
<value>thrift://node101:9083</value>
</property>
<property>
<name>hive.server2.thrift.bind.host</name>
<value>node101</value>
</property>
</configuration>
初始化元数据库
schematool -initSchema -dbType mysql
启动 MetaStore
nohup hive --service metastore 1>/dev/null 2>&1 &
# 使用 jps 和 kill -9 结束
Hive Shell
create database test;
use test;
create table student (
name string,
gender tinyint,
deskmates array<string>,
score struct<chinese:int, math:int, english:int>,
refs map<string, string>
) row format delimited fields terminated by '|' collection items terminated by ',' map keys terminated by ':' lines terminated by '\n';
insert 语句:
insert into student values ('教主', 1, array('雯玉', '芳'), named_struct('chinese', 90, 'math', 90, 'english', 90), map('height', '165', 'weight', '55', 'eyesight', '0.2'));
文件导入:
vim ~/student.txt
芳|2|教主|120,110,120|height:165,weight:50,eyesight:1.0
雯玉|2|教主|110,120,120|height:160,weight:45,eyesight:0.2
load data local inpath '/root/student.txt' into table student;
select * from student;
dfs -ls /user/hive/warehouse;
JDBC 访问 Hive
# 启动 hiveserver2
nohup hive --service hiveserver2 1>/dev/null 2>&1 &
WEB 界面:http://node101:10002
使用 beeline 客户端连接:
beeline -u jdbc:hive2://node101:10000 -n root
DataGrip 也支持 Hive 连接。
查看日志:
tail -n 300 /tmp/root/hive.log
四、HBase
4.1 安装 hbase-2.3.5
curl https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/2.3.5/hbase-2.3.5-bin.tar.gz -o hbase-2.3.5-bin.tar.gz
mkdir -p /opt/hbase
tar -zxvf hbase-2.3.5-bin.tar.gz -C /opt/hbase
环境变量:
# ...
export HBASE_HOME=/opt/hbase/hbase-2.3.5
export PATH=$PATH:$HBASE_HOME/bin
4.2 HBase 集群
配置文件
HDFS 配置文件软链接
ln -s $HADOOP_HOME/etc/hadoop/core-ste.xml $HBASE_HOME/conf/core-site.xml
ln -s $HADOOP_HOME/etc/hadoop/hdfs-ste.xml $HBASE_HOME/conf/hdfs-site.xml
hbase-env.sh
# ...
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
#...
export HBASE_MANAGES_ZK=false
# ...
export HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP=true
#...
regionservers
node101
node102
node103
backup-masters
node102
node103
hbase-site.xml
<configuration>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.rootdir</name>
<value>hdfs://hdfs-cluster/hbase</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>win10:2181,win10:2182,win10:2183</value>
</property>
</configuration>
启动集群
# node101
start-hbase.sh
WEB 界面:http://node101:16010、http://node101:16030
HBase Shell
# 创建表
create 'student', 'info', 'score'
# 列出表
list
# 查看表结构
describe 'student'
# 插入数据
put 'student', '1', 'info:name', 'icefery'
put 'student', '1', 'info:gender', '1'
put 'student', '1', 'score:math', '120'
put 'student', '2', 'info:name', 'fang'
put 'student', '2', 'info:gender', '2'
put 'student', '2', 'score:math', '110'
put 'student', '3', 'info:name', 'wenyu'
put 'student', '3', 'info:gender', '2'
put 'student', '3', 'score:math', '120'
# 扫描查看表数据
scan 'student'
# 统计表行数
count 'student'
# 查看指定行
get 'student', '1'
get 'student', '1', 'info:name'
# 删除指定行
delete 'student', '1', 'info:name'
deleteall 'student', '1'
# 禁用表
disable 'student'
# 删除表
drop 'student'