hadoop simple note

代码地址

git@github.com:yunuotianming/nier.git

环境搭建

1.虚拟机网络配置
在网络适配器(网络连接)中,找到VMware Network Adapter VMnet8,修改网络配置为:
ip地址: 192.168.25.1 (固定ip即可,倒数第二网段和虚拟机(编辑 -> 虚拟网络编辑器 中的保持一致)
子网掩码: 255.255.255.0
默认网关: 192.168.25.2 (和虚拟机"虚拟网络编辑器"中配置保持一致,且虚拟机配置 /etc/sysconfig/network-scripts/ifcfg-eth** 时也要保持一致)

首选DNS服务器: 8.8.8.8

2.针对虚拟机特殊配置
VMware 如果版本不一致,需要以txt形式修改配置中的版本
修改
CentOS 6 64 位.vmx
参数对应自己安装的VMware版本
virtualHW.version = “12”

并在
虚拟机右键,选择"设置"
点击"选项" -> “常规” -> “客户机操作系统” -> “linux” -> “版本 CentOS6”

内存建议 2.5G+
cpu核数建议 2+

会常用到的命令:
ps -ef|grep sshd
ps -ef|grep sshd|grep -v grep
grep -n ‘hello’ a.txt

查找文件并显示详细信息
find . -name “*.log” -ls
查找/root/目录下面权限为777的文件
find /root/ -perm 777
查找当前目录大于100M的文件
find . -size +100M

查询效率优于find的locate命令
需先安装:
yum -y install mlocate
安装后,会自动创建 /var/lib/mlocate/mlocate.db 数据库,以统计分析linux的所有文件
数据库每天更新一次,所以查询前需要先更新一次最新数据(文件都被索引了,所以查询比find快)

手动更新数据库
updatedb

查看/etc/下面所有以sh开头的文件
locate /etc/sh

查看和pwd相关的文件
locate pwd

用户相关
useradd 用户名: 添加用户
userdel 用户名: 删除用户
passwd 用户名: 设置密码

用户授权
chmod +w /etc/sudoers
vim /etc/sudoers
在文件最后添加如下内容:

add privilege for hadoop
hadoop ALL=(ALL) ALL
end

su 切换用户
建议使用切换时使用 su - 用户名 (切换用户并切换环境,仅仅使用su 可能切换会出现环境不对问题)
su - hadoop

授权
chmod 777 /home/hadoop -R
chmod u+x a.txt
chmod g-rwx a.txt

修改用户组:用户
chown -R hadoop:hadoop a.txt

系统服务命令
service 对应服务名 命令

service iptables status
service iptables stop

查看系统所有的后台服务进程
service --status-all

查看指定的后台服务进程的状态
service sshd status
关闭,启动,重启
service sshd stop
service sshd start
service sshd restart

配置防火墙开机开启/关闭
chkconfig iptables on
chkconfig iptables off

让httpd服务开机开启/关闭
chkconfig httpd on
chkconfig httpd off

编写shell脚本

语法:

约定(非必须)
一般shell脚本以 .sh 结尾

固定写法: /bin/bash 表示解析器为/bin下面的bash解析器(注意这里的#并不是注释)
#!/bin/bash

例:
创建存放shell的文件夹
mkdir /root/shells

创建文件并编辑脚本
vim hello.sh

添加下面内容:

#!/bin/bash
echo “Hello World !”

执行方式:
方式1:
sh hello.sh

方式2:
chmod +x ./hello.sh
./hello.sh

shell变量
局部变量:

vim hello2.sh
chmod +x hello2.sh

#!/bin/bash
str=“hello”
变量和其他字符串间有空格或制表符分割开,可以省略括号
echo $str World !
变量和其他字符串黏连,需要大括号
echo ${str}World !

环境变量:
使用命令查看环境变量
env

可看到
HOSTNAME=node01
SHELL=/bin/bash
TERM=xterm
HISTSIZE=1000
QTDIR=/usr/lib64/qt-3.3
QTINC=/usr/lib64/qt-3.3/include
USER=root
等等信息

自定义环境变量:
vim /etc/profile

在文件最后新增:

# jdk env begin
JAVA_HOME=/usr/local/jdk1.8.0_191
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH
# jdk env end
# maven env begin
export MAVEN_HOME=/opt/apache-maven-3.5.4
export PATH=$MAVEN_HOME/bin:$PATH
# maven env end

使环境配置文件生效:
source /etc/profile

#!/bin/bash
echo “Hello World !”

特殊字符:

$# -> 传递到脚本的参数个数
$* -> 以一个单字符串显示所有向脚本传递的参数。
$$ -> 脚本运行的当前进程 ID 号
$! -> 后台运行的最后一个进程的 ID 号
@ − > 与 @ -> 与 @>*相同,但是使用时加引号,并在引号中返回每个参数。
$? -> 显示最后命令的退出状态。 0 表示没有错误,其他任何值表明有错误。

例:

vim hello2.sh
chmod +x hello2.sh

#!/bin/bash
echo “第一个参数为: $1”;
echo “参数个数为: $#”;
echo “传递的参数作为一个字符串显示: $*”;

执行命令,并添加参数:
sh hello2.sh hello world hadoop

输出结果为:
第一个参数为: hello
参数个数为: 3
传递的参数作为一个字符串显示: hello world hadoop

运算符:

vim hello3.sh
chmod +x hello3.sh

#!/bin/bash
a=1;
b=2;
使用反引号可以解析反引号中间的命令, expr 对字符串,整数求值关键字, + - 运算符要通过空格隔开变量
echo expr $a + $b;
*需要转义为乘号,否则会被理解为匹配符
echo expr $a \* $b;
echo $((a+b));
echo $[a+b];

if语句:

#!/bin/bash
read命令用于从控制台读取输入数据, 并赋值给 NAME 变量
read -p “please input your name:” NAME
printf ‘%s\n’ $NAME 根据输入信息打印内容
注意 [ ] 两边都需要预留空格, = 两边也需要预留空格, = 这里表示的不是赋值而是判断
if [ $NAME = root ]
then
echo “hello ${NAME}, welcome !”
elif [ $NAME = gin ]
then
echo “hello ${NAME}, welcome !”
else
echo “Get out Please!”
fi

for 语句:
方式1:

#!/bin/bash
for N in 1 2 3
do
echo $N
done

方式2:
#!/bin/bash
for ((i = 0; i <= 5; i++))
do
echo “welcome $i times”
done

函数

#!/bin/bash
#需要定义函数名
funWithReturn(){
echo “这个函数会对输入的两个数字进行相加运算…”
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo “两个数字分别为 $aNum 和 $anotherNum !”
return ( ( (( ((aNum+$anotherNum))
}
#这里表示调用函数(直接写上函数名即可)
funWithReturn
$? 表示返回上一次变量的返回值
echo “输入的两个数字之和为 $? !”

linux系统需要关闭SElinux,安全模式较为复杂

vi /etc/selinux/config

#将强制安全模式注释掉,并新增一行为关闭状态
#SELINUX=enforcing
SELINUX=disabled

集群间机器免密访问:
通过公私钥进行安全认证

配置步骤:
1.生成公私钥
ssh-keygen -t rsa
直接回车即可

查看公私钥:
cd /root/.ssh

  1. 把需要访问该主机的服务器

所有共享访问的服务机器的公钥将拷贝到第一台机器中
(本机也要拷贝,会生成互联公钥信息到 authorized_keys 中)
执行命令:

ssh-copy-id node01

ssh-copy-id 192.168.25.110

3.复制第一台机器的认证到其他机器

将第一台机器的公钥信息集合文件拷贝到其他机器上
scp /root/.ssh/authorized_keys node02:/root/.ssh
scp /root/.ssh/authorized_keys node03:/root/.ssh
scp /root/.ssh/authorized_keys node04:/root/.ssh

验证免密登录:
在第一台机器上执行:
ssh node02

ssh 192.168.25.120

机器时钟同步
因为很多分布式系统是有状态的, 比如说存储一个数据, A节点 记录的时间是 1, B节点 记录的时间是 2, 就会出问题

安装时间同步服务器
yum install -y ntp

启动定时任务
crontab -e

编辑输入,每分钟同步一次(分别代表 分 时
*/1 * * * * /usr/sbin/ntpdate ntp4.aliyun.com;

查看日期:
date

查看自带的openjdk(需卸载)
rpm -qa | grep java

卸载系统自带的openjdk(根据上面显示的信息进行删除)
rpm -e java-1.6.0-openjdk-1.6.0.41-1.13.13.1.el6_8.x86_64 tzdata-java-2016j-1.el6.noarch java-1.7.0-openjdk-1.7.0.131-2.6.9.0.el6_8.x86_64 --nodeps

查看是否卸载完成
rpm -qa | grep java

将jdk解压到指定目录后,修改环境配置:
vim /etc/profile

cancel mail check
unset MAILCHECK

#jdk env begin
JAVA_HOME=/home/hadoop/mw/jdk1.8.0_141
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH
#jdk env end

zookeeper配置
拷贝一份配置 cp zoo_sample.cfg zoo.cfg

修改下列内容:

dataDir=/home/hadoop/mw/zookeeper-3.4.9/zkdatas
保留多少个快照
autopurge.snapRetainCount=3
日志多少小时清理一次
autopurge.purgeInterval=1
#集群中服务器地址
server.1=node01:2888:3888
server.2=node02:2888:3888
server.3=node03:2888:3888

zookeeper-3.4.9/zkdatas /这个路径下创建一个文件,文件名为myid ,文件内容为1(每台机器不同)
echo 1 > zkdatas/myid

启动
bin/zkServer.sh start

启动状态查看
bin/zkServer.sh status

集群启动时的简单选举:
第一台启动时是不会进行选举的,
第二台启动时,会开始投票,这时第一台给自己投票,第二台也是给自己投票;这时各自有一票,则比较myid中的值谁更大

复杂选举:
当主节点宕机,
从第一台开始投票,均投给自己;没有服务器获得半数以上支持则不能选举出leader;
这时第二台开始发起投票,这时第一台投票给第二台,第二台投票给自己,如此继续下去,直至有服务获取半数以上投票

Zookeeper的Shell 客户端操作
通过
bin/zkCli.sh
来启动zk的客户端连接

命令说明参数
create [-s] [-e] path data acl创建Znode,path为路径,data为创建节点包含的数据-s 指定是顺序节点
-e 指定是临时节点
ls path [watch]列出Path下所有子Znode
get path [watch]获取Path对应的Znode的数据和属性
ls2 path [watch]查看Path下所有子Znode以及子Znode的属性
set path data [version]更新节点version 数据版本
delete path [version]删除节点, 如果要删除的节点有子Znode则无法删除version 数据版本
rmr path删除节点, 如果有子Znode则递归删除
setquota -n|-b val path修改Znode配额-n 设置子节点最大个数
-b 设置节点数据最大长度
history列出历史记录

1:创建普通节点
app1表示节点名(路径); hello表示当前节点(app1包含的数据)
create /app1 hello

2: 创建顺序节点

create -s /app3 world

3:创建临时节点

create -e /tempnode world

4:创建顺序的临时节点(客户端和临时节点断开则临时会消失)

create -s -e /tempnode2 aaa

5:获取节点数据

get /app1

6:修改节点数据

set /app1 xxx

7:删除节点

删除的节点不能有子节点
delete /app1

递归删除
rmr /app1

修改配置文件(注意:编码不对会格式化失败,建议直接vi编辑,复制)
配置文件的位置在
cd /home/hadoop/mw/hadoop-3.1.1/etc/hadoop

core-site.xml

fs.defaultFS hdfs://node01:8020 hadoop.tmp.dir /home/hadoop/mw/hadoop-3.1.1/datas/tmp io.file.buffer.size 8192 fs.trash.interval 10080
<!-- 注意!!!如果使用hive,那么需要添加下面两项配置 -->
<!-- 
<property>
	<name>hadoop.proxyuser.hadoop.hosts</name>
	<value>*</value>
</property>
<property>
	<name>hadoop.proxyuser.hadoop.groups</name>
	<value>root</value>
</property>
-->

hadoop-env.sh
(搜索 export JAVA_HOME,打开注释并配置,
注意带 export ,因为env包含了两个修改 JAVA_HOME 的位置)

export JAVA_HOME=/home/hadoop/mw/jdk1.8.0_141

这里配置错误,在运行时会出现下列错误:
Container exited with a non-zero exit code 127. Error file: prelaunch.err.
Last 4096 bytes of prelaunch.err :
Last 4096 bytes of stderr :
/bin/bash: /bin/java: No such file or directory

如果配置没有问题还存在报错,可将 JAVA_HOME 软连接到 /bin/java
ln -s /home/hadoop/mw/jdk1.8.0_141/bin/java /bin/java

hdfs-site.xml

dfs.namenode.name.dir file:///home/hadoop/mw/hadoop-3.1.1/datas/namenode/namenodedatas dfs.blocksize 134217728 dfs.namenode.handler.count 10 dfs.datanode.data.dir file:///home/hadoop/mw/hadoop-3.1.1/datas/datanode/datanodeDatas dfs.namenode.http-address node01:50070 dfs.replication 3 dfs.permissions.enabled false dfs.namenode.checkpoint.edits.dir file:///home/hadoop/mw/hadoop-3.1.1/datas/dfs/nn/snn/edits dfs.namenode.secondary.http-address node01.hadoop.com:50090 dfs.namenode.edits.dir file:///home/hadoop/mw/hadoop-3.1.1/datas/dfs/nn/edits dfs.namenode.checkpoint.dir file:///home/hadoop/mw/hadoop-3.1.1/datas/dfs/snn/name

mapred-site.xml

mapreduce.framework.name yarn mapreduce.map.memory.mb 1024 mapreduce.map.java.opts -Xmx512M mapreduce.reduce.memory.mb 1024 mapreduce.reduce.java.opts -Xmx512M mapreduce.task.io.sort.mb 256 mapreduce.task.io.sort.factor 100 mapreduce.reduce.shuffle.parallelcopies 25 mapreduce.jobhistory.address node01.hadoop.com:10020 mapreduce.jobhistory.webapp.address node01.hadoop.com:19888 mapreduce.jobhistory.intermediate-done-dir /home/hadoop/mw/hadoop-3.1.1/datas/jobhsitory/intermediateDoneDatas mapreduce.jobhistory.done-dir /home/hadoop/mw/hadoop-3.1.1/datas/jobhsitory/DoneDatas yarn.app.mapreduce.am.env HADOOP_MAPRED_HOME=/home/hadoop/mw/hadoop-3.1.1 mapreduce.map.env HADOOP_MAPRED_HOME=/home/hadoop/mw/hadoop-3.1.1/ mapreduce.reduce.env HADOOP_MAPRED_HOME=/home/hadoop/mw/hadoop-3.1.1

yarn-site.xml

dfs.namenode.handler.count 100 yarn.log-aggregation-enable true yarn.resourcemanager.address node01:8032 yarn.resourcemanager.scheduler.address node01:8030 yarn.resourcemanager.resource-tracker.address node01:8031 yarn.resourcemanager.admin.address node01:8033 yarn.resourcemanager.webapp.address node01:8088 yarn.resourcemanager.hostname node01 yarn.scheduler.minimum-allocation-mb 1024 yarn.scheduler.maximum-allocation-mb 2048 yarn.nodemanager.vmem-pmem-ratio 2.1 yarn.nodemanager.vmem-check-enabled false yarn.nodemanager.resource.memory-mb 1024 yarn.nodemanager.resource.detect-hardware-capabilities true yarn.nodemanager.local-dirs file:///home/hadoop/mw/hadoop-3.1.1/datas/nodemanager/nodemanagerDatas yarn.nodemanager.log-dirs file:///home/hadoop/mw/hadoop-3.1.1/datas/nodemanager/nodemanagerLogs yarn.nodemanager.log.retain-seconds 10800 yarn.nodemanager.remote-app-log-dir /home/hadoop/mw/hadoop-3.1.1/datas/remoteAppLog/remoteAppLogs yarn.nodemanager.remote-app-log-dir-suffix logs yarn.nodemanager.aux-services mapreduce_shuffle yarn.log-aggregation.retain-seconds 18144000 yarn.log-aggregation.retain-check-interval-seconds 86400 yarn.app.mapreduce.am.resource.mb 1024

worker 配置文件,添加对应主机的hostname

node01 对应hdfs yarn 访问页面
node01.hadoop.com 对应一些页面上下载上传操作

192.168.25.110 node01 node01.hadoop.com
192.168.25.120 node02 node02.hadoop.com
192.168.25.130 node03 node03.hadoop.com

创建配置对应文件夹
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/tmp
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/dfs/nn/snn/edits
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/namenode/namenodedatas
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/datanode/datanodeDatas
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/dfs/nn/edits
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/dfs/snn/name
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/jobhsitory/intermediateDoneDatas
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/jobhsitory/DoneDatas
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/nodemanager/nodemanagerDatas
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/nodemanager/nodemanagerLogs
mkdir -p /home/hadoop/mw/hadoop-3.1.1/datas/remoteAppLog/remoteAppLogs

切换到修改好的目录下面,再将修改好的配置分发到其他服务器
cd /home/hadoop/mw/hadoop-3.1.1/etc
P W D 获 取 的 是 当 前 会 话 s h e l l 的 当 前 路 径 ( 即 : 这 时 PWD 获取的是当前会话shell的当前路径(即: 这时 PWDshell(:PWD 等价于 /home/hadoop/mw/hadoop-3.1.1/etc)
scp -r hadoop/ node04:$PWD

在每个节点配置环境变量
sudo vim /etc/profile

hadoop env begin
export HADOOP_HOME=/home/hadoop/mw/hadoop-3.1.1/
export PATH=: H A D O O P H O M E / b i n : HADOOP_HOME/bin: HADOOPHOME/bin:HADOOP_HOME/sbin:$PATH
hadoop env end

source /etc/profile

格式化HDFS

  • 为什么要格式化HDFS
    • HDFS需要一个格式化的过程来创建存放元数据(image, editlog)的目录
      (注意:如果格式化失败,可能是配置文件编码格式不对,建议直接vi 编辑,复制)
      cd /home/hadoop/mw/hadoop-3.1.1
      bin/hdfs namenode -format

设置/home/hadoop/mw/hadoop-3.1.1/etc/hadoop/hadoop-env.sh
在文件最后添加:

Users using Hadoop
export HDFS_NAMENODE_USER=“root”
export HDFS_DATANODE_USER=“root”
export HDFS_SECONDARYNAMENODE_USER=“root”
export YARN_RESOURCEMANAGER_USER=“root”
export YARN_NODEMANAGER_USER=“root”

启动集群

/home/hadoop/mw/zookeeper-3.4.9/bin/zkServer.sh start

#会登录进所有的worker启动相关进行, 也可以手动进行, 但是没必要
(直接在node01这台主节点服务器执行命令即可,从节点会对应启动)
1.执行下列命令,先启动hdfs:
/home/hadoop/mw/hadoop-3.1.1/sbin/start-dfs.sh

jps显示为:
3873 SecondaryNameNode
4213 Jps
2774 QuorumPeerMain
3658 DataNode
3498 NameNode

2.执行下列命令,再启动yarn:
/home/hadoop/mw/hadoop-3.1.1/sbin/start-yarn.sh

jps显示为:(新增了 NodeManager ResourceManager )
3873 SecondaryNameNode
5441 ResourceManager
5826 Jps
2774 QuorumPeerMain
3658 DataNode
5594 NodeManager
3498 NameNode

3.执行下列命令,再启动mapred 历史信息查看:
mapred --daemon start historyserver

停止集群
mapred --daemon stop historyserver
/home/hadoop/mw/hadoop-3.1.1/sbin/stop-yarn.sh
/home/hadoop/mw/hadoop-3.1.1/sbin/stop-dfs.sh

浏览器范文验证:

  • HDFS:
    http://192.168.25.110:50070/dfshealth.html#tab-overview
    显示 Overview ‘node01:8020’ (active) 表示成功运行
  • Yarn:
    http://192.168.25.110:8088/cluster

测试上传文件:

cd /home/hadoop/
mkdir test
cd /home/hadoop/test
touch abc.txt
hdfs dfs -put abc.txt /

文件查看页面
http://192.168.25.110:50070/explorer.html#/

hdfs常用的操作命令
hdfs dfs -ls / 查看根路径下面的文件或者文件夹
hdfs dfs -mkdir -p /xx/xxx 在hdfs上面递归的创建文件夹
hdfs dfs -moveFromLocal sourceDir(本地磁盘的文件或者文件夹的路径) destDir(hdfs的路径)
hdfs dfs -mv hdfsSourceDir hdfsDestDir
hdfs dfs -put localDir hdfsDir 将本地文件系统的文件或者文件夹放到hdfs上面去
hdfs dfs -appendToFile a.txt b.txt /hello.txt
hdfs dfs -cat hdfsDir 查看hdfs的文件内容
hdfs dfs -cp hdfsSourceDIr hdfsDestDir 拷贝文件或者文件夹
hdfs dfs -rm [-r] (递归)删除文件或者文件夹

hdfs的权限管理两个命令:
hdfs dfs -chmod -R 777 /xxx
hdfs dfs -chown -R hadoop:hadoop /xxx

在windows系统配置hadoop运行环境:

第一步:将apache-hadoop-3.1.1(需要下载windows版本的)文件夹拷贝到一个没有中文没有空格的路径下面

第二步:在windows上面配置hadoop的环境变量:
-> 添加一条环境变量 HADOOP_HOME
-> 将 HADOOP_HOME 添加到 PATH 中: %HADOOP_HOME%\bin

第三步:把bin目录下的hadoop.dll文件放到系统盘里面去 C:\Windows\System32

第四步:关闭windows重启

hdfs访问权限控制
停止hdfs集群,在node01机器上执行以下命令
cd /home/hadoop/mw/hadoop-3.1.1
sbin/stop-dfs.sh

修改node01机器上的hdfs-site.xml当中的配置文件
cd /home/hadoop/mw/hadoop-3.1.1/etc/hadoop
vim hdfs-site.xml

#之前配置文件默认的是 false,方便操作(其他系统操作,也会校验该系统的用户名)
如需要开启权限控制,设置为 true 即可

dfs.permissions.enabled true

修改完成之后配置文件发送到其他机器上面去
scp hdfs-site.xml node02: P W D s c p h d f s − s i t e . x m l n o d e 03 : PWD scp hdfs-site.xml node03: PWDscphdfssite.xmlnode03:PWD

随意上传一些文件到我们hadoop集群当中准备测试使用
cd /home/hadoop/mw/hadoop-3.1.1/etc/hadoop
hdfs dfs -mkdir /config
hdfs dfs -put *.xml /config
hdfs dfs -chmod 600 /config/core-site.xml

这时候再下载会发现并没有权限

MapReduce
Map负责“分”,即把复杂的任务分解为若干个“简单的任务”来并行处理。
可以进行拆 分的前提是这些小任务可以并行计算,彼此间几乎没有依赖关系。

Reduce负责“合”,即对map阶段的结果进行全局汇总。

构建抽象模型:
Map和Reduce MapReduce借鉴了函数式语言中的思想,
用Map和Reduce两个函数提供了高层的并行编程抽象模型
Map: 对一组数据元素进行某种重复式的处理;
Reduce: 对Map的中间结果进行某种进一步的结果整理。
Map和Reduce为程序员提供了一个清晰的操作接口抽象描述。
MapReduce 处理的数据类型是键值对。
MapReduce中定义了如下的Map和Reduce两个抽象的编程接口,由用户去编程实现:
Map: (k1; v1) → [(k2; v2)]
Reduce: (k2; [v2]) → [(k3; v3)]

MapReduce运行在yarn集群

  1. ResourceManager (主节点,接收(Applications Manager),分发(Resource Scheduler)任务)
  2. NodeManager

一个完整的mapreduce程序在分布式运行时有三类实例进程:

  1. MRAppMaster 负责整个程序的过程调度及状态协调
  2. MapTask 负责map阶段的整个数据处理流程
  3. ReduceTask 负责reduce阶段的整个数据处理流程

在 MapReduce 中, Reduce 当中默认的分区只有一个通过我们指定分区(根据业务需求,对k2进行分区),
会将同一个分区的数据发送到同一个 Reduce 当中进行处理, 并生成一个reduce结果文件
例如: 为了数据的统计, 可以把一批类似的数据发送到同一个 Reduce 当中,
在同一个 Reduce 当中统计相同类型的数据, 就可以实现类似的数据分区和统计等
其实就是相同类型的数据, 有共性的数据, 送到一起去处理
Reduce 当中默认的分区只有一个

Map: (k1; v1) → [(k2; v2)]
Reduce1: (k2(对2取模余0的数据); [v2]) → [(k3; v3)] -> 结果文件1
Reduce2: (k2(对2取模余1的数据); [v2]) → [(k3; v3)] -> 结果文件2
结果文件1+结果文件2 = 原先未切割分区的reduce的结果

每一个 map 都可能会产生大量的本地输出,
Combiner 的作用就是对 map 端的输出先做一次合并(在map端先做一次reduce),
以减少在 map 和 reduce 节点之间的数据传输量,以提高网络IO性能,
是 MapReduce 的一种优化手段之一.

combiner 是 MR 程序中 Mapper 和 Reducer 之外的一种组件
combiner 组件的父类就是Reducer(combiner 和 reducer 的区别在于运行的位置)
Combiner 是在每一个 maptask 所在的节点运行
Reducer 是接收全局所有 Mapper 的输出结果
combiner 的意义就是对每一个 maptask 的输出进行局部汇总,以减小网络传输量

Hive的安装
上传并解压安装包 将我们的hive的安装包(需要对应hadoop安装版本)上传到第一台服务,
然后进行解压
tar -zxvf apache-hive-3.1.0-bin.tar.gz -C /home/hadoop/

由于hive自带数据库不是特别好使用,故安装
第一步:在线安装mysql相关的软件包
yum install mysql mysql-server mysql-devel

第二步:启动mysql的服务
/etc/init.d/mysqld start

第三步:通过mysql安装自带脚本进行设置
/usr/bin/mysql_secure_installation

设置root密码: 123456
Set root password? [Y/n] Y
New password:
Re-enter new password:

移除匿名用户,可选Y
Remove anonymous users? [Y/n] Y
… Success!

禁止远程访问:需选n
Disallow root login remotely? [Y/n] n

移除测试数据库:可选n
Remove test database and access to it? [Y/n] n

重新加载权限表:需选Y
Reload privilege tables now? [Y/n] Y

第四步:进入mysql的客户端然后进行授权
mysql -u root -p
grant all privileges on . to ‘root’@’%’ identified by ‘123456’ with grant option;
flush privileges;

修改hive的配置文件
修改hive-env.sh
cd /home/hadoop/mw/apache-hive-3.1.0-bin/conf
cp hive-env.sh.template hive-env.sh
vim hive-env.sh

找到 HADOOP_HOME 和 export HIVE_CONF_DIR并设置地址
HADOOP_HOME=/home/hadoop/mw/hadoop-3.1.1/
export HIVE_CONF_DIR=/home/hadoop/mw/apache-hive-3.1.0-bin/conf

如果没有hive-site.xml则新建一个,将下面内容添加进去
cd /home/hadoop/mw/apache-hive-3.1.0-bin/conf
vim hive-site.xml
分别是对 数据库用户,密码,位置,(createDatabaseIfNotExist表示不存在就会自动创建)
连接驱动,是否校验格式,是否自动创建,绑定mysql所在服务器域名等的设置

<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> javax.jdo.option.ConnectionUserName root javax.jdo.option.ConnectionPassword 123456 javax.jdo.option.ConnectionURL jdbc:mysql://node01:3306/hive?createDatabaseIfNotExist=true&useSSL=false javax.jdo.option.ConnectionDriverName com.mysql.jdbc.Driver hive.metastore.schema.verification false datanucleus.schema.autoCreateAll true hive.server2.thrift.bind.host node01.hadoop.com

添加mysql的连接驱动包到hive的lib目录下
hive使用mysql作为元数据存储,必然需要连接mysql数据库,所以我们添加一个mysql的连接驱动包到
hive的安装目录下,然后就可以准备启动hive
将我们准备好的mysql-connector-java-5.1.38.jar 这个jar包直接上传到
/home/hadoop/mw/apache-hive-3.1.0-bin/lib 这个目录下即可

配置hive的环境变量
node01服务器执行以下命令配置hive的环境变量
sudo vim /etc/profile
export HIVE_HOME=/home/hadoop/mw/apache-hive-3.1.0-bin/
export PATH=: H I V E H O M E / b i n : HIVE_HOME/bin: HIVEHOME/bin:PATH

source /etc/profile

Hive 的三种交互方式
第一种交互方式 bin/hive
cd /home/hadoop/mw/apache-hive-3.1.0-bin
执行 hive 命令,hive则会开始加载
bin/hive
创建一个数据库
create database if not exists mytest;
show databases;
use mytest;
create table my_test(id int, name string);
show tables;

第二种交互方式 HiveServer2
hive官方推荐使用hiveserver2的这种交互方式,
需要我们启动hiveserver2这个服务端,
然后通过客户端去进行连接

启动服务端(前台启动命令如下)
cd /home/hadoop/mw/apache-hive-3.1.0-bin
bin/hive --service hiveserver2

重新开一个窗口启动我们的客户单进行连接
cd /home/hadoop/mw/apache-hive-3.1.0-bin
bin/beeline
!connect jdbc:hive2://node01.hadoop.com:10000
进行连接,用户名为root 密码为123456出现以下错误
User: root is not allowed to impersonate root (state=08S01,code=0)
注意: User:后面的是对应无权限的用户名,需要在 core-site.xml 对应配置,name的值也取决于用户名!!!

解决方法:关闭hive的服务端,在hadoop的配置文件
/home/hadoop/mw/hadoop-3.1.1/etc/hadoop/core-site.xml当中添加以下两行配置,

如果User:后面对应的用户名是hadoop,则name值为:

hadoop.proxyuser.hadoop.hosts



hadoop.proxyuser.hadoop.groups

如果User:后面对应的用户名是root,则name值为:

hadoop.proxyuser.root.hosts



hadoop.proxyuser.root.groups

然后重启hdfs以及yarn集群
mapred --daemon stop historyserver &&
/home/hadoop/mw/hadoop-3.1.1/sbin/stop-yarn.sh &&
/home/hadoop/mw/hadoop-3.1.1/sbin/stop-dfs.sh;

/home/hadoop/mw/hadoop-3.1.1/sbin/start-dfs.sh &&
/home/hadoop/mw/hadoop-3.1.1/sbin/start-yarn.sh &&
mapred --daemon start historyserver;

重新进行启动hive的服务端,然后继续使用客户端进行连接即可
启动服务端
cd /home/hadoop/mw/apache-hive-3.1.0-bin
/home/hadoop/mw/apache-hive-3.1.0-bin/bin/hive --service hiveserver2

守护启动:
nohup hiveserver2 1>./hiveserver.log 2>./hiveserver_error.log &

开一个新的xshell会话窗口,客户端进行连接
cd /home/hadoop/mw/apache-hive-3.1.0-bin
/home/hadoop/mw/apache-hive-3.1.0-bin/bin/beeline
!connect jdbc:hive2://node01.hadoop.com:10000

会显示开始连接:
Connecting to jdbc:hive2://node01.hadoop.com:10000
输入用户名: hadoop(注意:这里是安装hadoop集群的用户名,这里是使用hadoop安装的,
有些使用root或其他用户名安装的,要使用对应的用户名)
Enter username for jdbc:hive2://node01.hadoop.com:10000: hadoop
输入密码:123456(对应用户名的密码)
Enter password for jdbc:hive2://node01.hadoop.com:10000: ******
连接成功信息,命令栏:
Connected to: Apache Hive (version 3.1.0)
Driver: Hive JDBC (version 3.1.0)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://node01.hadoop.com:10000>

第三种交互方式:使用sql语句或者sql脚本进行交互
不进入hive的客户端直接执行hive的hql语句
cd /home/hadoop/mw/apache-hive-3.1.0-bin
bin/hive -e “create database if not exists mytest;”
或者我们可以将我们的hql语句写成一个sql脚本然后执行
cd /home/hadoop/mw
vim hive.sql

– hive.sql test begin
create database if not exists mytest;
use mytest;
create table stu(id int,name string);
– hive.sql test end

通过hive -f 来执行我们的sql脚本
hive -f hive.sql

会显示执行成功:
Logging initialized using configuration in jar:file:/home/hadoop/mw/apache-hive-3.1.0-bin/lib/hive-common-3.1.0.jar!/hive-log4j2.properties Async: true
Hive Session ID = 97e86ba8-5b57-473d-aca1-ec9976af6c0a
OK
Time taken: 1.185 seconds
OK
Time taken: 0.024 seconds
OK
Time taken: 0.772 seconds

创建数据库(数据库均以文件形式存放在hdfs的目录中)
默认位置: /user/hive/warehouse/

create database if not exists myhive;
use myhive;

hive的表存放位置模式是由hive-site.xml当中的一个属性指定的
hive.metastore.warehouse.dir
/user/hive/warehouse

创建数据库并指定位置
create database mytest location ‘/mytest’;

修改数据库
可以使用alter database 命令来修改数据库的一些属性。但是数据库的元数据信息是不可更改的,
包括数据库的名称以及数据库所在的位置
alter database mytest set dbproperties(‘createtime’=‘20180611’);

查看数据库信息:
查看数据库基本信息
desc database mytest;

查看数据库更多详细信息
desc database extended mytest;

删除数据库
删除一个空数据库,如果数据库下面有数据表,那么就会报错
drop database mytest;

强制删除数据库,包含数据库下面的表一起删除(不要轻易执行)
drop database myhive cascade;

创建数据库表的语法
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], …)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], …)]
[CLUSTERED BY (col_name, col_name, …)
[SORTED BY (col_name [ASC|DESC], …)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
说明:

  1. CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,
    则抛出异常;用户可以用IF NOT EXISTS 选项来忽略这个异常。
  2. EXTERNAL关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),
    Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,
    不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,
    而外部表只删除元数据,不删除数据(外部表相对安全)。
  3. LIKE 允许用户复制现有的表结构,但是不复制数据。
  4. ROW FORMAT DELIMITED 行分隔符
    [FIELDS TERMINATED BY char]
    [COLLECTION ITEMSTERMINATED BY char]
    [MAP KEYS TERMINATED BY char]
    [LINES TERMINATED BY char] |SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value, …)]
    用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者
    ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列
    用户在指定表的列的同时也会指定自定义的 SerDe,Hive通过 SerDe 确定表的具体的列的数据。
  5. STORED AS
    SEQUENCEFILE|TEXTFILE|RCFILE
    如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
  6. PARTITIONED BY(文件夹数量太多,则需要分区,即分文件夹存储)
    分区,一个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下
  7. SORTED BY
    排序
  8. ROW FORMAT
    指定数据之间的分隔符
  9. CLUSTERED BY (单个文件太大,则需要分桶拆分文件)
    对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范
    围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方
    式决定该条记录存放在哪个桶当中。
    把表(或者分区)组织成桶(Bucket)有两个理由:
  10. 获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结
    构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接
    (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果
    对这两个表都进了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。
  11. 使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在
    数据集的一小部分数据上试运行查询,会带来很多方便

建表测试(虚拟机时间不同步添加数据会出Check time and time zones错, 需执行 /usr/sbin/ntpdate ntp4.aliyun.com; )

– 创建内部表
/home/hadoop/mw/apache-hive-3.1.0-bin/bin/hive
create database if not exists myhive;
use myhive;
create table stu(id int,name string);
– 尽量避免在hive中进行数据插入或修改,会启动mapreduce,比较消耗资源,主要应在hive进行数据分析)
insert into stu values (1,“zhangsan”);
insert into stu values (2,“nier”);
insert into stu values (3,“luffy”);

select * from stu;

创建表并指定字段之间的分隔符
create table if not exists stu2(id int ,name string) row format delimited fields terminated by ‘\t’;
insert into stu2 values (4,“gin”);
insert into stu2 values (5,“naruto”);
select * from stu2;

根据查询结果创建表
– 通过复制表结构和表内容创建新表
create table stu3 as select * from stu2;
select * from stu3;

根据已经存在的表结构创建表
– 拷贝表结构,不复制内容
create table stu4 like stu2;

外部表的操作
外部表说明
外部表因为是指定其他的hdfs路径的数据加载到表当中来,
所以hive表会认为自己不完全独占这份数据,所以删除hive表的时候,
数据仍然存放在hdfs当中,不会删掉
/home/hadoop/mw/apache-hive-3.1.0-bin/bin/hive

创建老师表
create external table teacher (t_id string,t_name string) row format delimited fields terminated by ‘\t’;

创建学生表
create external table student (s_id string,s_name string,s_birth string , s_sex string ) row format delimited fields terminated by ‘\t’;

加载数据
load data local inpath ‘/home/hadoop/software/student.csv’ into table student;

加载数据并覆盖已有数据
load data local inpath ‘/home/hadoop/software/student.csv’ overwrite into table student;

从hdfs文件系统向表中加载数据(需要提前将数据上传到hdfs文件系统)
在linux的shell命令中执行
cd /home/hadoop/software/
hdfs dfs -mkdir -p /hivedatas
hdfs dfs -put techer.csv /hivedatas/
在hive中执行加载(是个剪切操作)
load data inpath ‘/hivedatas/techer.csv’ into table teacher;

分区表
在大数据中,最常用的一种思想就是分治,我们可以把大的文件切割划分成一个个的小的文件,
这样每次操作一个小的文件就会很容易了,同样的道理,在hive当中也是支持这种思想的,
就是我们可以把大的数据,按照每天,或者每小时进行切分成一个个的小的文件,
这样去操作小的文件就会容易得多了
创建分区表语法
/home/hadoop/mw/apache-hive-3.1.0-bin/bin/hive
create database if not exists myhive;
use myhive;
创建一个表带多个分区
create table score(s_id string,c_id string, s_score int) partitioned by (month string) row format delimited fields terminated by ‘\t’;
create table score2 (s_id string,c_id string, s_score int) partitioned by (year string,month string,day string) row format delimited fields terminated by ‘\t’;

加载数据到分区表中(分文件存放,/user/hive/warehouse/myhive.db/score/month=201806)
load data local inpath ‘/home/hadoop/software/score.csv’ into table score partition (month=‘201806’);

加载数据到多分区表中(分文件存放,那么存放路径为 /user/hive/warehouse/myhive.db/score2/year=2018/month=06/day=01 )
load data local inpath ‘/home/hadoop/software/score.csv’ into table score2 partition(year=‘2018’,month=‘06’,day=‘01’);

查看分区数据(where 条件后面接 分区名)
select * from score where month=‘201806’;
select * from score2 where day=‘01’;

多分区表联合查询(使用 union all )
select * from score where month = ‘201806’ union all select * from score where month = ‘201806’;

查看分区(分文件存放,/user/hive/warehouse/myhive.db/score/month=201806)
show partitions score;

添加一个分区
alter table score add partition(month=‘201805’);
查看是否添加成功
show partitions score;

删除分区
alter table score drop partition(month = ‘201806’);

分桶表
将数据按照指定的字段进行分成多个桶中去,说白了就是将数据按照字段进行划分,
可以将数据按照字段划分到多个文件当中去.

查看 分桶 默认值:
set hive.enforce.bucketing;
开启 Hive 的分桶功能
set hive.enforce.bucketing=true;

设置 Reduce 个数
set mapreduce.job.reduces=3;
查看设置是否成功:
set mapreduce.job.reduces;

创建桶表( clustered分桶字段必须是前面建表存在的字段,会通过hash算法对字段进行分桶)
create table course (c_id string,c_name string,t_id string) clustered by(c_id) into 3 buckets row format delimited fields terminated by ‘\t’;

桶表的数据加载,由于通标的数据加载通过hdfs dfs -put文件或者通过load data均不好使,只能通过insert overwrite
(前面两种方式只是数据导入,并没有走mapreduce,分桶需要通过mapreduce对数据根据字段hash值取模进行分桶,故不能直接简单的导入)

分桶表数据导入方式:
创建普通表,并通过insert overwrite的方式将普通表的数据通过查询的方式加载到桶表当中去
1.创建相同字段结构,表名不同的普通表
create table course_common (c_id string,c_name string,t_id string) row format delimited fields terminated by ‘\t’;

2.普通表中加载数据
load data local inpath ‘/home/hadoop/software/course.csv’ into table course_common;

3.通过查询分桶,再insert overwrite给桶表中加载数据
insert overwrite table course select * from course_common cluster by(c_id);

最终会在 /user/hive/warehouse/myhive.db/course 中根据c_id生成三个(之前reduc设置的个数)文件

修改表
重命名
基本语法:
alter table old_table_name rename to new_table_name;

把表stu4修改成stu5
show tables;
alter table stu4 rename to stu5;
show tables;

增加/修改列信息
查询表结构
desc stu5;
添加列
alter table stu5 add columns (mycol string, mysco string);
查询表结构
desc stu5;
更新列
alter table stu5 change column mycol mysco int;

删除表
drop table stu5;

hive表中加载数据
直接向分区表中插入数据(一般分析数据来源是外部,不会直接插入)
create table score3 like score;
insert into table score3 partition(month =‘201807’) values (‘001’,‘002’,‘100’);

通过查询插入数据
通过load方式加载数据
load data local inpath ‘/home/hadoop/software/course.csv’ overwrite into table score partition(month=‘201806’);
通过查询方式加载数据(insert overwrite会走mapreduce)
create table score4 like score;
insert overwrite table score4 partition(month = ‘201806’) select s_id,c_id,s_score from score;

Hive 查询语法
2.1. SELECT
SELECT [ALL | DISTINCT] select_expr, select_expr, …
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list [HAVING condition]]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY| ORDER BY col_list]
][
LIMIT number]

  1. order by 会对输入做全局排序,因此只有一个reducer(如果存在多个reduce,数据最终输出为多个文件,无法做全局统一排序),会导致当输入规模较大时,需要较长的计算时间(只有一个reduce,无法利用多台机器资源)。
  2. sort by 不是全局排序,其在数据进入reducer前完成排序。因此,如果用sort by进行排序,并且设置
    mapred.reduce.tasks>1,则sort by只保证每个reducer的输出有序,但是不保证全局有序。
  3. distribute by(字段)根据指定的字段将数据分到不同的reducer,且分发算法是hash散列(hash值取模分布到各个reduce,相当于mapreduce的partition功能)。
  4. Cluster by(字段) 除具有Distribute by的功能外,还会对该字段进行排序。 —> distribute by + sort by
    因此,如果分桶和sort字段是同一个时,此时, cluster by = distribute by + sort by
    分桶表的作用:最大的作用是用来提高join操作的效率;
    思考这个问题: select a.id,a.name,b.addr from a join b on a.id = b.id;
    如果a表和b表已经是分桶表,而且分桶的字段是id字段 做这个join操作时,不需要全表做笛卡尔积
    (分桶后的id可以精确匹配,不像join连表查询需要将两表数据交叉合并成一张临时表后,再在临时表中进行条件筛选)

查询语法
全表查询
select * from score;
选择特定列
select s_id ,c_id from score;
列别名
1)重命名一个列。
2)便于计算。
3)紧跟列名,也可以在列名和别名之间加入关键字‘AS’
select s_id as myid ,c_id from score;

常用函数
求总行数(count)
select count(1) from score;
求分数的最大值(max)
select max(s_score) from score;
求分数的最小值(min)
select min(s_score) from score;
求分数的总和(sum)
select sum(s_score) from score;
求分数的平均值(avg)
select avg(s_score) from score;

LIMIT语句
典型的查询会返回多行数据。LIMIT子句用于限制返回的行数。
select * from score limit 3;

WHERE语句

  1. 使用WHERE 子句,将不满足条件的行过滤掉。
  2. WHERE 子句紧随 FROM 子句。

操作符 支持的数据类型 描述
A=B 基本数据类型 如果A等于B则返回TRUE,反之返回FALSE
A<=>B 基本数据类型 如果A和B都为NULL,则返回TRUE,其他的和等号(=)操作符的结果一致,如果任一为NULL则结果为NULL
A<>B,A!=B 基本数据类型 A或者B为NULL则返回NULL;如果A不等于B,则返回TRUE,反之返回FALSE
A<B 基本数据类型 A或者B为NULL,则返回NULL;如果A小于B,则返回TRUE,反之返回FALSE
A<=B 基本数据类型 A或者B为NULL,则返回NULL;如果A小于等于B,则返回TRUE,反之返回FALSE
A>B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于B,则返回TRUE,反之返回FALSE
A>=B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于等于B,则返回TRUE,反之返回FALSE
A [NOT]
BETWEEN B AND C 基本数据类型 如果A,B或者C任一为NULL,则结果为NULL。如果A的值大于等于B而且小于或等于C,则结果为TRUE,反之为FALSE。如果使用NOT关键字则可达到相反的效果。
A IS NULL 所有数据类型 如果A等于NULL,则返回TRUE,反之返回FALSE
A IS NOT NULL 所有数据类型 如果A不等于NULL,则返回TRUE,反之返回FALSE
IN(数值1,数值2) 所有数据类型 使用 IN运算显示列表中的值
A [NOT]
LIKE B STRING 类型 B是一个SQL下的简单正则表达式,如果A与其匹配的话,则返回TRUE;反之返回FALSE。B的表达式说明如下:‘x%’表示A必须以字母‘x’开头,‘%x’表示A必须以字母’x’结尾,而‘%x%’表示A包含有字母’x’,可以位于开头,结尾或者字符串中间。如果使用NOT关键字则可达到相反的效果。
A RLIKE
B, A REGEXP B STRING 类型 B是一个正则表达式,如果A与其匹配,则返回TRUE;反之返回FALSE。匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。

查询出分数大于60的数据
select * from score where s_score > 60;
查询分数等于80的所有的数据
select * from score where s_score = 80;
查询分数在80到100的所有数据
select * from score where s_score between 80 and 100;
查询成绩为空的所有数据
select * from score where s_score is null;
查询成绩是80和90的数据
select * from score where s_score in(80,90);

LIKE 和 RLIKE

  1. 使用LIKE运算选择类似的值

  2. 选择条件可以包含字符或数字:
    % 代表零个或多个字符(任意个字符)。
    _ 代表一个字符。

  3. RLIKE子句是Hive中这个功能的一个扩展,其可以通过Java的正则表达式这个更强大的语言来指定匹配条件。

  4. 查找以8开头的所有成绩
    select * from score where s_score like ‘8%’;

  5. 查找第二个数值为9的所有成绩数据
    select * from score where s_score like ‘_9%’;

  6. 查询课程编号中包含1的数据(类似 %1%)
    select * from score where c_id rlike ‘[1]’;

逻辑运算符
AND 逻辑并
OR 逻辑或
NOT 逻辑否

/home/hadoop/mw/apache-hive-3.1.0-bin/bin/hive
show databases;
use myhive;

查询成绩大于80,并且s_id是01的数据
select * from score where s_score >80 and s_id = ‘01’;
查询成绩大于80,或者s_id 是01的数
select * from score where s_score > 80 or s_id = ‘01’;
查询s_id 不是 01和02的学生
select * from score where s_id not in (‘01’,‘02’);

分组(会走mapreduce)
GROUP BY 语句

计算每个学生的平均分数
select s_id ,avg(s_score) from score group by s_id;

计算每个学生最高成绩
select s_id ,max(s_score) from score group by s_id;

HAVING 语句

  1. having与where不同点
  2. where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据。
  3. where后面不能写分组函数,而having后面可以使用分组函数。
  4. having只用于group by分组统计语句。
  5. 案例实操:
    求每个学生的平均分数
    select s_id ,avg(s_score) from score group by s_id;
    求每个学生平均分数大于85的人
    select s_id ,avg(s_score) avgscore from score group by s_id having avgscore > 85;

JOIN 语句
2.9.1. 等值 JOIN
Hive支持通常的SQL JOIN语句,但是只支持等值连接,不支持非等值连接。

查询分数对应的姓名
SELECT s.s_id,s.s_score,stu.s_name,stu.s_birth FROM score s LEFT JOIN student stu ON s.s_id = stu.s_id;

2.9.2. 表的别名
好处:
使用别名可以简化查询。
使用表名前缀可以提高执行效率。

合并老师与课程表
select * from teacher t join course c on t.t_id = c.t_id;

2.9.3. 内连接
内连接:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
select * from teacher t inner join course c on t.t_id = c.t_id;

2.9.4. 左外连接
左外连接:JOIN操作符左边表中符合WHERE子句的所有记录将会被返回。
查询老师对应的课程:
select * from teacher t left join course c on t.t_id = c.t_id;

2.9.5. 右外连接
右外连接:JOIN操作符右边表中符合WHERE子句的所有记录将会被返回。
select * from teacher t right join course c on t.t_id = c.t_id;

2.9.6. 多表连接
注意:连接 n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
多表连接查询,查询老师对应的课程,以及对应的分数,对应的学生
select * from teacher t
left join course c
on t.t_id = c.t_id
left join score s
on s.c_id = c.c_id
left join student stu
on s.s_id = stu.s_id;
大多数情况下,Hive会对每对JOIN连接对象启动一个MapReduce任务。本例中会首先启动一个MapReduce job对表
techer和表course进行连接操作,然后会再启动一个MapReduce job将第一个MapReduce job的输出和表score;进行连
接操作。

2.9. 排序
2.9.1. 全局排序
Order By:全局排序,一个reduce

  1. 使用 ORDER BY 子句排序
    ASC(ascend): 升序(默认)
    DESC(descend): 降序

  2. ORDER BY 子句在SELECT语句的结尾。

查询学生的成绩,并按照分数降序排序
SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score DESC;
查询学生的成绩,并按照分数升序排序
SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score asc;

2.9.2. 按照别名排序
按照分数的平均值排序
select s_id ,avg(s_score) avg from score group by s_id order by avg;

2.9.3. 多个列排序
按照学生id和平均成绩进行排序
select s_id ,avg(s_score) avg from score group by s_id order by s_id,avg;

2.9.4. 每个MapReduce内部排序(Sort By)局部排序
Sort By:每个MapReduce内部进行排序,对全局结果集来说不是排序。

  1. 设置reduce个数
    set mapreduce.job.reduces=3;
  2. 查看设置reduce个数
    set mapreduce.job.reduces;
  3. 查询成绩按照成绩降序排列
    select * from score sort by s_score;
  4. 将查询结果导入到文件中(按照成绩降序排列)
    insert overwrite local directory ‘/home/hadoop/software/sort’ select * from score sort by s_score;

2.9.5. 分区排序(DISTRIBUTE BY)
Distribute By:类似MR中partition,进行分区,结合sort by使用。
注意,Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。

先按照学生id进行分区,再按照学生成绩进行排序。

  1. 设置reduce的个数,将我们对应的s_id划分到对应的reduce当中去
    set mapreduce.job.reduces=7;
    查看设置reduce个数
    set mapreduce.job.reduces;
  2. 通过distribute by 进行数据的分区
    insert overwrite local directory ‘/home/hadoop/software/sort’ select * from score distribute by s_id sort by s_score;

2.9.6. CLUSTER BY
当distribute by和sort by字段相同时,可以使用cluster by方式。
cluster by除了具有distribute by的功能外还兼具sort by的功能。
但是排序只能是倒序排序,不能指定排序规则为ASC或者DESC。
以下两种写法等价
select * from score cluster by s_id;
select * from score distribute by s_id sort by s_id;

  1. Hive 函数
    3.1. 内置函数
    内容较多,见《Hive官方文档》
    https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF

  2. 查看系统自带的函数
    show functions;

  3. 显示自带的函数的用法
    desc function upper;

  4. 详细显示自带的函数的用法
    desc function extended upper;
    例: SELECT upper(‘Facebook’);

4:常用内置函数
#字符串连接函数: concat
select concat(‘hello’, ’ world’, ’ hive’);

OK
hello world hive
Time taken: 0.226 seconds, Fetched: 1 row(s)

#带分隔符字符串连接函数: concat_ws
select concat_ws(’,’,‘hello’,‘world’,‘hive’);

OK
hello,world,hive
Time taken: 0.193 seconds, Fetched: 1 row(s)

#cast类型转换
select cast(1.5 as int);

OK
1
Time taken: 0.303 seconds, Fetched: 1 row(s)

#get_json_object(json 解析函数,用来处理json,必须是json格式)
select get_json_object(’{“name”:“jack”,“age”:“20”}’,’ . n a m e ′ ) ; s e l e c t g e t j s o n o b j e c t ( ′ " n a m e " : " j a c k " , " a g e " : " 20 " ′ , ′ .name'); select get_json_object('{"name":"jack","age":"20"}',' .name);selectgetjsonobject("name":"jack","age":"20",.age’);

OK
jack
Time taken: 0.255 seconds, Fetched: 1 row(s)

#URL解析函数
select parse_url(‘http://facebook.com/path1/p.php?k1=v1&key2=v2#Ref1’, ‘HOST’);
select parse_url(‘http://facebook.com/path1/p.php?k1=v1&key2=v2#Ref1’, ‘PATH’);
select parse_url(‘http://facebook.com/path1/p.php?k1=v1&key2=v2#Ref1’, ‘QUERY’);
select parse_url(‘http://facebook.com/path1/p.php?k1=v1&key2=v2#Ref1’, ‘QUERY’, ‘k1’);
select parse_url(‘http://facebook.com/path1/p.php?k1=v1&key2=v2#Ref1’, ‘QUERY’, ‘key2’);

OK
facebook.com
Time taken: 0.162 seconds, Fetched: 1 row(s)

#explode:把map集合中每个键值对或数组中的每个元素都单独生成一行的形式

3.2. 自定义函数

  1. Hive 自带的一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方式的扩展。
  2. 当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
  3. 根据用户自定义函数类别分为以下三种:
  4. UDF(User-Defined-Function)
    一进一出
  5. UDAF(User-Defined Aggregation Function)
    聚集函数,多进一出
    类似于: count / max / min
  6. UDTF(User-Defined Table-Generating Functions)
    一进多出
    如 lateral view explore()
  7. 官方文档地址 https://cwiki.apache.org/confluence/display/Hive/HivePlugins
  8. 编程步骤:
    1. 继承org.apache.hadoop.hive.ql.UDF
    2. 需要实现evaluate函数;evaluate函数支持重载;
  9. 注意事项
    1. UDF必须要有返回类型,可以返回null,但是返回类型不能为void;
    2. UDF中常用Text/LongWritable等类型,不推荐使用java类型;

UDF 开发
3.3.1. Step 1 创建 Maven 工程



org.apache.hive
hive-exec
3.1.1



org.apache.hadoop
hadoop-common
3.1.1




myudf


org.apache.maven.plugins
maven-compiler-plugin
3.0

1.8
1.8
UTF-8



继成UDF
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

/**

  • @author gin

  • @date 2020/2/24 19:21
    */
    public class MyUDF extends UDF {

    public Text evaluate(final Text str){
    //将输入字符串的第一个字母大写
    if(str != null && !"".equals(str.toString())){
    String tmpStr = str.toString();
    String retStr = tmpStr.substring(0, 1).toUpperCase() + tmpStr.substring(1);
    return new Text(retStr);
    }
    return new Text("");
    }
    }

打包成jar包,并上传至hive安装目录中的lib目录:
cd /home/hadoop/mw/apache-hive-3.1.0-bin/lib

进入hive的客户端添加我们的jar包
/home/hadoop/mw/apache-hive-3.1.0-bin/bin/hive
add jar /home/hadoop/mw/apache-hive-3.1.0-bin/lib/myudf.jar;

设置函数与我们的自定义函数类名进行关联
create temporary function my_upper as ‘com.gin.udf.MyUDF’;

使用自定义函数
select my_upper(‘hello udf’);

Flume分布式系统中最核心的角色是agent,flume采集系统就是由一个个agent所连接起来形成
每一个agent相当于一个数据传递员,内部有三个组件:

  1. Source:采集组件,用于跟数据源对接,以获取数据
  2. Sink:下沉组件,用于往下一级agent传递数据或者往最终存储系统传递数据
  3. Channel:传输通道组件,用于从source将数据传递到sink

Flume 的安装部署
下载解压修改配置文件:
http://archive.apache.org/dist/flume/1.8.0/apache-flume-1.8.0-bin.tar.gz

Flume的安装非常简单,只需要解压即可,前提是已有hadoop环境
上传安装包到数据源所在节点上:
cd /home/hadoop/software/
tar -zxvf apache-flume-1.8.0-bin.tar.gz -C …/mw/
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
cp flume-env.sh.template flume-env.sh
vim flume-env.sh

搜索 export JAVA_HOME 并打开注释:
export JAVA_HOME=/home/hadoop/mw/jdk1.8.0_141

测试案例1:
开发配置文件
根据数据采集的需求配置采集方案,描述在配置文件中(文件名可任意自定义)
配置我们的网络收集的配置文件
在flume的conf目录下新建一个配置文件(采集方案)

vim /home/hadoop/mw/apache-flume-1.8.0-bin/conf/my-netcat-logger.conf
#定义这个agent中各组件的名字(a1是agent的名字,可自定义; 并分别对sources,sinks,channels都取了名字(别名))
a1.sources = r1
a1.sinks = k1
a1.channels = c1
#描述和配置source组件: r1
#(netcat是表示数据来源于网络套接字,type类型可查看官方文档;bind,port 表示绑定哪台主机(ip:port)来处理数据源,这里绑定集群第一台服务器)
a1.sources.r1.type = netcat
a1.sources.r1.bind = 192.168.25.110
a1.sources.r1.port = 44444
#描述和配置sink组件: k1 (logger表示最终存储在日志系统)
a1.sinks.k1.type = logger
#描述和配置channel组件, 此处使用是内存缓存的方式( memory表示内存暂存,capacity表示一次存储1000单位, transactionCapacity表示一次处理100单位)
a1.channels.c1.type = memory
#队列大小
a1.channels.c1.capacity = 1000
#一次向sinks传输的数据数量
a1.channels.c1.transactionCapacity = 100
#描述和配置source channel sink之间的连接关系(这里表示sources和sinks均使用c1这个channel)
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

启动配置文件
指定采集方案配置文件,在相应的节点上启动flume agent
先用一个最简单的例子来测试一下程序环境是否正常
启动agent去采集数据
cd /home/hadoop/mw/apache-flume-1.8.0-bin/
bin/flume-ng agent -c conf -f conf/my-netcat-logger.conf -n a1 -Dflume.root.logger=INFO,console

-c conf 指定flume自身的配置文件所在目录
-f conf/my-netcat-logger.conf 指定我们所描述的采集方案
-n a1 指定我们这个agent的名字(这也是 my-netcat-logger.conf 中定义的agent的名字)
INFO,console 表示INFO级别,并在控制台输出

安装 Telnet 准备测试
在node02机器上面安装telnet客户端,用于模拟数据的发送
yum -y install telnet
#使用telnet模拟数据发送
telnet node01 44444

显示连接成功:
Trying 192.168.25.110…
Connected to node01.
Escape character is ‘^]’.

尝试输入数据:
hello flume
OK

测试案例2:
某服务器的某特定目录下,会不断产生新的文件,每当有新文件出现,就需要把文件采集到HDFS中去
思路
根据需求,首先定义以下3大要素

  1. 数据源组件,即source ——监控文件目录 : spooldir
  2. 监视一个目录,只要目录中出现新文件,就会采集文件中的内容
  3. 采集完成的文件,会被agent自动添加一个后缀:COMPLETED
  4. 所监视的目录中不允许重复出现相同文件名的文件
  5. 下沉组件,即sink——HDFS文件系统 : hdfs sink
  6. 通道组件,即channel——可用file channel 也可以用内存channel

Step 1: Flume 配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf/
#创建存储文件的目录,以便sources监听
mkdir -p /home/hadoop/mw/dirfile

vim spooldir.conf

#Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1

#Describe/configure the source
##注意:不能往监控目中重复丢同名文件
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /home/hadoop/mw/dirfile
a1.sources.r1.fileHeader = true

#Use a channel which buffers events in memory
a1.channels.c1.type = memory
#默认该通道中最大的可以存储的event数量
a1.channels.c1.capacity = 1000
#每次最大可以从source中拿到或者送到sink中的event数量
a1.channels.c1.transactionCapacity = 100

#Describe the sink
#hdfs表示sinks以hdfs分布式文件系统存储
a1.sinks.k1.type = hdfs
#表示hdfs的存储路径(格式是/年-月-日/时-分 两级目录)
a1.sinks.k1.hdfs.path = hdfs://node01:8020/spooldir/files/%y-%m-%d/%H%M/
#文件前缀
a1.sinks.k1.hdfs.filePrefix = events-
#文件采集滚动 begin
#是否采用文件滚动
a1.sinks.k1.hdfs.round = true
#文件夹生成周期 每10分钟一次 begin
a1.sinks.k1.hdfs.roundValue = 10
a1.sinks.k1.hdfs.roundUnit = minute
#文件夹生成周期 每10分钟一次 end
#(下面三个条件达到一个则生成新文件)每隔3秒产生一个新的文件
a1.sinks.k1.hdfs.rollInterval = 3
#文件大小达到20字节产生一个新文件(临时文件,最终会到hdfs)
a1.sinks.k1.hdfs.rollSize = 20
#文件(hdfs的临时文件)大小达到5个event时,产生一个新文件
a1.sinks.k1.hdfs.rollCount = 5
#文件采集滚动 end
#一次性从channel中拿几个单位数据量,batchSize < transactionCapacity < capacity
a1.sinks.k1.hdfs.batchSize = 1
#是否使用本地时间戳
a1.sinks.k1.hdfs.useLocalTimeStamp = true
#生成的文件类型,默认是Sequencefile,可用DataStream,则为普通文本
a1.sinks.k1.hdfs.fileType = DataStream

#Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

Step 2: 启动 Flume
启动agent去采集数据
cd /home/hadoop/mw/apache-flume-1.8.0-bin/
bin/flume-ng agent -c ./conf -f ./conf/spooldir.conf -n a1 -Dflume.root.logger=INFO,console

Step 3: 上传文件到指定目录
将不同的文件上传到下面目录里面去,注意文件不能重名
cd /home/hadoop/mw/dirfile

添加测试文件,隔3秒输入测试一次

cat > 1.txt <<‘EOF’
1 1
2 2
3 3
EOF

cat > 4.txt <<‘EOF’
4 4
5 5
6 6
EOF

cat > 7.txt <<‘EOF’
7 7
8 8
9 9
EOF

需求
比如业务系统使用log4j生成的日志,日志内容不断增加,需要把追加到日志文件中的数据实时采集到hdfs

分析
根据需求,首先定义以下3大要素
采集源,即source——监控文件内容更新 : exec ‘tail -F file’

下沉目标,即sink——HDFS文件系统 : hdfs sink
Source和sink之间的传递通道——channel,可用file channel 也可以用 内存channel

Step 1: 定义 Flume 配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf/
vim tail-file.conf

agent1.sources = source1
agent1.sinks = sink1
agent1.channels = channel1
#Describe/configure tail -F source1
#type = exec 可以监控linux一个命令的执行结果
agent1.sources.source1.type = exec
agent1.sources.source1.command = tail -F /home/hadoop/mw/taillogs/access_log
#最后配置关系: agent1.sources.source1.channels = channel1
#Describe sink1
agent1.sinks.sink1.type = hdfs
#a1.sinks.k1.channel = c1
agent1.sinks.sink1.hdfs.path = hdfs://node01:8020/weblog/flume-collection/%y-%m-%d/%H-%M
#文件前缀
agent1.sinks.sink1.hdfs.filePrefix = access_log
#最大可打开文件
agent1.sinks.sink1.hdfs.maxOpenFiles = 5000
#最多可存储event个数
agent1.sinks.sink1.hdfs.batchSize= 100
#文件格式DataStream(普通文件类型)
agent1.sinks.sink1.hdfs.fileType = DataStream
#文件类型 : Text 文本类型
agent1.sinks.sink1.hdfs.writeFormat =Text
#滚动文件 rollSize达到多大进行切割, rollCount达到多少行进行切割
agent1.sinks.sink1.hdfs.rollSize = 102400
agent1.sinks.sink1.hdfs.rollCount = 1000000
#十分钟创建一个新的文件夹
agent1.sinks.sink1.hdfs.round = true
agent1.sinks.sink1.hdfs.roundValue = 10
agent1.sinks.sink1.hdfs.roundUnit = minute
agent1.sinks.sink1.hdfs.useLocalTimeStamp = true
#Use a channel which buffers events in memory
agent1.channels.channel1.type = memory
agent1.channels.channel1.keep-alive = 120
agent1.channels.channel1.capacity = 500000
agent1.channels.channel1.transactionCapacity = 600
#Bind the source and sink to the channel
agent1.sources.source1.channels = channel1
agent1.sinks.sink1.channel = channel1

创建测试文件:
mkdir -p /home/hadoop/mw/taillogs/
mkdir -p /home/hadoop/mw/shells/
cd /home/hadoop/mw/shells/
vim tail-file.sh

#!/bin/bash
while true
do
date >> /home/hadoop/mw/taillogs/access_log;
sleep 0.5;
done

启动agent去采集数据
cd /home/hadoop/mw/apache-flume-1.8.0-bin/
bin/flume-ng agent -c ./conf -f ./conf/tail-file.conf -n agent1 -Dflume.root.logger=INFO,console

启动脚本
sh /home/hadoop/mw/shells/tail-file.sh

Agent级联
第一个agent负责收集文件当中的数据,通过网络发送到第二个agent当中去
第二个agent负责接收第一个agent发送的数据,并将数据保存到hdfs上面去
Step 1: Node02 安装 Flume
将node01机器上面解压后的flume文件夹拷贝到node02机器上面去
cd /home/hadoop/mw/
scp -r apache-flume-1.8.0-bin/ node02:$PWD
Step 2: Node02 配置 Flume
在node02机器配置我们的flume
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim tail-avro-avro-logger.conf

##################
#Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
#Describe/configure the source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /home/hadoop/mw/taillogs/access_log
a1.sources.r1.channels = c1
#Describe the sink
##sink端的avro是一个数据发送者( avro 表示该组件为级联组件)
a1.sinks = k1
a1.sinks.k1.type = avro
a1.sinks.k1.channel = c1
#级联下沉数据到哪台服务器ip:port 接收方需要对应该配置(这里需要发送到node01)
a1.sinks.k1.hostname = 192.168.25.110
a1.sinks.k1.port = 4141
a1.sinks.k1.batch-size = 10
#Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
#Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

Step 3: 开发脚本向文件中写入数据
直接将node01下面的脚本和数据拷贝到node02即可,node03机器上执行以下命令
cd /home/hadoop/mw
scp -r shells/ taillogs/ node02:$PWD

Step 4: Node01 Flume 配置文件
在node01机器上开发flume的配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim avro-hdfs.conf

#Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
#Describe/configure the source
##source中的avro组件是一个接收者服务(node01是接收方,接收方开启本机端口接收数据)
a1.sources.r1.type = avro
a1.sources.r1.channels = c1
a1.sources.r1.bind = 192.168.25.110
a1.sources.r1.port = 4141
#Describe the sink
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://node01:8020/av/%y-%m-%d/%H%M/
a1.sinks.k1.hdfs.filePrefix = eventsa1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 10
a1.sinks.k1.hdfs.roundUnit = minute
a1.sinks.k1.hdfs.rollInterval = 3
a1.sinks.k1.hdfs.rollSize = 20
a1.sinks.k1.hdfs.rollCount = 5
a1.sinks.k1.hdfs.batchSize = 1
a1.sinks.k1.hdfs.useLocalTimeStamp = true
#生成的文件类型,默认是Sequencefile,可用DataStream,则为普通文本
a1.sinks.k1.hdfs.fileType = DataStream
#Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
#Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

Step 5: 顺序启动
node01机器启动flume进程
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -c conf -f conf/avro-hdfs.conf -n a1 -Dflume.root.logger=INFO,console

node02机器启动flume进程
cd /home/hadoop/mw/apache-flume-1.8.0-bin/
bin/flume-ng agent -c conf -f conf/tail-avro-avro-logger.conf -n a1 -Dflume.root.logger=INFO,console

node02机器启shell脚本生成文件
cd /home/hadoop/mw/shells
sh tail-file.sh

高可用方案
在完成单点的Flume NG搭建后,下面我们搭建一个高可用的Flume NG集群,架构图如下所示:

Flume的Agent和Collector分布如下表所示:
名称 HOST 角色
Agent1 node01 Web Server
Collector1 node02 AgentMstr1
Collector2 node03 AgentMstr2

Agent1数据分别流入到Collector1和Collector2,Flume NG本身提供了Failover机制,
可以自动切换和恢复(实现了故障转移)

Node03 安装和配置
将node01机器上面的flume安装包以及文件生产的两个目录拷贝到node01机器上面去
node01机器执行以下命令
cd /home/hadoop/mw
scp -r apache-flume-1.8.0-bin/ node03: P W D s c p − r s h e l l s / t a i l l o g s / n o d e 03 : PWD scp -r shells/ taillogs/ node03: PWDscprshells/taillogs/node03:PWD

node01机器配置agent的配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim agent.conf

#agent1 name
agent1.channels = c1
agent1.sources = r1
#这里配置了两个 sinks,两个sinks多活
agent1.sinks = k1 k2

###set gruop
agent1.sinkgroups = g1

agent1.sources.r1.channels = c1
agent1.sources.r1.type = exec
agent1.sources.r1.command = tail -F /home/hadoop/mw/taillogs/access_log

###set channel
agent1.channels.c1.type = memory
agent1.channels.c1.capacity = 1000
agent1.channels.c1.transactionCapacity = 100

###set sink1
agent1.sinks.k1.channel = c1
agent1.sinks.k1.type = avro
agent1.sinks.k1.hostname = node02
agent1.sinks.k1.port = 52020

###set sink2
agent1.sinks.k2.channel = c1
agent1.sinks.k2.type = avro
agent1.sinks.k2.hostname = node03
agent1.sinks.k2.port = 52020

###set sink group
agent1.sinkgroups.g1.sinks = k1 k2

###set failover type(failover表示故障转移,只发送给权重高的一台,权重高的挂掉再发送给权重低的一台)
agent1.sinkgroups.g1.processor.type = failover
agent1.sinkgroups.g1.processor.priority.k1 = 10
agent1.sinkgroups.g1.processor.priority.k2 = 1
#最大惩罚时间,当机器宕机后,多长时间能不能恢复接收数据
agent1.sinkgroups.g1.processor.maxpenalty = 10000

Node02 与 Node03 配置 FlumeCollection
node02机器修改配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim collector.conf

#set Agent name
a1.sources = r1
a1.channels = c1
a1.sinks = k1

###set channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

###other node,nna to nns
a1.sources.r1.type = avro
a1.sources.r1.bind = node02
a1.sources.r1.port = 52020
a1.sources.r1.channels = c1

###set sink to hdfs
a1.sinks.k1.type=hdfs
a1.sinks.k1.hdfs.path= hdfs://node01:8020/flume/failover/
a1.sinks.k1.hdfs.fileType=DataStream
#是否使用本地时间戳
a1.sinks.k1.hdfs.useLocalTimeStamp = true
a1.sinks.k1.hdfs.writeFormat=TEXT
a1.sinks.k1.hdfs.rollInterval=10
a1.sinks.k1.channel=c1
a1.sinks.k1.hdfs.filePrefix=%Y-%m-%d

node03机器修改配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim collector.conf

#set Agent name
a1.sources = r1
a1.channels = c1
a1.sinks = k1

###set channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

###other node,nna to nns
a1.sources.r1.type = avro
a1.sources.r1.bind = node03
a1.sources.r1.port = 52020
a1.sources.r1.channels = c1

###set sink to hdfs
a1.sinks.k1.type=hdfs
a1.sinks.k1.hdfs.path= hdfs://node01:8020/flume/failover/
a1.sinks.k1.hdfs.fileType=DataStream
#是否使用本地时间戳
a1.sinks.k1.hdfs.useLocalTimeStamp = true
a1.sinks.k1.hdfs.writeFormat=TEXT
a1.sinks.k1.hdfs.rollInterval=10
a1.sinks.k1.channel=c1
a1.sinks.k1.hdfs.filePrefix=%Y-%m-%d

顺序启动(时间同步 /usr/sbin/ntpdate ntp4.aliyun.com;)
node03机器上面启动flume
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -n a1 -c conf -f conf/collector.conf -Dflume.root.logger=DEBUG,console

node02机器上面启动flume
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -n a1 -c conf -f conf/collector.conf -Dflume.root.logger=DEBUG,console

node01机器上面启动flume
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -n agent1 -c conf -f conf/agent.conf -Dflume.root.logger=DEBUG,console

node01机器启动文件产生脚本
cd /home/hadoop/mw/shells
sh tail-file.sh

下面我们来测试下Flume NG集群的高可用(故障转移)。
场景如下:我们在Agent1节点上传文件,由于我们配置Collector1的权重比Collector2大,
所以 Collector1优先采集并上传到存储系统。然后我们kill掉Collector1,
此时有Collector2负责日志的采集上传工作,之后,我们手动恢复Collector1节点的Flume服务,
再次在Agent1上次文件,发现Collector1恢复优先级别的采集工作。

Flume 的负载均衡
负载均衡是用于解决一台机器(一个进程)无法解决所有请求而产生的一种算法。Load balancing Sink
Processor 能够实现 load balance 功能,Agent1 是一个路由节点,负责将 Channel 暂存的
Event 均衡到对应的多个 Sink组件上,而每个 Sink 组件分别连接到一个独立的 Agent 上

三台机器(模拟flume的负载均衡)规划如下:
node01:采集数据,发送到node02和node03机器上去
node02:接收node01的部分数据
node03:接收node01的部分数据

第一步:开发node01服务器的flume配置
node01服务器配置:
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim load_banlancer_client.conf

#agent name
a1.channels = c1
a1.sources = r1
a1.sinks = k1 k2

#set gruop
a1.sinkgroups = g1

#set channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
a1.sources.r1.channels = c1
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /home/hadoop/mw/taillogs/access_log

#set sink1
a1.sinks.k1.channel = c1
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = node02
a1.sinks.k1.port = 52020

#set sink2
a1.sinks.k2.channel = c1
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = node03
a1.sinks.k2.port = 52020
#set sink group
a1.sinkgroups.g1.sinks = k1 k2

#set load_balance
#load_balance 表示负载均衡; failover 表示失败转移
a1.sinkgroups.g1.processor.type = load_balance
a1.sinkgroups.g1.processor.backoff = true
#round_robin表示轮询策略
a1.sinkgroups.g1.processor.selector = round_robin
#超时时间
a1.sinkgroups.g1.processor.selector.maxTimeOut=10000

第二步:开发node02服务器的flume配置
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim load_banlancer_server.conf

#Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1

#Describe/configure the source
a1.sources.r1.type = avro
a1.sources.r1.channels = c1
a1.sources.r1.bind = node02
a1.sources.r1.port = 52020

#Describe the sink
a1.sinks.k1.type = logger

#Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

#Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

第三步:开发node03服务器flume配置
node03服务器配置
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf
vim load_banlancer_server.conf

#Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1

#Describe/configure the source
a1.sources.r1.type = avro
a1.sources.r1.channels = c1
a1.sources.r1.bind = node03
a1.sources.r1.port = 52020

#Describe the sink
a1.sinks.k1.type = logger

#Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

#Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

第四步:准备启动flume服务
启动node03的flume服务
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -n a1 -c conf -f conf/load_banlancer_server.conf -Dflume.root.logger=DEBUG,console

启动node02的flume服务
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -n a1 -c conf -f conf/load_banlancer_server.conf -Dflume.root.logger=DEBUG,console

启动node01的flume服务
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -n a1 -c conf -f conf/load_banlancer_client.conf -Dflume.root.logger=DEBUG,console

第五步:node01服务器运行脚本产生数据
cd /home/hadoop/mw/shells
sh tail-file.sh

  1. Flume 案例一
  2. 案例场景
    A、B两台日志服务机器实时生产日志主要类型为access.log、nginx.log、web.log
    现在要求:
    把A、B 机器中的access.log、nginx.log、web.log 采集汇总到C机器上然后统一收集到hdfs中。
    但是在hdfs中要求的目录为:
    /source/logs/access/20180101/**
    /source/logs/nginx/20180101/**
    /source/logs/web/20180101/**

采集端配置文件开发
node01与node02服务器开发flume的配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf/
vim exec_source_avro_sink.conf

#Name the components on this agent
#表示存在三个sources源,因为需要读取三个文件的变化
a1.sources = r1 r2 r3
a1.sinks = k1
a1.channels = c1
#Describe/configure the source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /home/hadoop/mw/taillogs/access.log
#配置拦截器,给数据加上tag,这样到了数据接收端才能根据tag不同存储到对应的文件目录
#拦截器名
a1.sources.r1.interceptors = i1
#表示拦截器为静态拦截器
a1.sources.r1.interceptors.i1.type = static
##static拦截器的功能就是往采集到的数据的header中插入自己定义的key-value对
##key=type 表示标记的键的名字为 type, 下游获取数据就能通过类似 get(“type”) 方式获取对应的value值;
##key值可以自定义
a1.sources.r1.interceptors.i1.key = type
##value就是获取对应key时会得到的结果,value值不同,放置到不同的文件夹
a1.sources.r1.interceptors.i1.value = access
a1.sources.r2.type = exec
a1.sources.r2.command = tail -F /home/hadoop/mw/taillogs/nginx.log
a1.sources.r2.interceptors = i2
a1.sources.r2.interceptors.i2.type = static
a1.sources.r2.interceptors.i2.key = type
a1.sources.r2.interceptors.i2.value = nginx
a1.sources.r3.type = exec
a1.sources.r3.command = tail -F /home/hadoop/mw/taillogs/web.log
a1.sources.r3.interceptors = i3
a1.sources.r3.interceptors.i3.type = static
a1.sources.r3.interceptors.i3.key = type
a1.sources.r3.interceptors.i3.value = web

#Describe the sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = node03
a1.sinks.k1.port = 41414
#Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 20000
a1.channels.c1.transactionCapacity = 10000

#Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sources.r2.channels = c1
a1.sources.r3.channels = c1
a1.sinks.k1.channel = c1

服务端配置文件开发
在node03上面开发flume配置文件
cd /home/hadoop/mw/apache-flume-1.8.0-bin/conf/
vim avro_source_hdfs_sink.conf

a1.sources = r1
a1.sinks = k1
a1.channels = c1
#定义source
a1.sources.r1.type = avro
a1.sources.r1.bind = node03
a1.sources.r1.port =41414
#添加时间拦截器
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = org.apache.flume.interceptor.TimestampInterceptor$Builder

#定义channels
a1.channels.c1.type = memory
a1.channels.c1.capacity = 20000
a1.channels.c1.transactionCapacity = 10000

#定义sink
a1.sinks.k1.type = hdfs
#获取拦截器中的值,%{type} 里面自定义的 type 要跟之前拦截器 key 的名字保持一致
a1.sinks.k1.hdfs.path=hdfs://node01:8020/source/logs/%{type}/%Y%m%d
a1.sinks.k1.hdfs.filePrefix =events
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.writeFormat = Text

#时间类型
a1.sinks.k1.hdfs.useLocalTimeStamp = true
#生成的文件不按条数生成
a1.sinks.k1.hdfs.rollCount = 0
#生成的文件按时间生成
a1.sinks.k1.hdfs.rollInterval = 30
#生成的文件按大小生成
a1.sinks.k1.hdfs.rollSize = 10485760
#批量写入hdfs的个数
a1.sinks.k1.hdfs.batchSize = 10000
#flume操作hdfs的线程数(包括新建,写入等)
a1.sinks.k1.hdfs.threadsPoolSize=10
#操作hdfs超时时间
a1.sinks.k1.hdfs.callTimeout=30000
#组装source、channel、sink
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

采集端文件生成脚本
在node01与node02上面开发shell脚本,模拟数据生成
cd /home/hadoop/mw/shells
vim server.sh

#!/bin/bash

while true
do
date >> /home/hadoop/mw/taillogs/access.log;
date >> /home/hadoop/mw/taillogs/web.log;
date >> /home/hadoop/mw/taillogs/nginx.log;
sleep 0.5;
done

顺序启动服务
node03启动flume实现数据收集
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -c conf -f conf/avro_source_hdfs_sink.conf -name a1 -Dflume.root.logger=DEBUG,console

node01与node02启动flume实现数据监控
cd /home/hadoop/mw/apache-flume-1.8.0-bin
bin/flume-ng agent -c conf -f conf/exec_source_avro_sink.conf -name a1 -Dflume.root.logger=DEBUG,console

node01与node02启动生成文件脚本
cd /home/hadoop/mw/shells
sh server.sh

为什么需要Azkaban
一个完整的数据分析系统通常都是由大量任务单元组成
shell脚本程序
java程序
mapreduce程序
hive脚本等

各任务单元之间存在时间先后及前后依赖关系, 为了很好地组织起这样的复杂执行计划,
需要一个工作流调度系统来调度执行;
例如,我们可能有这样一个需求,某个业务系统每天产生20G原始数据,我们每天都要对其进行处理,
处理步骤如下所示:

  1. 通过Hadoop先将原始数据同步到HDFS上;
  2. 借助MapReduce计算框架对原始数据进行转换,生成的数据以分区表的形式存储到多张Hive表中;
  3. 需要对Hive中多个表的数据进行JOIN处理,得到一个明细数据Hive大表;
  4. 将明细数据进行各种统计分析,得到结果报表信息;
  5. 需要将统计分析得到的结果数据同步到业务系统中,供业务调用使用。

安装
2.1. 编译
我们这里选用azkaban3.51.0这个版本自己进行重新编译,编译完成之后得到我们需要的安装包进行安装
注意:我们这里编译需要使用jdk1.8的版本来进行编译,如果编译服务器使用的jdk版本是1.7的,
记得切换成jdk1.8,我们这里使用的是jdk8u141这个版本来进行编译

(注意在安装了需要使用数据库的机器上安装,方便测试,目前是node01)
cd /home/hadoop/software/

wget https://github.com/azkaban/azkaban/archive/3.51.0.tar.gz

上传已经下载好的 zxvf 3.51.0.tar.gz 包

tar -zxvf 3.51.0.tar.gz -C …/mw/

yum -y install git
yum -y install gcc-c++

#最好能使用下载编译好的,编译需要下载仓库等时间较长
cd /home/hadoop/mw/azkaban-3.51.0/
./gradlew build installDist -x test

编译完成后得到如下文件

Azkaban组件

  1. azkaban-exec-server(负责任务的执行)
  2. azkaban-web-server(负责任务的页面显示和其他调度)
  3. DB

单服务模式: Sole Server
一个进程中包含了:
Exec server
Web Server
H2 (Azkaban自带的数据库)

Two Server模式
进程一
Exec Server
进程二
Web Server

数据库(存储两个进程间需要交互的数据) 可以采用mysql等

集群模式:
进程一
Exec Server
进程二
Web Server
进程三
Web Server

数据库

azkaban-exec-server
编译完成之后得到我们需要的安装包在以下目录下即可获取得到
azkaban-exec-server存放目录
/home/hadoop/mw/azkaban-3.51.0/azkaban-exec-server/build/distributions

azkaban-web-server
azkaban-web-server存放目录
/home/hadoop/mw/azkaban-3.51.0/azkaban-web-server/build/distributions

azkaban-solo-server
azkaban-solo-server存放目录
/home/hadoop/mw/azkaban-3.51.0/azkaban-solo-server/build/distributions

execute-as-user.c
azkaban two server模式下需要的C程序在这个路径下面
/home/hadoop/mw/azkaban-3.51.0/az-exec-util/src/main/c

数据库脚本文件
数据库脚本文件在这个路径下面
/home/hadoop/mw/azkaban-3.51.0/azkaban-db/build/install/azkaban-db

Azkaban 单服务模式安装与使用

所需软件 : azkaban-solo-server
Step 1: 解压
azkaban 的solo server使用的是一个单节点的模式来进行启动服务的,
只需要一个azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz的安装包即可启动,
所有的数据信息都是保存在H2这个azkaban默认的数据当中,
找编译后的目录:
cd /home/hadoop/mw/azkaban-3.51.0/azkaban-solo-server/build/distributions
cp azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz /home/hadoop/software

上传我们的压缩包
然后修改配置文件启动即可

cd /home/hadoop/software
tar -zxvf azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz -C …/mw/

Step 2: 修改时区配置文件
cd /home/hadoop/mw/azkaban-solo-server-0.1.0-SNAPSHOT/conf
vim azkaban.properties

找到 default.timezone.id 这行配置文件:
default.timezone.id=Asia/Shanghai

修改commonprivate.properties配置文件
cd /home/hadoop/mw/azkaban-solo-server-0.1.0-SNAPSHOT/plugins/jobtypes
vim commonprivate.properties

#需要新增下面两行配置,以关闭内存检查(azkaban 对内存要求较高,测试环境需要取消内存检查)
execute.as.user=false
memCheck.enabled=false

Step 3: 启动solo-server
启动azkaban-solo-server
cd /home/hadoop/mw/azkaban-solo-server-0.1.0-SNAPSHOT
bin/start-solo.sh

Step 4: 启动验证

通过 jps 命令查看是否启动
40846 AzkabanSingleServer

浏览器页面访问
http://node03:8081/
用户名: azkaban
密码: azkaban

单服务模式使用
需求:使用azkaban调度我们的shell脚本,执行linux的shell命令

可以在Windows系统(能打开azkaban主页面的系统)创建普通文本文件 foo.job,文件内容如下

#command表示任务类型为执行命令
type=command
#需要执行的命令为 echo
command=echo “hello world”

然后将这个文件打包为压缩文件,如下:
foo.zip

上传我们的压缩包到 azkaban

  1. 通过 http://node03:8081/ 登录
  2. 点击Projects菜单栏中的 Create Project; name和Description自定义,如 helloProject
  3. 在创建好的 helloProject 中点击上传(upload)
  4. 选择刚刚压缩好的 foo.zip 上传成功后,在 helloProject 中的Flows显示新增的 foo
  5. 在 foo 列,点击 Execute Flow

Azkaban 两个服务器模式安装与使用

需要的工具
Azkaban Web服务安装包 azkaban-web-server-0.1.0-SNAPSHOT.tar.gz
Azkaban执行服务安装包 azkaban-exec-server-0.1.0-SNAPSHOT.tar.gz
编译之后的sql脚本 create-all-sql-0.1.0-SNAPSHOT.sql
C程序文件脚本 execute-as-user.c

对应路径
/home/hadoop/mw/azkaban-3.51.0/azkaban-exec-server/build/distributions
/home/hadoop/mw/azkaban-3.51.0/azkaban-web-server/build/distributions
/home/hadoop/mw/azkaban-3.51.0/azkaban-db/build/install/azkaban-db
/home/hadoop/mw/azkaban-3.51.0/az-exec-util/src/main/c

cp /home/hadoop/mw/azkaban-3.51.0/azkaban-exec-server/build/distributions/azkaban-exec-server-0.1.0-SNAPSHOT.tar.gz /home/hadoop/software/
cp /home/hadoop/mw/azkaban-3.51.0/azkaban-web-server/build/distributions/azkaban-web-server-0.1.0-SNAPSHOT.tar.gz /home/hadoop/software/
cp /home/hadoop/mw/azkaban-3.51.0/azkaban-db/build/install/azkaban-db/create-all-sql-0.1.0-SNAPSHOT.sql /home/hadoop/software/
cp /home/hadoop/mw/azkaban-3.51.0/az-exec-util/src/main/c/execute-as-user.c /home/hadoop/software/

Step 1: 数据库准备
进入mysql的客户端执行以下命令

mysql -uroot -p

执行以下命令:
CREATE DATABASE azkaban;
CREATE USER ‘azkaban’@’%’ IDENTIFIED BY ‘azkaban’;
GRANT all privileges ON azkaban.* to ‘azkaban’@’%’ identified by ‘azkaban’ WITH GRANT OPTION;
flush privileges;
use azkaban;
source /home/hadoop/software/create-all-sql-0.1.0-SNAPSHOT.sql;

Step 2: 解压软件包
解压软件安装包

解压azkaban-web-server

cd /home/hadoop/software
tar -zxvf azkaban-web-server-0.1.0-SNAPSHOT.tar.gz -C …/mw/
cd /home/hadoop/mw
mv azkaban-web-server-0.1.0-SNAPSHOT/ azkaban-web-server-3.51.0

解压azkaban-exec-server
cd /home/hadoop/software
tar -zxvf azkaban-exec-server-0.1.0-SNAPSHOT.tar.gz -C …/mw/
cd /home/hadoop/mw
mv azkaban-exec-server-0.1.0-SNAPSHOT/ azkaban-exec-server-3.51.0

Step 3: 安装SSL安全认证
安装ssl安全认证,允许我们使用https的方式访问我们的azkaban的web服务
#切换到web的主目录,使用keytool生成ssl秘钥
cd /home/hadoop/mw/azkaban-web-server-3.51.0
keytool -keystore keystore -alias jetty -genkey -keyalg RSA

注意,输入密码为: azkaban
密码一定要一个个的字母输入,或者粘贴也行

What is your first and last name?
What is the name of your organizational unit?
What is the name of your organization?
What is the name of your City or Locality?
What is the name of your State or Province?
What is the two-letter country code for this unit?
以上信息直接回车即可

Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]:
这里需要输入: yes

Enter key password for
(RETURN if same as keystore password):
这里的密码还是输入: azkaban

最后查看keystore是否生成成功
ll

Step 4: azkaban web server安装
修改azkaban-web-server的配置文件

cd /home/hadoop/mw/azkaban-web-server-3.51.0/conf
vim azkaban.properties

#Azkaban Personalization Settings
#azkaban的名字,可以自定义
azkaban.name=Azkaban
#azkaban的标签,可以自定义
azkaban.label=My Azkaban
azkaban.color=#FF3601
azkaban.default.servlet.path=/index
web.resource.dir=web/
#时区需要修改
default.timezone.id=Asia/Shanghai
#Azkaban UserManager class
user.manager.class=azkaban.user.XmlUserManager
user.manager.xml.file=conf/azkaban-users.xml
#Loader for projects
executor.global.properties=conf/global.properties
azkaban.project.dir=projects
#Velocity dev mode
velocity.dev.mode=false
#Azkaban Jetty server properties.
#设置可以通过https进行访问
jetty.use.ssl=true
jetty.maxThreads=25
jetty.port=8081
#ssl=true 需要新增下列ssl的配置信息,端口,秘钥路径,密码
jetty.ssl.port=8443
jetty.keystore=/home/hadoop/mw/azkaban-web-server-3.51.0/keystore
jetty.password=azkaban
jetty.keypassword=azkaban
jetty.truststore=/home/hadoop/mw/azkaban-web-server-3.51.0/keystore
jetty.trustpassword=azkaban
#新增ssl配置信息结束
#Azkaban Executor settings
#mail settings
mail.sender=
mail.host=
#User facing web server configurations used to construct the user facing server URLs. They are useful when there is a reverse proxy between
Azkaban web servers and users.
#enduser -> myazkabanhost:443 -> proxy -> localhost:8081
#when this parameters set then these parameters are used to generate email links.
#if these parameters are not set then jetty.hostname, and jetty.port(ifssl configured jetty.ssl.port) are used.
#azkaban.webserver.external_hostname=myazkabanhost.com
#azkaban.webserver.external_ssl_port=443
#azkaban.webserver.external_port=8081
job.failure.email=
job.success.email=
lockdown.create.projects=false
cache.directory=cache
#JMX stats
jetty.connector.stats=true
executor.connector.stats=true
#Azkaban mysql settings by default. Users should configure their own username and password.
database.type=mysql
mysql.port=3306
#数据库改成对应主机的主机名
mysql.host=node01
mysql.database=azkaban
mysql.user=azkaban
mysql.password=azkaban
mysql.numconnections=100
#Multiple Executor
azkaban.use.multiple.executors=true
#测试环境需要注释 azkaban.executorselector.filters 不然内存等配置过低启动会失败
#azkaban.executorselector.filters=StaticRemainingFlowSize,MinimumFreeMemory,CpuStatus
azkaban.executorselector.comparator.NumberOfAssignedFlowComparator=1
azkaban.executorselector.comparator.Memory=1
azkaban.executorselector.comparator.LastDispatched=1
azkaban.executorselector.comparator.CpuUsage=1

#需要新增的刷新频率及线程配置 begin
azkaban.activeexecutor.refresh.milisecinterval=10000
azkaban.queueprocessing.enabled=true
azkaban.activeexecutor.refresh.flowinterval=10
azkaban.executorinfo.refresh.maxThreads=10
#需要新增的刷新频率及线程配置 end

Step 5: azkaban executor server 安装
第一步:修改azkaban-exex-server配置文件

cd /home/hadoop/mw/azkaban-exec-server-3.51.0/conf
vim azkaban.properties

#Azkaban Personalization Settings
#name label可以和web保持一致,也可自定义
azkaban.name=Azkaban
azkaban.label=My Azkaban
azkaban.color=#FF3601
azkaban.default.servlet.path=/index
web.resource.dir=web/
#修改时区
default.timezone.id=Asia/Shanghai
#Azkaban UserManager class
user.manager.class=azkaban.user.XmlUserManager
user.manager.xml.file=conf/azkaban-users.xml
#Loader for projects
executor.global.properties=conf/global.properties
azkaban.project.dir=projects
#Velocity dev mode
velocity.dev.mode=false
#Azkaban Jetty server properties.
#设置开启https
jetty.use.ssl=true
jetty.maxThreads=25
jetty.port=8081

#对应 ssl=true 需新增配置 begin
jetty.keystore=/home/hadoop/mw/azkaban-web-server-3.51.0/keystore
jetty.password=azkaban
jetty.keypassword=azkaban
jetty.truststore=/home/hadoop/mw/azkaban-web-server-3.51.0/keystore
jetty.trustpassword=azkaban
#对应 ssl=true 需新增配置 end

#Where the Azkaban web server is located
#使用two server所在的主机名
azkaban.webserver.url=https://node01:8443
#mail settings
mail.sender=
mail.host=
#User facing web server configurations used to construct the user facing server URLs. They are useful when there is a reverse proxy between
Azkaban web servers and users.
#enduser -> myazkabanhost:443 -> proxy -> localhost:8081
#when this parameters set then these parameters are used to generateemail links.
#if these parameters are not set then jetty.hostname, and jetty.port(ifssl configured jetty.ssl.port) are used.
#azkaban.webserver.external_hostname=myazkabanhost.com
#azkaban.webserver.external_ssl_port=443# azkaban.webserver.external_port=8081
job.failure.email=
job.success.email=
lockdown.create.projects=false
cache.directory=cache
#JMX stats
jetty.connector.stats=true
executor.connector.stats=true
#Azkaban plugin settings
azkaban.jobtype.plugin.dir=plugins/jobtypes
#Azkaban mysql settings by default. Users should configure their ownusername and password.
database.type=mysql
mysql.port=3306
#同步选择对应数据库主机的主机名
mysql.host=node01
mysql.database=azkaban
mysql.user=azkaban
mysql.password=azkaban
mysql.numconnections=100
#Azkaban Executor settings
executor.maxThreads=50
executor.flow.threads=30

Step 6: azkaban executor server 安装
添加插件:
将我们编译后的C文件execute-as-user.c拷贝到/home/hadoop/mw/azkaban-exec-server-3.51.0/plugins/jobtypes/
cd /home/hadoop/mw/azkaban-exec-server-3.51.0/plugins/jobtypes/
cp /home/hadoop/software/execute-as-user.c /home/hadoop/mw/azkaban-exec-server-3.51.0/plugins/jobtypes/

然后执行以下命令生成execute-as-user
yum -y install gcc-c++
cd /home/hadoop/mw/azkaban-exec-server-3.51.0/plugins/jobtypes
gcc execute-as-user.c -o execute-as-user
chown root execute-as-user
chmod 6050 execute-as-user

Step 7: azkaban executor server 安装
修改配置文件
cd /home/hadoop/mw/azkaban-exec-server-3.51.0/plugins/jobtypes
vim commonprivate.properties

execute.as.user=false
#需要添加的配置信息,跳过内存检查,及配置信息对应的目录
memCheck.enabled=false
azkaban.native.lib=/home/hadoop/mw/azkaban-exec-server-3.51.0/plugins/jobtypes

Step 7: 启动服务
第一步:启动azkaban exec server

cd /home/hadoop/mw/azkaban-exec-server-3.51.0
bin/start-exec.sh

通过jps命令查看,显示为:
AzkabanExecutorServer

第二步:激活我们的exec-server
node01机器任意目录下执行以下命令(注意 😒 前面为机器的hostname)

curl -G “node01:$(<./executor.port)/executor?action=activate” && echo

显示为 {“status”:“success”} 则表示激活成功

第三步:启动azkaban-web-server
cd /home/hadoop/mw/azkaban-web-server-3.51.0/
bin/start-web.sh

通过jps命令查看,显示为:
AzkabanWebServer

访问地址:
https://node01:8443

Step 8: 修改linux的时区问题
由于先前做好了时钟同步,所以不用担心时区问题,不需要修改时区了( /usr/sbin/ntpdate ntp4.aliyun.com; )
注:先配置好服务器节点上的时区

  1. 先生成时区配置文件Asia/Shanghai,用交互式命令 tzselect 即可
  2. 拷贝该时区文件,覆盖系统本地时区配置
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

实战
Azkaba内置的任务类型支持command、java

3.1. Command 类型单一 Job 示例
Step 1: 创建 Job 描述文件
创建文本文件,更改名称为mycommand.job
注意后缀.txt一定不要带上,保存为格式为UFT-8(单纯的UTF-8 不带 bom 的格式)
内容如下:

type=command
command=echo ‘hello world’

Step 2: 将job资源文件打包成zip文件

Step 3: 创建project并上传压缩包
通过azkaban的web管理平台创建project并上传job压缩包

首先创建project, name desc自己定义就好
在对应project中,点击upload上传zip包
点击execute执行job

3.2. Command 类型多 Job 示例

Step 1: 创建有依赖关系的多个job描述
第一个job:foo.job

type=command
command=echo ‘foo’

第二个job:bar.job依赖foo.job

type=command
command=echo ‘bar’
#表示该任务依赖了foo任务的执行
dependencies=foo

Step 2: 将所有job资源文件打到一个zip包中
名字可自定义,例: foo_bar.zip

Step 3: 在azkaban的web管理界面创建工程并上传zip包

Step 4: 启动工作流flow
点击 Execute Flow,并在弹出界面点击 Execute 即可执行测试
这里会发现流程上是先执行了foo再去执行bar

3.3. HDFS 操作任务
Step 1: 创建job描述文件fs.job

type=command
#需要使用命令的绝对路径
command=/home/hadoop/mw/hadoop-3.1.1/bin/hdfs dfs -mkdir /azkaban

Step 2: 将job资源文件打包成zip文件
例: fs.zip
Step 3: 通过azkaban的web管理平台创建project并上传job压缩包
Step 4: 启动执行该job

3.4. MapReduce 任务
MR 任务依然可以使用command的job类型来执行
Step 1: 创建job描述文件,及mr程序jar包(示例中直接使用hadoop自带的example.jar 求π的值 3.1415926;后面第一个参数为使用mapreduce的个数,第二个为计算π的采样数,越大越准)

type=command
command=/home/hadoop/mw/hadoop-3.1.1/bin/hadoop jar hadoop-mapreduce-examples-3.1.1.jar pi 3 5

Step 2: 将所有job资源文件打到一个zip包中
jar包所在位置: cd /home/hadoop/mw/hadoop-3.1.1/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.1.jar

Step 3: 在azkaban的web管理界面创建工程并上传zip包
Step 4: 启动job

3.5. Hive ​ 脚本任务
Step 1: 创建job描述文件和hive脚本
Hive脚本: hive.sql

create database if not exists azhive;
use azhive;
create table if not exists aztest(id string,name string) row format delimited fields terminated by ‘\t’;

Step 2: Job描述文件:hive.job

type=command
command=/home/hadoop/mw/apache-hive-3.1.0-bin/bin/hive -f ‘hive.sql’

Step 3: 将所有job资源文件打到一个zip包中
例: hive.zip

Step 4: 在azkaban的web管理界面创建工程并上传zip包
Step 5: 启动job

验证是否创建成功
cd /home/hadoop/mw/apache-hive-3.1.0-bin/
bin/hive

show databases;
use azhive;
show tables;

3.6. Azkaban 的定时任务
使用azkaban的scheduler功能可以实现对我们的作业任务进行定时调度功能
在点击了Execute Flow后,弹出界面的左下角 Schedule 进行配置

*/1 * ? * * 每分钟执行一次定时调度任务
0 1 ? * * 每天晚上凌晨一点钟执行这个任务
0 */2 ? * * 每隔两个小时定时执行这个任务
30 21 ? * * 每天晚上九点半定时执行这个任务

  1. sqoop数据迁移

4.1、概述
sqoop是apache旗下一款“Hadoop和关系数据库服务器之间传送数据”的工具。
导入数据:MySQL,Oracle导入数据到Hadoop的HDFS、HIVE、HBASE等数据存储系统;
导出数据:从Hadoop的文件系统中导出数据到关系数据库mysql等

工作机制
将导入或导出命令翻译成mapreduce程序来实现
在翻译出的mapreduce中主要是对inputformat和outputformat进行定制
4.4 、sqoop实战及原理

3.4.1 sqoop安装
安装sqoop的前提是已经具备java和hadoop的环境
1、下载并解压
下载地址
http://archive.apache.org/dist/sqoop/1.4.7
sqoop1版本详细下载地址
http://archive.apache.org/dist/sqoop/1.4.7/sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz
sqoop2版本详细下载地址
http://archive.apache.org/dist/sqoop/1.99.6/sqoop-1.99.6-bin-hadoop200.tar.gz
我们这里使用sqoop1的版本,下载之后上传到/home/hadoop/software目录下,然后进行解压

cd /home/hadoop/software
tar -zxvf sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C …/mw/

2、修改配置文件
cd /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0/conf
cp sqoop-env-template.sh sqoop-env.sh
vim sqoop-env.sh

#找到对应的配置项,打开对应注释
export HADOOP_COMMON_HOME=/home/hadoop/mw/hadoop-3.1.1
export HADOOP_MAPRED_HOME=/home/hadoop/mw/hadoop-3.1.1
export HIVE_HOME=/home/hadoop/mw/apache-hive-3.1.0-bin/

3、加入额外的依赖包
sqoop的使用需要添加两个额外的依赖包,一个是mysql的驱动包,一个是java-json的依赖包,不然就会报错
mysql-connector-java-5.1.40.jar
java-json.jar
将这个两个jar包添加到sqoop的lib目录下

cp /home/hadoop/software/mysql-connector-java-5.1.40.jar /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0/lib/
cp /home/hadoop/software/java-json.jar /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0/lib/

4、验证启动
cd /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0
bin/sqoop-version

4.5、 Sqoop的数据导入
“导入工具”导入单个表从RDBMS到HDFS。表中的每一行被视为HDFS的记录。所有记录
都存储为文本文件的文本数据(或者Avro、sequence文件等二进制数据)

列举出所有的数据库
命令行查看帮助
bin/sqoop list-databases --help

列出windows主机所有的数据库(这里的 10.57.17.214 是云主机的ip, 本地windows装了mysql可以用本机ip)
bin/sqoop list-databases --connect jdbc:mysql://10.57.17.214:3306/ --username root --password 123456

查看某一个数据库下面的所有数据表(这里的 10.57.17.214 是云主机的ip, 本地windows装了mysql可以用本机ip)
bin/sqoop list-tables --connect jdbc:mysql://10.57.17.214:3306/bp_atreus --username root --password 123456

如果出现连接拒绝,可在mysql的数据库中执行以下命令:
开启windows的远程连接权限
GRANT ALL PRIVILEGES ON . TO ‘需授权用户’@’%’ IDENTIFIED BY ‘你需要授权用户的密码’ WITH GRANT OPTION;
例:
GRANT ALL PRIVILEGES ON . TO ‘root’@’%’ IDENTIFIED BY ‘123456’ WITH GRANT OPTION;
FLUSH PRIVILEGES;

导入数据库表数据到HDFS
下面的命令用于从MySQL数据库服务器中的emp表导入HDFS。
(使用 mysql数据库中系统表 user 测试导入到hdfs;不指定分隔符则默认使用逗号)

cd /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0
bin/sqoop import --connect jdbc:mysql://10.57.17.214:3306/mysql --username root --password 123456 --table user --m 1

如果成功执行,那么会得到下面的输出。
为了验证在HDFS导入的数据,请使用以下命令查看导入的数据
hdfs dfs -ls /user/root/user
或者通过页面下载查看数据(路径也是 /user/root/user )
http://192.168.25.110:50070/explorer.html#/user/root/user

导入到HDFS指定目录
在导入表数据到HDFS使用Sqoop导入工具,我们可以指定目标目录。
使用参数 --target-dir 来指定导出目的地,
使用参数 —delete-target-dir 来判断导出目录是否存在,如果存在就删掉
使用参数 --m 表示使用几个mapreduce

cd /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0
bin/sqoop import --connect jdbc:mysql://10.57.17.214:3306/mysql --username root --password 123456 --delete-target-dir --table help_category --target-dir /sqoop/category --m 1

查看导出的数据
hdfs dfs -text /sqoop/category/part-m-00000

它会用逗号(,)分隔表的数据和字段。
导入到hdfs指定目录并指定字段之间的分隔符(通过 --fields-terminated-by 来指定)
cd /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0
bin/sqoop import --connect jdbc:mysql://10.57.17.214:3306/mysql --username root --password 123456 --delete-target-dir --table help_category --target-dir /sqoop/category2 --m 1 --fields-terminated-by ‘\t’

查看文件内容
hdfs dfs -text /sqoop/category2/part-m-00000

导入关系表到HIVE
将我们mysql表当中的数据直接导入到hive表中的话,
我们需要将hive的一个叫做hiveexec-3.1.1.jar 的jar包拷贝到sqoop的lib目录下
第一步:拷贝jar包
cp /home/hadoop/mw/apache-hive-3.1.0-bin/lib/hive-exec-3.1.0.jar /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0/lib

查看复制结果
ll /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0/lib|grep hive-exec-3.1.0.jar

第二步:准备hive数据库与表
cd /home/hadoop/mw/apache-hive-3.1.0-bin
bin/hive

create database sqooptohive;
use sqooptohive;
CREATE external TABLE help_category_hive(help_category_id int,name string,parent_category_id int,url string) row format delimited fields terminated by ‘\001’;

第三步:开始导入(将我们mysql当中的数据导入到hive表当中来)
指定导入为hive模式 --hive-import
指定hive的哪个数据库的哪个表 --hive-table
表示数据覆盖 --hive-overwrite

cd /home/hadoop/mw/sqoop-1.4.7.bin__hadoop-2.6.0
bin/sqoop import --connect jdbc:mysql://10.57.17.214:3306/mysql --username root --password 123456 --table help_category --fields-terminated-by ‘\001’ --hive-import --hive-table sqooptohive.help_category_hive --hive-overwrite --delete-target-dir --m 1

第四步:hive表数据查看
cd /home/hadoop/mw/apache-hive-3.1.0-bin
bin/hive;

use sqooptohive;
select * from help_category;

导入关系表到hive并自动创建hive表(前提表字段hive能识别,特殊字段类型hive无法识别)
我们也可以通过命令来将我们的mysql的表直接导入到hive表当中去

bin/sqoop import --connect jdbc:mysql://10.57.17.214:3306/mysql --username root --password 123456 --table help_topic --hive-import -m 1 --hive-database sqooptohive

通过这个命令,我们可以直接将我们mysql表当中的数据以及表结构一起倒入到hive当中去
cd /home/hadoop/mw/apache-hive-3.1.0-bin
bin/hive;

use sqooptohive;
show tables;
select * from help_topic;

导入表数据子集
我们可以导入表的使用Sqoop导入工具,"where"子句的一个子集。它执行在各自的数据库服务器相应的SQL查询,并将结果存储在HDFS的目标目录。
where子句的语法如下。
按照条件进行查找,通过 —where参数来查找表 user 当中User字段的值为root的
所有数据导入到hdfs上面去
bin/sqoop import
–connect jdbc:mysql://10.57.17.214:3306/mysql
–username root --password 123456 --table user
–target-dir /sqoop/user_root -m 1 --delete-target-dir
–where “User = ‘root’”

查看hdfs数据内容
hdfs dfs -text /sqoop/user_root/part*

sql语句查找导入hdfs
我们还可以通过 –query参数来指定我们的sql语句,通过sql语句来过滤我们的数据进行导入
bin/sqoop import
–connect jdbc:mysql://10.57.17.214:3306/mysql --username root --password 123456
–delete-target-dir -m 1
–query ‘select User from user where 1=1 and $CONDITIONS’
–target-dir /sqoop/user_tmp

查看hdfs数据内容
hdfs dfs -text /sqoop/user_tmp/part*

增量导入
在实际工作当中,数据的导入,很多时候都是只需要导入增量数据即可,并不需要将表中的数据全部导入到hive或者hdfs当中去,
肯定会出现重复的数据的状况,所以我们一般都是选用一些字段进行增量的导入,为了支持增量的导入,
sqoop也给我们考虑到了这种情况并且支持增量的导入数据。
它需要添加‘incremental’, ‘check-column’, 和 ‘last-value’选项来执行增量导入。

第一种增量导入使用上面的选项来实现
导入 help_category 表当中 help_category_id 大于 20 的所有数据
注意:增量导入的时候,一定不能加参数–delete-target-dir否则会报错
–incremental append 表示追加方式增量导入
–check-column help_category_id 需要检查增量的列
–last-value 20 上次导入的最后一个值

再增量导入
bin/sqoop import
–connect jdbc:mysql://10.57.17.214:3306/mysql
–username root
–password 123456
–table help_category
–incremental append
–check-column help_category_id
–last-value 20
-m 1
–target-dir /sqoop/help_category_increment

查看hdfs数据内容
hdfs dfs -text /sqoop/help_category_increment/part*

第二种增量导入通过–where条件来实现
或者我们使用–where来进行控制数据的选取会更加精准

bin/sqoop import
–connect jdbc:mysql://10.57.17.214:3306/mysql
–username root
–password 123456
–table help_category
–incremental append
–check-column help_category_id
–where “parent_category_id > 30 and parent_category_id < 36”
-m 1
–target-dir /sqoop/help_category_where

查看hdfs数据内容
hdfs dfs -text /sqoop/help_category_where/part*

Sqoop的数据导出(将数据从HDFS把文件导出到RDBMS数据库)
导出前,目标表必须存在于目标数据库中。
默认操作是从将文件中的数据使用INSERT语句插入到表中
更新模式下,是生成UPDATE语句更新表数据

hdfs导出到mysql
数据是在HDFS当中的如下目录 /sqoop/category (之前操作已导入到hdfs)

CREATE TABLE help_category_out (
help_category_id smallint(5),
name VARCHAR(512) NOT NULL,
parent_category_id smallint(5),
url VARCHAR(512) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘help categories’;

bin/sqoop export
–connect jdbc:mysql://10.57.17.214:3306/bp_atreus
–username root --password 123456
–table help_category_out
–export-dir /sqoop/category
–input-fields-terminated-by “,”

验证mysql表数据(在对应 10.57.17.214:3306/bp_atreus 数据库中查询)
select * from help_category_out;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值