大数据处理之Hadoop
大数据Hadoop
基础:
- SQL功底
- Linux功底
- Java SE
怎么学?
第一阶段:大数据基础 Hadoop2.x
一、大数据应用发展前景
-
数据公司、政府、金融、银行、电子商务
-
最经典的大数据的案例:啤酒和尿布
-
应用分析:
- 统计
- 推荐
- 机器学习(分类、聚类)
- 人工智能,预测(算法)
-
SQL on Hadoop
- Hive 骨灰级玩家
- Prestore(国外比较多)
- Impala(国外比较多,不是很稳定)
- Phoneix(基于HBase)国外运用比较多
- Spark SQL
-
Hadoop诞生 网络可扩展,分析可存储
- Common:工具、基础,为服务
- 来源(Google) -----> Hadoop诞生的东西
- GFS(C语言编写的) ------> HDFS(Java编写的,也是分布式的): 存储海量数据
- 分布式(思想:分而治之,大数据集分为许多小的数据集,每个数据集都进行逻辑业务处理(map),合并统计数据集结果(reduce))
- 分布式
- 安全性(副本数据,每一个数据会有3个副本)
- 数据是以block的方式进行存储
- MapReduce ----------> MapReduce : 对海量数据的分析处理
- BigTable ------> HBase :
- YARN:分布式资源管理框架(Hadoop2开始出现)
- 管理整个集群的资源(内存、cpu核数)
- 分配调度集群的资源
-
检索工具
- Nutch
- Lunence
二、Hadoop概述
2.1 Apache Hadoop 起源
- Apache Lucene:开源的高性能全文检索工具包
- Apache Nutch:开源的Web搜索引擎
- Google三大论文:MapReduce、GFS、BigTable
- Apache Hadoop:大规模数据处理
2.2 HDFS 系统架构图
- NameNode:主节点---存储文件的元数据如文件名、文件目录结构、文件属性(生成时间,副本数,文件权限),以及每个文件的块列表和块所在的DataNode等。
- 存在内存当中
- 本地磁盘
- fsimage:镜像文件
- edites:编辑日志
- Datanodes:从节点----在本地文件系统存储文件块数据,以及块数据的校验和。
- Secondary NameNode:用来监控HDFS状态的辅助后台程序,每隔一段时间获取HDFS快照。
- rep:副本数
2.3 YARN 架构图
-
Node Manager:每台机器都需要管理
- 单个节点上的资源管理
- 处理来自ResourceManager的命令
- 处理来自ApplicationMaster的命令
-
Resource Manage:管理整个集群
- 处理客户端请求
- 启动/监控ApplicationMaster
- 监控NodeManager
- 资源分配与调度
-
App Mstr:ApplicationMaster 应用管理者,每有一个新开启的项目,就向Resource Manager申请一个管理者,对项目进行管理、资源分配和调度
- 数据切分
- 为应用程序申请资源,并分配给内部任务
- 任务监控与容错
-
Container:容器,一个项目,只能在一个容器中运行,相当于是分配给这个项目的资源
- 对任务运行环境的抽象,封装了cpu、内存等多维资源以及环境变量、启动命令等任务运行相关的信息
2.4 MapReduse 离线计算框架
- 将计算过程分为两个阶段,Map和reduce
- Map阶段并行处理输入数据
- Reduce阶段对Map结果进行汇总
- Shffle连接Map和Reduce两个阶段
- Map Task 将数据写到本地磁盘上
- Reduce Tase 从每个Map Task上读取一份数据
- 仅适合离线批处理
- 具有很好的容错性和扩展性
- 适合简单的批处理任务
- 缺点明显
- 启动开销大
- 过多使用磁盘导致效率低下等
2.5 MapReduce on YARN
三、Hadoop 2.x 生态系统
- Sqoop:SQL on Hadoop 将关系型数据中的数据存储到HDFS中
- Flume:日志收集框架
- Oozie:对整个项目进行管理和调度(工具框架)
- Hive:在MapReduce基础上
- Pig:类似Hive
- HBase:分布式数据库
- Cloudera Manager:集群管理框架
- Zookeeper:协作框架,高可用
- Hue:将所有的管理页面集成到一起
四、Hadoop 环境搭建
4.1 环境要求
-
一些基本命令
- 查看软件 rpm -qa|gre java
- 卸载软件 rpm -e --nodeps java...
- vim:G 进入到文件的末尾ls
-
JDK
-
Hadoop
- tar -zxvf Hadoop-2.5.0.tar.gz -C /opt/modules/
- 修改 /Users/theniceboy/Desktop/modules/hadoop-2.5.0/etc/hadoop/hadoop-env.sh 中的 JAVA_HOME
# The java implementation to use. export JAVA_HOME=/usr/local/java/jdk1.8.0_131 - tar -zxvf Hadoop-2.5.0.tar.gz -C /opt/modules/
4.2 本地模式
-
MapReduce 程序运行在本地,启动 JVM
-
在 hadoop-2.5.0下新建 wcinput 目录并在该目录下新建一个 wcinput 文件,输入内容
hadoop yarn hadoop mapreduce hadoop hdfs yarn nodemanager hadoop resuourcemanager -
在 hadoop-2.5.0 目录下 运行 hadoop 中的 wordcount 方法(统计单词出现的个数)
- wcinput 输入文件夹
- wcoutput 输出结果的文件夹,此文件夹不能预先存在
[root@MagiwiseCentOS-1 hadoop-2.5.0]# bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount wcinput wcouput- 运行结果
-
4.3 HDFS 环境配置
- 修改 hadoop-2.5.0/etc/hadoop/core-site.xml 配置文件
<configuration>
<property>
<name>fs.defaultFS</name>
<!--hostname-->
<value>hdfs://hadoop:8020</value>
</property>
<!--配置hadoop运行的临时目录-->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/modules/hadoop-2.5.0/data/tmp</value>
</property>
</configuration>
- 修改 hadoop-2.5.0/etc/hadoop/hdfs-site.xml 配置文件
<configuration>
<!--配置hdfs中存储的份数-->
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
- Format the filesystem
[root@hadoop hadoop-2.5.0]# bin/hdfs namenode -format
- 启动 namenode
[root@hadoop hadoop-2.5.0]# sbin/hadoop-daemon.sh start namenode
- 启动datanode
[root@hadoop hadoop-2.5.0]# sbin/hadoop-daemon.sh start datanode
- 使用 jps 命令查看启动情况
- 日志文件存春在 logs 目录中
- 在 hdfs 中新建文件夹 操作 hdfs 的命令都在 bin/hdfs 目录下面,具体操作命令类似于Linux,也可以访问 50070 端口进行查看(hdfs文件管理系统web页面)
[root@hadoop hadoop-2.5.0]# bin/hdfs dfs -mkdir -p /usr/root/maperduce/wordcount/input
- 上传文件到 hdfs 目录中
[root@hadoop hadoop-2.5.0]# bin/hdfs dfs -put /opt/modules/hadoop-2.5.0/wcinput/wc.input /usr/root/mapreduce/wordcount/input/
- 下载 hdfs 目录中的文件
[root@hadoop hadoop-2.5.0]# bin/hdfs dfs -get /usr/root/mapreduce/wordcount/input/wc.input
- 运行一下 wordcount
[root@hadoop hadoop-2.5.0]# bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /usr/root/mapreduce/wordcount/input/wc.input /usr/root/mapreduce/wordcount/output
或者
[root@hadoop hadoop-2.5.0]# bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /usr/root/mapreduce/wordcount/input//usr/root/mapreduce/wordcount/output
- 查看一下输出
[root@hadoop hadoop-2.5.0]# bin/hdfs dfs -ls /usr/root/mapreduce/wordcount/output
4.4 配置 yarn
- 修改 hadoop-2.5.0/etc/hadoop/yarn-env.sh 配置文件
# some Java parameters
export JAVA_HOME=/usr/local/java/jdk1.8.0_281
- 修改 hadoop-2.5.0/etc/hadoop/yarn-site.xml 配置文件
<configuration>
<!--配置运行 mapreduce-->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!-- 配置resourcemanager在哪一台机器上 -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop</value>
</property>
</configuration>
- 修改 hadoop-2.5.0/etc/hadoop/slaves 文件,记录从节点所在的机器,里面记录的是主机名或者ip地址
hadoop
- 启动 yarn resourcemanager
[root@hadoop hadoop-2.5.0]# sbin/yarn-daemon.sh start resourcemanager
- 启动 yarn nodemanager
[root@hadoop hadoop-2.5.0]# sbin/yarn-daemon.sh start nodemanager
- 查看启动情况
- yarn 启动成功后,可以在 8088 端口访问web页面
- 修改 hadoop-2.5.0/etc/hadoop/mapred-env.sh 配置文件
export JAVA_HOME=/usr/local/java/jdk1.8.0_281
- 复制 mapred-site.xml.template 并重命名为 mapred-site.xml,然后修改配置
<configuration>
<!--配置 mapreduce 运行在 yarn 上-->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
- 重新运行 wordcount 运行之前,必须要删除之前存在的output目录
[root@hadoop hadoop-2.5.0]# bin/hdfs dfs -rm -r /usr/root/mapreduce/wordcount/output*
[root@hadoop hadoop-2.5.0]# bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /usr/root/mapreduce/wordcount/input/ /usr/root/mapreduce/wordcount/output
- 进入 yarn 管理界面查看
- 运行结束,进入 HDFS 查看结果
4.5 总结
Hadoop 2.x
-
common
-
HDFS
- 存储数据
- namenode
- 存储文件系统的元数据,命名空间namespace
- datanode
- 存储数据
- secondarynamenode
- 辅助namenode工作,合并两个文件(定时周期)
- namenode只是存储文件名称、文件结构等信息,具体的数据存储在datanode中,所以数据流不从namenode过
-
YARN
- Hadoop 操作系统 ---> data 操作系统
- 管理所有的资源
- 可以运行各种框架
- 对于每一个运行在其上面的应用都分配一个应用管理者
- 通过容器 container 将资源分配给应用,体现了隔离的思想
- Resourcemanager
- 整个集群资源的管理和调度
- nodemanager
- 管理每个节点的资源与调度
-
MapReduce
- 分而治之
- map
- 分,
- reduce
- 合并
- map
- input --> map --> shuffle(洗牌,排序) --> reduce --> output
- 运行在yarn上的数据处理框架
- 分布式并行的计算框架
- 运行模式
- 本地模式 仅仅用于测试,小数据量
- yarn 模式
- 分而治之
-
hdfs 命令
- bin/hdfs dfs
[root@hadoop hadoop-2.5.0]# bin/yarn jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /usr/root/mapreduce/wordcount/input/ /usr/root/mapreduce/wordcount/output
4.6 问题解析
- hdfs 格式化错误
- core-site.xml
- 主机名与IP地址的映射
- namenode启动出错
- 日志信息
- 在安装目录下logs文件夹中,直接看log结尾的文件
- more xxxx.log 分页查看
- tail -f xxx.log 一般用于查看启动日志,文件的末尾
- Tail -100f xxx.log 查看倒数100行
- 日志信息
4.7 查看 yarn 历史服务器 以及 日志聚集
- 第一步:启动历史服务器
[root@hadoop hadoop-2.5.0]# sbin/mr-jobhistory-daemon.sh start historyserver
- 第二步:点击进去
-
启动 log Aggregation 日志的聚集 这个是yarn上的一个服务,所以在 yarn-site.xml中进行配置
- 将运行完成以后,将日志信息上传到HDFS系统上
- 配置 log Aggregation 日志的聚集
<!-- 配置 yarn 的日志聚集 --> <property> <name>yarn.log-aggregation-enable</name> <value>true</value> </property> <!-- 日志保存的最长时间 以秒为单位--> <property> <name>yarn.log-aggregation.retain-check-interval-seconds</name> <value>640800</value> </property>- 重启 yarn
[root@hadoop hadoop-2.5.0]# sbin/yarn-daemon.sh stop resourcemanager stopping resourcemanager [root@hadoop hadoop-2.5.0]# sbin/yarn-daemon.sh stop nodemanager stopping nodemanager [root@hadoop hadoop-2.5.0]# sbin/mr-jobhistory-daemon.sh stop historyserver stopping historyserver [root@hadoop hadoop-2.5.0]# sbin/yarn-daemon.sh start resourcemanager starting resourcemanager, logging to /opt/modules/hadoop-2.5.0/logs/yarn-root-resourcemanager-hadoop.out [root@hadoop hadoop-2.5.0]# sbin/yarn-daemon.sh start nodemanager starting nodemanager, logging to /opt/modules/hadoop-2.5.0/logs/yarn-root-nodemanager-hadoop.out [root@hadoop hadoop-2.5.0]# sbin/mr-jobhistory-daemon.sh start historyserver starting historyserver, logging to /opt/modules/hadoop-2.5.0/logs/mapred-root-historyserver-hadoop.out [root@hadoop hadoop-2.5.0]# [root@hadoop hadoop-2.5.0]# jps 31586 JobHistoryServer 30053 ResourceManager 30982 NodeManager 22120 DataNode 32217 Jps 21743 NameNode ## 重新运行新的任务 [root@hadoop hadoop-2.5.0]# [root@hadoop hadoop-2.5.0]# bin/yarn jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /usr/root/mapreduce/wordcount/input /usr/root/mapreduce/wordcount/output2 -
查看 日志聚集
4.8 hadoop 配置文件
-
默认配置文件 相对应的jar包中
- core-default.xml
- hdfs-default.xml
- yarn-default.xml
- mapred-default.xml
-
自定义配置文件 $HADOOP_HOME/etc/hadoop/
- core-site.xml
- hdfs-site.xml
- yarn-site.xml
- mapred-site.xml
4.9 HDFS 垃圾回收
修改 hadoop-2.5.0/etc/hadoop/core-site.xml
</property>
<!-- 配置垃圾回收站,表示删除的文件进入垃圾回收站,最长保存时间,以分钟为单位 -->
<property>
<name>fs.trash.interval</name>
<value>10080</value>
<!-- <value>7*24*60</value> -->
</property>
4.10 启动 HDFS 和 YARN 方式
-
启动方式
- 方式一:各个服务逐一启动
# 启动 hdfs hadoop-daemon.sh start|stop namenode |datanode|secondarynamenode # 启动 yarn yarn-daemon.sh start|stop resourcemanager|nodemanager # 启动 mapreduce mr-historyserver-daemon.sh start|stop historyserver- 方式二:各个模块分开启动需要配置ssh免密登录
# 启动 hdfs start-dfs.sh # 停止 hdfs stop-dfs.sh # 启动 yarn start-yarn.sh # 停止 yarn stop-yarn.sh- 方式三:全部启动
# 启动 start-all.sh # 停止 stop-all.sh
4.11 配置 SSH 无密钥登录
- 使用密码登录,每次都必须输入密码,非常麻烦。SSH还提供了公钥登录,可以省去输入密码的步骤。
- 所谓的公钥登录,就是用户将自己的公钥存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先存储的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码
-
步骤
- 生成公钥/私钥对
$ ssh-keygen -t rsa- 在 $HOME/.ssh/ 目录下,会新生成两个文件:id_rsa.pub 和 id_rsa。前者是你的公钥,后者是你的私钥。
- 拷贝公钥至 authorized_keys 文件
hadoop(主机名),一般在集群中,每个主机名都配置为相同的
4.12 细节问题 各个服务组件如何配置在那台服务器运行并测试
- 指定 namenode 运行机器 core-site.xml
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop:8020</value>
</property>
- 指定 datanode 运行机器 slaves 文件指定
hadoop
- 指定 secondarynamenode 运行机器 hdfs-default.xml 文件指定
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>0.0.0.0:50090</value>
<description>
The secondary namenode http server address and port.
</description>
</property>
<property>
<name>dfs.namenode.secondary.https-address</name>
<value>0.0.0.0:50090</value>
<description>
The secondary namenode https server address and port.
</description>
</property>
-
指定 yarn 运行机器
- 指定 resourcemanager 运行机器 yarn-site.xml 文件指定
<!-- 配置resourcemanager在哪一台机器上 --> <property> <name>yarn.resourcemanager.hostname</name> <value>hadoop</value> </property>-
指定 nodemanager 运行机器 slaves 文件指定
# 主机名 hadoop
-
指定 mapreduce historyserver 运行机器 mapred-site.xml 文件指定
<property> <name>mapreduce.jobhistory.address</name> <value>hadoop:10020</value> </property> <property> <name>mapreduce.jobhistory.webapp.address</name> <value>hadoop:19888</value> </property> -
启动顺序
[root@hadoop hadoop-2.5.0]# sbin/start-all.sh
This script is Deprecated. Instead use start-dfs.sh and start-yarn.sh
Starting namenodes on [hadoop]
hadoop: starting namenode, logging to /opt/modules/hadoop-2.5.0/logs/hadoop-root-namenode-hadoop.out
hadoop: starting datanode, logging to /opt/modules/hadoop-2.5.0/logs/hadoop-root-datanode-hadoop.out
Starting secondary namenodes [0.0.0.0]
0.0.0.0: starting secondarynamenode, logging to /opt/modules/hadoop-2.5.0/logs/hadoop-root-secondarynamenode-hadoop.out
starting yarn daemons
starting resourcemanager, logging to /opt/modules/hadoop-2.5.0/logs/yarn-root-resourcemanager-hadoop.out
hadoop: starting nodemanager, logging to /opt/modules/hadoop-2.5.0/logs/yarn-root-nodemanager-hadoop.out
4.13 解决 bin/hdfs dfs 命令警告问题
-
警告内容
WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platofrm... using builtin-java classes where applicable -
出现原因
- 默认下载hadoop的时候,hadoop默认自带的 lib/native 库和系统本地编译的库不一致导致的
-
解决方式:自己编译hadoop源码,然后进行替换 lib/native
4.14 hadoop 编译
- 下载 源码包 : hadoop-2.5.0-src.tar.gz http://archive.apache.org/dist/
- 解压 源码包: tar -zxf hadoop-2.5.0-src.tar.gz
- 查看解压后的文件中有一个 BUILDING.txt 文档
五、深入 hadoop 2.x
5.1 HDFS 的架构 和启动过程
5.1.1 HDFS 的来源
- 源自于Google的GFS论文
- 发表于2003年10月
- HDFS是GFS的克隆版
- Hadoop Distributed File System
- 易于扩展的分布式文件系统
- 运行在大量普通廉价机器上,提供容错机制
- 为大量用户提供性能不错的文件存取服务
5.1.2 namenode
- namenode 是一个中心服务器,单一节点(简化系统的设计和实现),负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。
- 文件操作,namenode负责文件元数据的操作,datanode负责处理文件内容的读写请求,跟文件内容相关的数据流不经过namenode,只会询问它跟哪个datanode联系,否则namenode会成为系统的瓶颈。
- 副本存放在哪些datanode上由namenode来控制,根据全局情况作出块放置决定,读取文件时namenode尽量让用户先读取最近的副本,降低带块消耗和读取时延。(但是可以根据自己的实际需求进行一些调整,bin/hdfs 下有个 balancer 命令,run a clster balancing utility,运行一个集群的均衡策略的工具,可以均衡集群上数据存储分布的情况)
- namenode全权管理数据块的复制,它周期性地从集群中的每个datanode接收心跳信号和块状态报告(Blockreport)。接收到心跳信号意味着datanode节点工作正常。块状态报告包含一个该datanode上所有数据块的列表。
- namenode 和 datanode 交互方式( 走的是rp协议,在common模块中运行的)
- 定期 datanode 给 namenode 发送心跳 ---是否活着
- datanode 给 namenode 发送块的报告 --- 具体情况
5.1.3 datanode
- 一个数据块在datanode以文件存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
- datanode启动后向namenode注册,通过后,周期性(1小时)的向namenode上报所有信息。
- 心跳是每3秒一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用。
- 集群运行中可以安全加入和退出一些机器
- 块存放在 tmp目录下面的文件夹中,真正的存储结构。 块默认是128M一块
5.1.4 文件
- 文件切分(默认大小128M),以块为单位,每个块有多个副本存储在不同的机器上,副本数可在文件生成时指定(默认为3)。
- namenode是主节点,存储文件的元数据如文件名、文件目录结构、文件属性(生成时间、副本数、文件权限),以及每个文件块列表以及块所在的datanode等等。
- 指定块副本数 : -setrep [-R] [-w]
... - datanode在本地文件系统存储文件块数据,以及块数据的校验和。
- 可以创建、删除、移动或重命名文件,当文件创建、写入和关闭之后不能修改文件内容。
- 块副本设置的策略
5.1.5 数据损坏(corruption处理)面试题
-
datanode自动去检测和修复块的损坏,以保证块的备份数目,维护数据的完整性。
-
当datanode读取block的时候,它会计算checksum
-
如果计算后的checksum,与block创建时值不一样,说明该block已经损坏
-
Client读取其他DN上的block
-
namenode标记该块已经损坏,然后复制block达到预期设置的文件备份数
-
datanode在其文件创建后会验证其checksum
5.1.6 HDFS 启动过程
- namenode 存储的文件 一部分在内存中,一部分在本地磁盘(fsimage + edits)
- 内存
- 本地磁盘
- fsimage: fs 镜像文件(格式化HDFS文件系统就是为了生成fsimage 文件)
- edits :编辑日志文件,存储对文件到所有操作日志记录
5.1.6.1 第一次启动
- 步骤:
- format
- fsimage
- start namenode
- read fsimage
- start datanode
- 向namenode注册
- 给namenode 发送 block report
- Create dir /usr/root/tmp ------> 会写到 edits 中
- Put files /usr/root/tmp(*-site.xml) -----> 会写到 edits 中
- delete file /usr/root/tmp/core-site.xml -----> 会写入到 edits 中
5.1.6.1 第二次启动
-
namenode
- reda fsimage
- read edits
-
gen write fsimage [new] 生成 写入到一个新的 fsimage中,下次酒直接读取这个fsimage,不再去读取edits了,读取edits是一个很慢的操作
-
gen edits [null] 新生成一个编辑日志,初始化为空
-
start datanode
- 向namenode注册
- 给namenode 发送 block report
-
Create dir /usr/root/tmp ------> 会写到 edits 中
-
Put files /usr/root/tmp(*-site.xml) -----> 会写到 edits 中
-
delete file /usr/root/tmp/core-site.xml -----> 会写入到 edits 中
5.2 HDFS Java API使用
5.2.1 HDFS Shell 命令
5.2.1.1 文件操作命令
- 调用文件系统(FS)Shell 命令使用 bin/hdfs dfs 的形式
- 所有的FS Shell 命令使用URL路径作为参数
- URL格式是:scheme://authority/paht。 HDFS的scheme是hdfs,对本地文件系统,scheme是file。其中scheme和authority参数都是可选的,如果未加指定,就会使用配置中指定的默认scheme
- 例子: /parent/child 可以表示成 hdfs://namenode:namenodePort/parent/child
- 或者:/parent/child(假设配置文件是namenode:namenodePort)
- bin/hdfs dfs -Dfs.defaultFS=file:/// -ls /
- 大多数FS Shell 命令的行为和对应的Unix Shell命令类似
5.2.1.2 管理命令
- 查看集群的状态:bin/hdfs dfsadmin -report
- 刷新集群状态:bin/hdfs dfsadmin -refresh
5.2.3 Java API 调用
5.2.3.1 开发环境准备
-
安装 maven,用于管理项目依赖包(apache-maven-3.0.5-bin.tar)
-
安装Eclipse(eclipse-jee-kepler-SR1-linux-gtk-x86_64.tar)
-
配置Eclipse与maven插件
-
设置Linux下Eclipse快捷键
- 点击eclipse窗口栏的window --> Perferences --> 左边搜索框输入keys --> 点击打开以后在右边的command里面找到如下两个key对其进行修改
key oldValue modefyValue Content Assist Ctrl+Space Alt+/ Word Completion Alt + / Ctrl+Space(只要不与其他快捷键冲突) -
设置Eclipse字体大小(Java文件和XML文件)
-
创建Maven Project,配置POM文件
5.2.3.2 使用 HDFS FS API 详解
- 文件操作
- 上传本地文件到HDFS
- 读取文件
- 在hadoop fs 中新建文件,并写入
- 重命名文件
- 删除hadoop fs 上到文件
- 目录操作
- 读取某个目录下到所有文件
- 在hadoop fs 上创建目录
- 删除目录
- HDFS 信息
- 查找某个文件在HDFS集群到位置
- 获取HDFS集群上所有节点名称信息
5.3 secondarynode 辅助namenode
- 辅助namenode
- 本地磁盘
- fsimage
- edits
- 定期的将fsimage和edits合并 成为一个新的 fsimage,并生成一个新的空的edits
- 本地磁盘
5.4 namenode 安全模式
- 发生在 namenode读取fsimage和edit完毕,并生成一个新的fsimage和新的edits之后,namenode就进入了安全模式。
- 等待 datanode 向它发送 block report
- 当 datanodes blocks / total blocks = 99.999%, 此时安全模式才会退出
- 在安全模式期间,有些操作是不能进行的
- 只能查看文件系统的文件
- 不能改变文件系统的命名空间
- 不能创建文件
- 不能上传文件
- 不能删除文件
- hdfs启动过程中,在关闭安全模式之前,会有30秒的稳定时间。所有的服务器在启动时到用户可以操作之间,都会有一个稳定时间。
5.5 YARN 架构、应用监控
5.5.1 Yarn 架构
- yarn可以管理资源、调度资源
- yarn没有自己的独立进程,上面运行的是其他的框架,例如mapreduce(处理数据)、spark
- Resourcemanager
- 全局的资源管理器,整个集群只有一个,负责集群资源的统一管理和调度分配
- 功能
- 处理客户端请求
- 启动/监控ApplicationMaster
- 监控NodeManger
- 资源分配与调度
- NodeManger
- 整个集群有多个,负责单阶段资源管理和使用
- 功能
- 单个节点上的资源管理和任务管理
- 处理来自resourcemanager的命令
- 处理来自ApplicationMaster的命令
- nodemanager管理抽象容器,这些容器代表着可供一个特定应用程序使用的针对每个节点的资源
- 定时地向resourcemanager汇报本节点上的资源使用情况和各个Container的运行状态,也会向resourcemanager发送心跳
- nodemanager也会像Applicationmaster发送报告
- Application Master
- 管理一个在YARN内运行的应用程序的每个实例
- 功能
- 数据切分(是客户端去做的,不是Applicationmaster去做的)
- 为应用程序申请资源,并进一步分配给内部任务
- 任务监控与容错
- 负责协调来自resourcemanager的资源,开通nodemanager监视容器的执行和资源使用(CPU、内存等资源分配)
- container
- yarn中资源抽象,封装某个节点上多维度资源,如内存、CPU、磁盘、网络等,当AM向RM申请资源时,RM向AM返回资源便是用container表示的
- yarn会为每个任务分配一个container,且该任务只能使用该container中描述的资源,达到隔离的目的
- 功能
- 对任务运行环境的抽象
- 描述一系列信息
- 任务运行资源(节点、内存、CPU)
- 任务启动命令
- 任务运行环境
5.5.2 yarn 资源管理
-
资源调度和资源隔离是yarn作为一个资源管理系统,最重要和最基础的两个功能。资源调度由resourcemanager完成,而资源隔离由各个nodemanager实现。
-
resource将某个nodemanager上资源分配给任务(这就是所谓的资源调度)后,nodemanager按照要求为任务提供相应的资源,甚至保证这些资源应具有独占性,为任务运行提供基础的保证,这就是所谓的资源隔离。
-
当谈及到资源时,我们通常指内存、CPU和IO三种资源。Hadoop YARN同时支持内存和CPU两种资源的调度。
-
内存资源多少会决定任务的生死,如果内存不够,任务可能会运行失败;相比之下,CPU资源则不同,它只会决定任务运行的快慢,不会对生死产生影响。
-
Nodemanager 资源调度配置 yarn-site.xml
-
yarn允许用户配置每个节点上可用的物理内存资源,注意,这里是“可用的”,因为一个节点上的内存会被若干个服务共享,比如一部分给yarn,一部分给HDFS,一部分给HBase等,yarn配置的只是自己可以使用的,配置参数如下:(一般保持默认值即可)
-
目前的CPU被划分成虚拟CPU(CPU virtual Core),这里的虚拟CPU是yarn自己引入的概念,初衷是:考虑到不同节点的CPU性能可能不同,每个CPU具有的计算能力也是不一样的,比如某个物理CPU的计算能力可能是另外一个物理CPU的2倍,这时候,你可以通过为第一个物理CPU多配置几个虚拟CPU弥补这种差异。用户提交作业时,可以指定每个任务需要的虚拟CPU个数。在yarn中,CPU相关配置参数如下:
-
注意:虚拟内存其实本质是磁盘空间,llinux系统下是swap空间就是虚拟内存的一种形式。
5.5.3 yarn 生态系统
-
apacher slider
5.6 MapReduce
Hadoop 2.x 包含三个部分:
- hdfs
- yarn
- mapreduce
- 思想:分而治之
- map:对每一部分数据进行处理,最关键部分,不可或缺,同时也集中体现了并行思想
- reduce:合并,可以没有
- 思想:分而治之
5.6.1 mapreduce 编程模型
- 一种分布式计算模型,解决海量数据的计算问题
- mapreduce将整个并行计算过程抽象到两个函数
- map(映射):对一些独立元素组成的列表的每一个元素进行指定的操作,可以高度并行
- reduce(化简或合并):对一个列表的元素进行合并
- 一个简单的mapreduce程序只需要指定map()、reduce()、input、output,剩下的事由框架完成。
- MapReduce 将作业的整个运行过程分为两个阶段:Map阶段 和 Reduce阶段
- Map阶段由一定数量的Map Task组成
- 输入数据格式解析:InputFormat
- 输入数据处理:Mapper
- 数据分组:Partitioner
- Reduce阶段由一定数量的Reduce Task组成
- 数据远程拷贝
- 数据按照key排序
- 数据处理:Reducer
- 数据输出格式:OutputFormat
5.6.1.1 mapreduce 数据传输
-
传输方向
input ---> map --> reduce --> output
-
数据传输的流通格式:<key, value>
5.6.1.2 编写 MapReduce 程序
-
基于MapReduce计算模型编写分布式并行程序非常简单,程序员主要编码工作就是 实现Map 和 Reduce 函数
-
其他的并行程序中的种种负载问题,如分布式存储,工作调度,负载平衡,容错处理,网络通信等,均由yarn框架负责处理。
-
操作过程
input:<key,value> map output:<key,value> ----------------------------- input:<key,value> reduce output:<key,value> wc.input 转化为 <key, value> key:偏移量 hadoop yarn -------> <0, hadoop yarn> hadoop mapreduce -------> <11, hadoop mapreduce> hadoop hdfs -------> <26, hadoop hdfs> yarn nodemanager -------> <37, yarn nodemanager>
5.6.1.3 MapReduce 八股文 编程规范
-
八股文模版
package com.zhang.mapreduce; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException; import java.util.StringTokenizer; public class ModelMapReduce { //step 1: map class //public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> //TODO public static class modelMapper extends Mapper<LongWritable, Text, Text, IntWritable> { @Override public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { //TODO } } //step 2: reduce class // public class Reducer<KEYIN, VAKUEIN, KEYOUT, VALUEOUT> //TODO public static class modelReducer extends Reducer<Text, IntWritable, Text, IntWritable> { @Override public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { //TODO } } //step 3: driver, component job public int run(String[] args) throws IOException, ClassNotFoundException, InterruptedException { // 1: get configuration Configuration configuration = new Configuration(); // 2: create job Job job = Job.getInstance(configuration, this.getClass().getSimpleName()); // 3: run jar job.setJarByClass(this.getClass()); // 4: set job // input --> map --> reduce --> output // 4.1: input // TODO Path inPath = new Path(args[0]); FileInputFormat.addInputPath(job, inPath); // 4.2: map // TODO job.setMapperClass(modelMapper.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); //4.3: reduce //TODO job.setReducerClass(modelReducer.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); // 4.4 output //TODO Path outPath = new Path(args[1]); FileOutputFormat.setOutputPath(job, outPath); // 5: submit job // 打印日志信息 boolean isSucess = job.waitForCompletion(true); return isSucess ? 0 : 1; } // step 4: run program public static void main(String[] args) throws InterruptedException, IOException, ClassNotFoundException { // String[] arg = {"/user/theniceboy/data/wcinput", "/user/theniceboy/data/wcoutput1"}; int status = new modelMapReduce().run(args); System.exit(status); } } -
MapReduce中,map和reduce函数准巡如下常规格式:
-
map:(K1, V1 ) ---> list(K2,V2)
-
reduce: (K2, list(V2) ) ----> list(K3, V3) ----- 将key相同的value合并到一起,放到一个集合当中
-
-
Mapper 的基类
protected void map(KEY key, VALUE value, Context context) throws IOException, InterruptedException { } -
Reduce的基类
protected void reduce(KEY key, Iterable<VALUE> values, Context context) throws IOException, InterruptedException { } -
Context 是上下文对象
-
Driver:组装成job去运行
-
MapReduce运行模式
- 本地模式
- 运行在yarn上
-
代码示例
package com.zhang.mapreduce; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.FileOutputStream; import java.io.IOException; import java.util.StringTokenizer; // public class WordCountMapReduce extends Configured implements Tool 实现 driver中的方法 public class WordCount { //step 1: map class //public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> public static class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> { private Text MapOutPutKey = new Text(); private final static IntWritable MapOutPutValue = new IntWritable(1); @Override public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String linevalue = value.toString(); //String strs = lineValue,split(" "); --- 内存消耗太大,不建议使用 StringTokenizer stringTokenizer = new StringTokenizer(linevalue); // iterator 迭代循环取出数据 while(stringTokenizer.hasMoreTokens()){ String WordValue = stringTokenizer.nextToken(); // set key MapOutPutKey.set(WordValue); // output context.write(MapOutPutKey, MapOutPutValue); } } } //step 2: reduce class public static class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable outputValue = new IntWritable(); @Override public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for(IntWritable value : values) { sum += value.get(); } outputValue.set(sum); context.write(key, outputValue); } } //step 3: driver, component job public int run(String[] args) throws IOException, ClassNotFoundException, InterruptedException { // 1: get configuration Configuration configuration = new Configuration(); // 2: create job Job job = Job.getInstance(configuration, this.getClass().getSimpleName()); // 3: run jar job.setJarByClass(this.getClass()); // 4: set job // input --> map --> reduce --> output // 4.1: input Path inPath = new Path(args[0]); FileInputFormat.addInputPath(job, inPath); // 4.2: map job.setMapperClass(WordCountMapper.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); //4.3: reduce job.setReducerClass(WordCountReducer.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); // 4.4 output Path outPath = new Path(args[1]); FileOutputFormat.setOutputPath(job, outPath); // 5: submit job // 打印日志信息 boolean isSucess = job.waitForCompletion(true); return isSucess ? 0 : 1; } // step 4: run program public static void main(String[] args) throws InterruptedException, IOException, ClassNotFoundException { // String[] arg = {"/user/theniceboy/data/wcinput", "/user/theniceboy/data/wcoutput1"}; int status = new WordCount().run(args); System.exit(status); } } -
MapReduce 标准结构
-
遗留问题
- 打包成 jar 包后运行提示找不到类
5.6.2 MapReduce 数据类型
- Long --> LongWritable
- Int ---> IntWritabe
- String ---> Text
- Writable
- Write() 是把每个对象序列化到输出流
- readFields()是把输入流子节反序列化
5.6.3 排序
-
WritableComparable
- <key,value>
- 依据 key
- 比较
- key,不但需要继承Writable,需要继承 Comparable
- Value, 只需要继承 Writable
- 依据 key
- <key,value>
-
Java 值对象的比较
- 重写toString()、hashCode()、equals()方法
-
用于value的类
package com.zhang.mapreduce; import org.apache.hadoop.io.Writable; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.Objects; public class PaiWritable implements Writable { private int id; private String name; public PaiWritable(){ } public PaiWritable(int id, String name){ this.set(id, name); } private void set(int id, String name) { this.setId(id); this.setName(name); } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PaiWritable that = (PaiWritable) o; return id == that.id && name.equals(that.name); } @Override public int hashCode() { return Objects.hash(id, name); } @Override public String toString() { return id + "\t" + name; } @Override public void write(DataOutput out) throws IOException { out.writeInt(id); out.writeUTF(name); } @Override public void readFields(DataInput in) throws IOException { //顺序相同 this.id = in.readInt(); this.name = in.readUTF(); } } -
用于key的类,也可以用与value
package com.zhang.mapreduce; import org.apache.hadoop.io.Writable; import org.apache.hadoop.io.WritableComparable; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.Objects; public class PaiWritable implements WritableComparable<PaiWritable> { private int id; private String name; public PaiWritable(){ } public PaiWritable(int id, String name){ this.set(id, name); } private void set(int id, String name) { this.setId(id); this.setName(name); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PaiWritable that = (PaiWritable) o; return id == that.id && name.equals(that.name); } @Override public int hashCode() { return Objects.hash(id, name); } @Override public String toString() { return id + "\t" + name; } @Override public void write(DataOutput out) throws IOException { out.writeInt(id); out.writeUTF(name); } @Override public void readFields(DataInput in) throws IOException { //顺序相同 this.id = in.readInt(); this.name = in.readUTF(); } @Override public int compareTo(PaiWritable o) { // compare id int comp = Integer.valueOf(this.getId()).compareTo(Integer.valueOf(o.getId())); // if(0 != comp){ return comp; } // compare name return this.getName().compareTo(o.getName()); } }
5.6.4 MapReduce 编程模版优化 sqoop
- Mapper 类中的方法
- setup(Context) : 初始化准备工作(例如连接数据、验证等),在对<key, value>进行处理之前,需要将 <key, value> 进行初始化工作
- cleanup(Context): 程序运行完了之后,需要对资源进行清理
- 可以使用的工具 sqoop
- SQ L + to + Had oop
- 将关系型数据库中的数据导入到HDFS文件系统中,然后对其进行存储、处理和计算
package com.zhang.mapreduce;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.util.StringTokenizer;
public class modelMapReduce {
//step 1: map class
//public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
// TODO
public static class modelMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
@Override
public void setup(Context context) throws IOException, InterruptedException {
super.setup(context);
//nothing
}
@Override
public void cleanup(Context context) throws IOException, InterruptedException {
super.cleanup(context);
//nothing
}
//TODO
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//TODO
}
}
//step 2: reduce class
public static class modelReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
//TODO
@Override
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//TODO
}
//step 3: driver, component job
public int run(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 1: get configuration
Configuration configuration = new Configuration();
// 2: create job
Job job = Job.getInstance(configuration, this.getClass().getSimpleName());
// 3: run jar
job.setJarByClass(this.getClass());
// 4: set job
// input --> map --> reduce --> output
// 4.1: input
// TODO
Path inPath = new Path(args[0]);
FileInputFormat.addInputPath(job, inPath);
// 4.2: map
// TODO
job.setMapperClass(modelMapper.class);
//4.3: reduce
// TODO
job.setReducerClass(modelReducer.class);
// 4.4 output
Path outPath = new Path(args[1]);
FileOutputFormat.setOutputPath(job, outPath);
// 5: submit job
// 打印日志信息
boolean isSucess = job.waitForCompletion(true);
return isSucess ? 0 : 1;
}
// step 4: run program
public static void main(String[] args) throws InterruptedException, IOException, ClassNotFoundException {
// TODO
}
}
}
5.7 shuffle 概念
5.7.1 mapreduce运行过程
-
step 1
- input
- InputFormat
- 读取数据
- 将数据格式化为<key, value> 格式
- FIleInputFormat
- TextInputFormat : 文本、字符串、普通的日志文件,按行变成<key, value>
- InputFormat
- input
-
step 2
- map
- ModuleMapper
- map(KEYIN, VALUE, KEYOUT, VALUEOUT)
- 默认情况下
- KEYIN:LongWritable 偏移量
- VALUEIN:TEXT
- ModuleMapper
- map
-
Step 3(partition、sort、copy(拷贝,用户无法干涉)、group、compress(可设置,属于配置文件)、combiner(可设置,合并,类似于reduce的作用,通常称为 map task 端的 reduce,可直接采用方法的方式进行设置 set))
-
shuffle
-
Process(过程)
-
Map, output<key, value>
- 输出一开始存放在内存中(memory)
- 当达到内存的最大存储后,将会溢写到磁盘当中(spill),可能会有很多个文件
- 在spill过程当中有两个操作
- 分区:parttition 分区数和reduce数是一样的
- 排序:sort
-
当输出完毕之后,磁盘上有很多的小文件,spill
-
将文件进行合并 merge
-
排序 sort
-
合并成一个大文件,这个大文件是经过分区了,也经过排序了的
-
大文件 --> Map Task 运行的机器的本地磁盘
------------------------------- 到这里,map对数据的处理才算结束-------------------------------
-
-
Copy
-
Reduce Task, 会到 map task 运行到机器上,拷贝要处理的数据
-
合并 meige,需要进行排序
-
分组 group: 将相同key 的value放在一起,可以一下子减少很多的 <key, value>
------------------------------- 到这里,shuffle 处理过程 -------------------------------
-
-
-
-
-
Step 4
- reduce
- reduce(KEYIN, VALUE, KEYOUT, VALUEOUT)
- Map 输出<key,value> 数据类型与reduce输入<key, value>类型一致
- reduce(KEYIN, VALUE, KEYOUT, VALUEOUT)
- reduce
-
step
- output
- OutputFormat
- FileoutputFormat
- TextoutFormat
- 每个<key, value>对,输出一行,key与value中间分隔符号为 Tab键("\t"),默认调用 key 和 value 的 toString() 方法
- output
5.7.2 shuffle 过程 画图
5.7.3 设置压缩
// 1. get configuration
Configuration configuration = new Configuration();
// 设置压缩
configuration.set("mapreduce.map.output.compress", "true");
configuration.set("mapreduce.map.output.codec", "org.apache.hadoop.io.compress.SnappyCodec");
5.8 mapreduce 调优
5.8.1 Reduce Task Number 非常关键 在Hive调优中,需要进行评估
-
默认情况下,Reduce任务只有一个
-
对应的属性(设置默认的reduce个数):mapreduce.job.reduces
-
在程序中设置Reduce个数
job.setNumberReduceTask(1)
5.8.2 Map Task 输出压缩
- map的任务数我们控制不了;
- 默认情况下,一个块对应一个map进行处理
5.8.3 Shuffle Phase 参数
<property>
<name>mapreduce.map.cpu.vcores</name>
<value>1</value>
<description>
The number of virtual cores
</description>
</property>
<property>
<name>mapreduce.reduce.cpu.vcores</name>
<value>1</value>
<description>
The number of virtual cores required for each reduce task
</description>
</property>
<property>
<name>mapreduce.task.io.start.factor</name>
<value>10</value>
<description>
The number of stream to merge at once while sorting files. This determines the number of open file handles.
</description>
</property>
<property>
<name>mapreduce.task.io.sort.mb</name>
<value>100</value>
<description>
The total amount of buffer memory to use while sorting files, in megabytes. By default, gives each merge stream 1 MB, which should minimize seeks
</description>
</property>
<property>
<name>mapreduce.map.sort.spill.percent</name>
<value>0.80</value>
<description>
The soft limit in the serialization buffer. Once reached, a thread will begin to spill the contents to disk in the background.
Note that collection will not block if this threshold is exceeded while a spill is already in progress, so spills may be larger
than this threshold when ti is set to less than 5.
</description>
</property>
六、分布式部署Hadoop2.x
6.1 Hadoop 2.x 部署
- 本地模式 Local Mode
- 分布式 Distributed Mode
- 伪分布式
- 一台机器,运行所有的守护进程
- 从节点DataNode、NodeManager只有一台
- 完全分布式
- 有多个从节点
- DataNodes
- NodeManagers
- 配置文件
- $HADOOP_HOME/etc/hadoop/slaves
- 有多个从节点
- 伪分布式
6.1.2 部署完全分布式
- 基于伪分布式环境进行展开
- 规划机器与服务
- HDFS文件系统
- YARN云操作系统
- JobHistoryServer历史服务监控
- 修改配置文件,设置服务运行机器节点
- 分发HADOOP安装包至各个机器节点
- 依据官方汲取安装文档,分别启动各个节点相应服务
- 测试HDFS、YARN、MApReduce,Web UI 集群
- 配置主节点至各从节点SSH无密钥登录
- 集群基准测试(实际环境中必须的)-----面试题
6.1.3 集群搭建完成以后
6.1.3.1 基本测试
-
服务启动,是否可用,简单的应用
-
hdfs
-
读写操作
bin/hdfs dfs -mkdir -p /user/zhang/data/tmp/conf bin/hdfs dfs -put /etc/hadoop/*-site.xml /user/zhang/data/tmp/conf bin/hdfs dfs -text /user/zhang/data/tmp/conf/core-site.xml
-
-
yarn
run jar -
mapreduce
bin/yarn jar share/hadop/mapreduce/hadoop*example*.jar wordcount /user/zhang/data/tmp/conf/core-site.xml /user/zhang/data/tmp/wcoutput
-
6.1.3.2 基准测试 测试集群的性能
- hdfs
- 写数据
- 读数据
6.1.3.3 监控集群 Cloudera Manager
- 部署安装集群
- 监控集群
- 配置同步集群
- 预警。。。
6.1.3.4 集群的时间要同步(内网时间同步) ntp
-
找一台机器作为时间服务器
-
所有的机器与这台机器时间进行定时的同步
-
步骤
-
rpm -qa|grep ntp 检查是否安装
-
vim /etc/ntp.con
# undisciplined Local Clock. This is a fake driver interded for backup # and when no outside source of synchronized time is avaiable server 127.127.1.0 # local clock fudge 127.127.1.0 stratum 10 -
-
Vim /etc/sysconfig/ntpd
# 添加这一行 SYNC_HWCLOCK=yes -
启动 ntp 服务 (注意:启动之后,必须经过10分钟才能进行同步,手动同步也一样)
service ntpd status service ntpd start chkconfig ntpd on # 设置 ntpd 自动启动 -
在需要同步的机器上写定时任务脚本进行同步 corntab -e,手动同步可以直接输入下面 /usr/sbin/ntpdate hadoop00 进行同步
0-59/10 * * * * /usr/sbin/ntpdate hadoop00
6.2 ZooKeeper
6.2.1 What is ZooKeeper? 并发 服务器的节点一般是奇数个
-
一个开源的分布式的,为分布式应用提供协调服务的Apache项目
-
提供一个简单的原语集合,以便于分布式应用可以在它之上构建更高层次的同步服务
-
设计非常易于编程,使用java语言编写,它使用的是类似于文件系统那样的树形数据结构
-
目的就是将分布式服务不再需要由于协作冲突而另外实现协作服务
-
ZooKeeper、HBase都来自于Google
-
服务架构图
6.2.2 ZooKeeper 数据结构
-
数据结构和分等级的命名空间
-
ZooKeeper 的命名空间的结构和文件系统很像。一个名字和一个文件一样使用 / 的路径表现,zookeeper的每个节点都是被路径唯一标识
-
ZooKeeper's Hierarchical Namespace
-
6.2.3 ZooKeeper 角色
- Follower 也可以叫做 Observer
6.2.4 ZooKeeper 典型应用场景 基于观察者模式
-
ZooKeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,ZooKeeper 就将负责通知已经在ZooKeeper上注册的那些观察者做出相应的反应,从而实现集群中类似Master/Slave管理模式
-
应用场景
- 统一命名服务(Name Service)
- 配置管理 (Configuration Management)
- 集群管理 (Group Membership)
- 共享锁 (Locks)/同步锁
6.2.5 ZooKeeper 单机模式安装
-
安装JDK、配置环境变量、验证Java-version
-
下载、赋执行权限、解压
- 下载地址:http://apache.datagurn.cn/zookeeper/
- 权限:chmod u+x zookeeper-3.4.5.tar.gz
- 解压:tar -zxvf zookeeper-3.4.5.tar.gz -C /opt/modules/
-
配置
- 复制配置文件:cp conf/zoo_sample.cfg conf/zoo.cfg
- 配置数据存储目录:dataDir=/opt/modules/zookeeper-3.4.5/data
- 创建数据存储目录:mkdir /opt/modules/zookeeper-3.4.5/data
-
启动
-
启动:bin/zkServer.sh start
-
-
检测
-
查看状态:bin/zkServer.sh status
-
Client Shell : bin/zkCli.sh
-
创建一个目录: create /test "test-data" 或取数据等
-
6.2.6 ZooKeeper 配置参数详解
- tickTime:这个时间作为Zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳
- dataDir:顾名思义就是Zookeeper保存数据等目录,默认情况下,Zookeeper将写数据等日志文件也保存在这个目录里
- clientPort:这个端口就是客户端连接Zookeeper服务器的端口,Zookeeper会监听这个端口,接受客户端的访问请求
- initLimit:这个配置项是用来配置Zookeeper接受客户端(这里所说的客户端不是用户连接Zookeeper服务器的客户端,而是Zookeeper服务集群中连接到Leader的Follower服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过10个心跳的时间(也就是tickTime)长度后Zookeeper服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是5*2000=10秒
- syncLimit:这个配置项标识Leader与Follower之间发送消息,请求和应答时间长度,最长不能超过多少个tickTime的时间长度,总的时间长度就是2*2000=4秒
- Server_A=B:C:D :
- A:是一个数字,表示这个是第几号服务器;
- B:是这个服务器的ip地址,也可以是主机名
- C:表示是这个服务器与集群中的Leader服务器交换信息的端口
- D:表示的是万一集群中的Leader服务器挂了,需要一个端口来进行重新选择,选出一个心的Leader,而这个端口就是用来执行选举时服务器相互通信的端口
- 如果是伪集群的配置方式,由于B都是一样的,所以不同的Zookeeper实例通信端口不能一样,所以要给它们分配不同的端口号
- 集群模式下配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面就只有一个数据,就是 A 的值,Zookeeper启动时读取次文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是哪个server。
- Zookeeper Client命令详解
- 命令:bin/zkCli.sh -server localhost:2181
- 详解:ls、get、create、delete、set
6.2.7 Zookeeper 集群
-
配置
-
复制配置文件:cp conf/zoo_sample.cfg conf/zoo.cfg
-
在zoo.cfg中配置数据存储目录:dataDir=/opt/modules/zookeeper-3.4.5/data
-
在zoo.cfg中添加如下配置
dataDir=/opt/modules/zookeeper-3.4.5/data initLimit=5 syncLimit=2 ##############################针对集群######################### server.1=hadoop00:2888:3888 server.2=hadoop01:2888:3888 server.3=hadoop02:2888:3888 -
创建数据存储目录:mkdir /opt/modules/zookeeper-3.4.5/data
-
在 /opt/modules/zookeeper-3.4.5/data 下 创建 myid 文件,并填入 1(身份标识)
-
分发 scp 到每台机器上,同时修改每台机器上的myid文件,修改为该机器的身份标识,不同机器不一样
-
6.3 HDFS HA 架构部署测试
6.3.1 HDFS 高可用性背景
HDFS:分布式存储
-
NameNode:存储元数据的
- 文件名称
- 路径
- 所属者(拥有者)
- 所属组
- 权限
- 副本数...
-
DataNode:存储具体数据的
-
以 Block(128M)方式进行存储的
-
存储在本地磁盘,路径可以自定义,由 dfs.datanode.data.dir 属性进行指定和配置
<property> <name>dfs.datanode.data.dir</name> <value>file://${hadoop.tmp.dir}/dfs/data</value> </property> -
Client
- --> NameNode ---> put
-
-
在hadoop 2.x
- hadoop 2.2.0 发布了 HDFS HA(高可用性)
- NameNode Active
- NameNode Standby
- hadoop 2.2.0 发布了 HDFS HA(高可用性)
-
背景简介
- Hadoop 2.0。之前,在HDFS集群中NameNode存在单点故障(SPOF)。对于只有一个NameNode的集群,若NameNode机器出现故障,则整个集群将无法使用,直到NameNode重新启动。
- NameNode主要在以下两个方面影响HDFS集群
- NameNode机器发生意外,如宕机,集群将无法使用,直到管理员重启
- NameNode机器需要升级,包括软件、硬件升级,此时集群也将无法使用
- HDFS HA 功能通过配置 Active/Standby 两个 NameNode 实现在集群中对NameNode的热备,这时可以通过此种方式将NameNode很快的切换到另外一台机器。
- 热备:快速接手所有工作
- 冷备
6.3.2 HDFS HA 设计
-
HDFS
- edits 变化
-
NameNode Active
-
NameNode Standby:需要知道所有的DataNodes和block报告
-
两个问题
-
怎么保证两个NameNode内存里面元数据文件一致?
-
怎么保证编辑日志文件的可靠性?
-
两个问题解决方式:Zookeeper 日志节点(奇数个节点)
- 只要有两个日志节点的日志写入成功,则表示当前的编辑日志文件是可靠的
-
6.3.3 配置 HDFS HA
6.3.3.1 配置要点
- edits:现在已经交给JournalNode管理了,共享edites。多了守护进程 JournalNode(一般是奇数个)
- NameNode:以前只需要一个NameNode,现在需要配置两个
- Client:客户端访问方式通过Proxy(可以判断两个NameNode的状态)进行重定向访问,且Client同时只能访问一个NameNode
- 两个NameNode需要进行隔离(fence):同一时刻,仅仅有一个NameNode对外提供服务。当一个是active时,其余的必须是Standby。
- 有了HA之后,就不需要Secondary NameNode(合并文件,在下一次启动会更快)了
6.3.3.2 具体配置步骤
-
规划集群
00 01 02 NameNode NameNode JournalNode JournalNode JournalNode DataNode DataNode DataNode
6.3.3.3 QJM HA 启动
-
在各个JournalNode节点上,输入以下命令启动journalnode服务
$ sbin/hadoop-daemon.sh start journalnode -
在[nn1]上,对其进行格式,并启动
bin/hdfs namenode -format sbin/hadoop-daemon.sh start namenode -
在[nn2]上,同步nn1的元数据信息
bin/hdfs namenode -bootstrapStandby -
启动[nn2]
sbin/hadoop-daemon.sh start namenode -
将[nn1]切换为Acitve,可以和第6步更换顺序
bin/hdfs haadmin -transitionToActive nn1 # 高可用管理命令 -
在[nn1]上,启动所有datanode
sbin/hadoop-daemon.sh start datanode
6.4 Zookeeper 配置 NN HA 自动故障转移(Failover)
6.4.1 问题
- 最开始启动以后,都是Standby,我们需要选举一个为Active
- 监控:ZKFC(FailvoerController)故障转移控制器,每一个namenode都需要加一个 ZKFC 来监控状态
- 集群规划
| 00 | 01 | 02 |
|---|---|---|
| NameNode | NameNode | |
| JournalNode | JournalNode | JournalNode |
| DataNode | DataNode | DataNode |
| ZKFC | ZKFC | ZKFC |
-
在 hdfs-site.xml 中添加配置
<property> <name>dfs.ha.automatic-failover.enabled</name> <value>true</value> </property> -
在 core-site.xml 中添加配置
<property> <name>ha.zookeeper.quorum</name> <value>zkl.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value> </property>
6.4.2 启动故障自动转移
- 启动
- 关闭所有HDFS服务:sbin/stop-dfs.sh
- 启动Zookeeper集群:bin/zkServer.sh start
- 初始化 HA 在 Zookeeper 中状态:bin/hdfs zkfc -formatZK
- 启动 HDFS 服务:sbin/start-dfs.sh
- 在各个NameNode节点上启动DFSZK Failover Controller,先在哪台机器上启动,哪台机器的NameNode就是Active NameNode:sbin/hadoop-daemon.sh start zkfc
- 验证
- 将Active NameNode进程kill,命令:kill -9 pid
- 将Active NameNode机器断开网路,命令:service network stop
- 注意
- zookeeper自动选举主节点(active)
- 如果zookeeper集群挂了,对整个集群的运行没有什么影响,只是不能再进行自动故障转移了
- zookeeper集群对于被管理集群的时间同步要求非常高
- zookeeperFC是zookeeper的一个客户端
6.5 NameNode 管理命令
- bin/hdfs namenode
- [-backup]
- [-checkpoint]
- [-importCheckpoint]
- [-format] [-clusterid cid] [-nonInteractive]
- [-upgrade]
- [-rollback]
- [-finalize]
- [-initializeSharedEdits]
- [-bootstrapStandby]
- [-recover [-force]]
- bin/hdfs haadmin
6.6 HDFS Using QJM
- QJM:分布式日志管理
6.7 Federation 2.x
6.7.1 单 NameNode 架构的局限性
-
Namespace(命名空间)的限制
由于NameNode在内存中存储所有的元数据(metadata),因此单个NameNode所能存储的对象(文件+块)数据收到NameNode所在JVM的heap size的限制。50G的heap能够存储20亿(200million)个对象,这20亿个对象支持4000个datanode,12PB的存储(假设文件平均大小为40MB)。随着数据的飞速增长,存储的需求也随之增长。单个datanode从4T增长到36T,集群的尺寸增长到8000个datanode。存储的需求从12PB增长到大于100PB。
-
隔离问题
由于HDFS仅有一个NameNode,无法隔离各个程序,因此HDFS上的一个实验程序就很有可能影响整个HDFS上运行的程序
-
性能的瓶颈
由于是单个NameNode的HDFS架构,因此整个HDFS文件系统的吞吐量受限于单个NameNode的吞吐量。
6.7.2 优化考虑 -- Federation -- 企业中运用得不多,大公司在使用(阿里的云容器)
-
能不能有多个NameNode,每个NameNode管理不同的任务,相互独立,且多个NameNode管理的数据存储在所有的DataNode节点上。(单独管理,共享存储)
NameNode NameNode NameNode 元数据 元数据 元数据 log machine 电商数据/话单数据(实时获取)
6.7.3 HDFS Federation 架构设计
6.7.4 HDFS Federation 应用思考
- 不同应用可以使用不同NameNode进行数据管理
- 图片业务、爬虫业务、日志审计业务
- Hadoop生态系统中,不同的框架使用不同的NameNode进行管理Namespace(隔离性)
6.8 File System Snapshots(文件系统快照)2.x
6.8.1 概述和功能
- HDFS快照是
- 一个只读的机遇时间点文件系统拷贝。
- 快照可以是整个文件系统也可以是一部分。
- 常用来作为数据备份,防止用户错误和容灾快照功能
- HDFS实现功能
- Snapshot创建的时间复杂度为O(1),但不包括INode的寻找时间
- 只有当修改SnapShot时,才会有额外的内存占用,内存使用量为O(M),M为修改的文件或者目录数
- 在DataNode上面的blocks不会复制,做Snapshot的文件时记录了block的列表和文件的大小,但是没有数据的复制
- Snapshot并不会影响HDFS的正常操作:修改会按照时间的反序记录,这样可以直接读取到最新的数据。快照数据是当前数据减去修改的部分计算出来的。
6.8.2 常用命令
-
设置一个目录为可快照:
bin/hdfs dfsadmin -allowSnapshot <paht> -
取消目录可快照
bin/hdfs dfsadmin -disableSnapshot <path> -
生成快照
bin/hdfs dfs -createSanpshot <path> [<snapshotName>] -
删除快照
bin/hdfs dfs -deleteSnapshot <path> <snapshotName> -
列出所有可快照目录
bin/hdfs lsSnapshottableDir -
比较快照之间的差异
bin/hdfs snapshotDiff <path> <formSnapshot> <toSnapshot>
6.9 集中式缓存管理 2.4.x 用得还是特别的广
6.9.1 概述
Hadoop从2.3.0版本开始支持HDFS缓存机制,HDFS允许用户将一部分目录或文件缓存在HDFS当中,NameNode会通知拥有对应块的DataNodes将其缓存在DataNode的内存当中
6.9.2 优势
- 防止那些被频繁使用的数据从内存中清除
- 因为DataNode的缓存由NameNode来管理,applications在做任务安排时可以查询这个缓存的列表,使用一个被缓存的块副本能够提高读性能
- 当块被dataNode缓存之后,客户端可以使用一个新的、高效的、zero-copy的读API,因为缓存中的数据已经被计算过checksum,当使用新API时,客户端基本上是零开销的
- 可以提高集群的内存利用率。当使用操作系统缓存时,对一个块的重复读会导致所有的副本都会被放到缓存区当中;当使用集中式缓存时,用户可以指定n个副本中的m个才会被缓存,可以节约n-m的内存
6.9.3 使用场景
- 集中是缓存对那些频繁访问的文件是非常有用的。例如Hive中经常被使用的fact表就非常适合缓存
- 另一方便,缓存一年的查询结果可能没有那么有用了,因为这个结果可能只会被查看一次
- 有助于提高混合类型作业的SLA性能,把高优先级的数据缓存起来可以确保它不会与低优先级的数据竞争磁盘IO
6.9.4 cacheadmin connand-line interface
6.10 Distributed Cpoy(DistCp) 分布式拷贝
在实际的生产环境中,会同时具备测试集群和生产集群,同时,在一些企业中还会同时存在多个版本的Haoop大数据集群,分布式拷贝就用于集群之间的资源迁移。
6.11 不同版本haoop集群之间的资源迁移 HFTP协议
相同版本的Hadoop集群之间,可以直接使用分布式拷贝方式进行迁移,但是如果Hadoop版本不同,则不能直接使用分布式拷贝的方式进行迁移,需要使用HFTP协议进行迁移
hadoop distcp -i hftp://sourceFS:8020/src hdfs://destFS:8020/dest # -i:表示覆盖
底层实现:mapreduce
6.12 YARN HA hadoop 2.5.x ResourceManaager High Availability / ResourceManager Restart
-
ResourceManager 存在单节点故障(SPOF)
- 管理集群资源
- 分配调度集群资源
-
NodeManagers
-
目前:
- 测试环境HDFS做了HA的 ---- 数据是最重要的
- 生产环境:ResourceManger做了HA的
七、Hadoop 版本比较&应用案例
7.1 基于HDFS云盘存储系统 -- 分析百度网盘
-
使用HDFS作为云盘底层的优势(HDFS的设计目标)
- 普通的商用机器:内存大、磁盘大且便宜
- 数据的安全性:默认的副本数是三份,保证了数据的安全性
- 一次存储,多次读取
-
具体操作
- put,get
- rm [-R]
- mv
- 极速上传:本身并没有上传数据(根本没有传文件)
- 对于每个文件,都会生成一个码(hashcode),上传的时候,会先扫描自己的库里面有没有对应的文件,如果有,则直接在前端显示一个图标,且指向对应的文件链接;如果扫描自己的库里面没有对应的文件,则直接上传文件
- 云盘前端显示的文件列表(表)存放位置:不同的公司不一样,可以存入到HBase中
-
JAVA API --- FileSystem
-
核心:HDFS集群
- HDFS HA
7.2 Hadoop 三大发行版本
-
apache 版本 ADP
- 在企业实际使用当中,并不多
- 最原始(最基础)的版本
-
cloudera 版本 CDP -- 专门对hadoop进行封装发行的公司 -- flume(收集数据),hue(图形化界面管理),impala(内存数据分析)
- 2008年成立的Cloudera 是最早将Hadoop商用的公司,为合作伙伴提供Hadoop的商用解决方案,主要包括支持、咨询服务、培训
- 2009年Hadoop的创始人Doug Cutting也加盟Cloudera公司。Cloudera产品主要为CDH、Cloundera Manager、Cloudera Support
- CDH 是Cloudera 的 Hadoop 发行版本,完全开源,比Apache Hadoop在兼容性、安全性、稳定性上有所增强
- Cloudera Manager 是集群的软件分发及管理监控平台,可以在几个小时内部署好一个Hadoop集群,并对集群节点及服务进行实时监控。Cloudera Support 即是对Hadoop的技术支持
- Cloudera 的标价为每年每个节点4000美元。Cloudera 开发并贡献了可实时处理大数据的Impala项目
-
Hortonworks Hadoop HDP
- 2011年成立的 Hortonworks 是雅虎与硅谷风投公司Benchmark Capital 合资组建
- 公司成立之初就吸纳了大约25名到30名专门研究Hadoop的雅虎工程师,上述工程师均在2005年开始协助雅虎开发Hadoop,贡献了Hadoop 80%的代码
- 雅虎工程副总裁、雅虎Hadoop开发团队负责人Eric Baldeschwieler出任Hortonworks的CEO
- Hortonworks 的主打产品是 Hortonworks Data Platform(HDP),也同样是 100%开源的产品,HDP除常见的项目外还包含了Ambari,一款开源的安装和管理系统
- HCatalog,一个元数据管理系统,HCatalog现已集成到Facebook开源的Hive中。Hortonworks的Stinger开创性地极大优化了Hive项目。Hortonworks为入门提供了一个非常好的易于使用的沙盒
- Hortonworks开发了很多增强特性并提交至核心主干,这是的Apache Hadoop 能够包括 Windows Server 和 Windows Azure 在内的 Microsoft Windows平台上本地运行。定价以集群为基础,每10个节点每年为12500美元
-
版本选择
7.3 项目实战 北风网站日志分析
7.3.1 第一步:收集数据--样本数据(文件)
-
每一行就是一条数据,用户访问的一条记录
-
各个字段的含义
-
应用系统web前端服务器,使用什么记录日志
-
字段名称以及含义
-
-
本项目的日志格式 log_format main
["$remote_addr" "$remote_user" "$time_local" "$request" ] ["$status" "$body_bytes_sent" "request_body" "$http_referer" ] ["$http_user_agent" "$http_x_forwarded_for" "$host" ]
7.3.2 第二步:数据处理--原始数据清洗 (常用mapreduce) -- 数据质量
每天的日志大小为10G,数据量至少30-50G大小)
最害怕的一件事情:
- 数据全部符合我们的要求 --- 理想
- 部分数据会有问题 --- 实际
- *往往数据的不合格导致应用程序出问题(考虑不全),空指针异常
7.3.3 第三步:依据需求
-
需求一:【$remote_addr】
客户端的 ip 地址(如果中间有代理服务器那么这里显示的 ip 就为代理服务器的 ip 地址)
-
业务
- 依据 ip 地址确定区域,定向营销,【 IP地址 ----> 地域 】
211.61.0.0 -- 211.71.255.255 中国 211.123.0.0 -- 211.255.255.255 中国 210.25.0.0 -- 210.47.255.255 中国 - 用户统计,访问某一网站数
- 准确性(同一外网,不同内网)
-
-
需求二:【$time_local】
用于记录访问时间和时区
- 业务
- 分析用户访问网站的时间段
- 针对销售来说,合理安排值班,销售课程
- 业务
-
需求三:【$request】
用于记录请求的url以及请求方法
- 业务
- 用户最关注的网站 --> 课程
- 定向投放此套课程,做好相关课程
- 实时输入建议
- 思路
- 分析搜索关键字 url
- 拆分关键字
- h --> 花千骨
- Hbas --> Hbase
- 思路
- 业务
-
需求四:【$http_refer】
可以记录用户从哪个链接访问过来的
- 业务
- 关注用户如何访问我们的课程,定向某个区域,进行广告投放
- 业务
数据分析过程
-
收集数据
- 程序
- put hdfs
- 定时程序,如QUARTZ
- flume
- shell 脚本
- 程序
-
处理数据
- 数据预处理
- 核心:数据质量
- 数据清洗、过滤、剔除「脏数据」
- mapreduce
- hive
- 原表 ---> 业务表:使用HQL语句,python脚本,udf
- 处理数据
- mapreduce
- 时间格式 2015-09-12T17:23:45
- Hive
- 特殊处理特殊字段
- $time_local:转换为Long类型数字,或者符合楼阁格式
- $request:提取出请求URL
- $http_referer:上一个连接,计算网页中的「二级跳转」
- mapreduce
- 数据预处理
-
展示数据 (需要对结果集,进行处理,数据格式(json,导入到RDBMS))
- 报表工具,进行展示
- DAAS 数据即服务

浙公网安备 33010602011771号