[email protected]: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
所有共享访问的服务机器的公钥将拷贝到第一台机器中
(本机也要拷贝,会生成互联公钥信息到 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
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/namemapred-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.1yarn-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 1024worker 配置文件,添加对应主机的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的当前路径(即: 这时 PWD获取的是当前会话shell的当前路径(即:这时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
设置/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
浏览器范文验证:
测试上传文件:
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 即可
修改完成之后配置文件发送到其他机器上面去
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: PWDscphdfs−site.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集群
一个完整的mapreduce程序在分布式运行时有三类实例进程:
在 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所在服务器域名等的设置
添加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]
说明:
建表测试(虚拟机时间不同步添加数据会出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]
查询语法
全表查询
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语句
操作符 支持的数据类型 描述
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 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
使用LIKE运算选择类似的值
选择条件可以包含字符或数字:
% 代表零个或多个字符(任意个字符)。
_ 代表一个字符。
RLIKE子句是Hive中这个功能的一个扩展,其可以通过Java的正则表达式这个更强大的语言来指定匹配条件。
查找以8开头的所有成绩
select * from score where s_score like ‘8%’;
查找第二个数值为9的所有成绩数据
select * from score where s_score like ‘_9%’;
查询课程编号中包含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 语句
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
使用 ORDER BY 子句排序
ASC(ascend): 升序(默认)
DESC(descend): 降序
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内部进行排序,对全局结果集来说不是排序。
2.9.5. 分区排序(DISTRIBUTE BY)
Distribute By:类似MR中partition,进行分区,结合sort by使用。
注意,Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
先按照学生id进行分区,再按照学生成绩进行排序。
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;
Hive 函数
3.1. 内置函数
内容较多,见《Hive官方文档》
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
查看系统自带的函数
show functions;
显示自带的函数的用法
desc function upper;
详细显示自带的函数的用法
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. 自定义函数
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相当于一个数据传递员,内部有三个组件:
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大要素
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: PWDscp−rshells/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
采集端配置文件开发
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原始数据,我们每天都要对其进行处理,
处理步骤如下所示:
安装
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组件
单服务模式: 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
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; )
注:先配置好服务器节点上的时区
实战
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 ? * * 每天晚上九点半定时执行这个任务
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;