HADOOP是apache旗下的一套开源软件平台HADOOP提供利用服务器集群,根据用户的自定义业务逻辑,对海量数据进行分布式处理,HADOOP的核心组件有:HDFS(分布式文件系统)、YARN(运算资源调度系统)、MAPREDUCE(分布式运算编程框架),广义上来说,HADOOP通常是指一个更广泛的概念——HADOOP生态圈
HADOOP最早起源于Nutch。Nutch的设计目标是构建一个大型的全网搜索引擎,包括网页抓取、索引、查询等功能,但随着抓取网页数量的增加,遇到了严重的可扩展性问题——如何解决数十亿网页的存储和索引问题。2003年、2004年谷歌发表的两篇论文为该问题提供了可行的解决方案。——分布式文件系统(GFS),可用于处理海量网页的存储——分布式计算框架MAPREDUCE,可用于处理海量网页的索引计算问题。Nutch的开发人员完成了相应的开源实现HDFS和MAPREDUCE,并从Nutch中剥离成为独立项目HADOOP,到2008年1月,HADOOP成为Apache顶级项目,迎来了它的快速发展期。
注:由于大数据技术领域的各类技术框架基本上都是分布式系统,因此,理解hadoop、storm、spark等技术框架,都需要具备基本的分布式系统概念
分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据 。分布式系统的特点是:硬件独立,各设备之间独立,互不依赖、 软件统一,对用户来说,就像是跟单个系统打交道。
为了性能扩展:系统负载高,单台机器无法承受,希望通过多台机器来提高系统负载能力 为了增强可靠性:软件不是完美的,网络不是完美的,甚至机器也不是完美的,随时可能出错,为了避免故障,需要将业务分散开保留一定的冗余度
该软件系统会划分成多个子系统或模块,各自运行在不同的机器上,子系统或模块之间通过网络通信进行协作,实现最终的整体功能
比如分布式操作系统、分布式程序设计语言及其编译(解释)系统、分布式文件系统和分布式数据库系统等。
“Web点击流日志”包含着网站运营很重要的信息,通过日志分析,我们可以知道网站的访问量,哪个网页访问人数最多,哪个网页最有价值,广告转化率、访客的来源信息,访客的终端信息等。
HADOOP集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起HDFS集群:负责海量数据的存储,集群中的角色主要有 NameNode / DataNode YARN集群:负责海量数据运算时的资源调度,集群中的角色主要有 ResourceManager / NodeManager (那mapreduce是什么呢?它其实是一个应用程序开发包)
服务器分配
本集群搭建案例,以5节点为例进行搭建,角色分配如下:
节点 | 进程 |
---|---|
node-1 | NameNode ResourceManager |
node-2 | SecondaryNameNode |
node-3 | DataNode NodeManager |
node-4 | DataNode NodeManager |
node-5 | DataNode NodeManager |
配置系统网络,安装常用依赖包如文件上传、编辑器、网络工具
同步时间、配置各主机名称映射、配置ssh免密登陆
安装java环境
# 下载
$ wget https://mirrors.shu.edu.cn/apache/hadoop/common/hadoop-2.7.7/hadoop-2.7.7.tar.gz
# 解压缩
$ tar -zxvf hadoop-2.7.7/hadoop-2.7.7.tar.gz
# 修改系统环境变量
$ vi /etc/profile
export HADOOP_HOME=/export/servers/hadoop2.7.7
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# 配置环境变量
$ vi hadoop-env.sh
export JAVA_HOME=/usr/local/jdk1.8.0_191
# core-site.xml配置如下
$ vi core-site.xml
fs.defaultFS
hdfs://node-1:9000
hadoop.tmp.dir
/export/data/hadoop/tmp
# hdfs-site.xml配置如下
$ vi hdfs-site.xml
dfs.namenode.name.dir
/export/data/hadoop/name
dfs.datanode.data.dir
/export/data/hadoop/data
dfs.replication
3
dfs.secondary.http.address
node-2:50090
# mapred-site.xml配置如下
$ vi mapred-site.xml
mapreduce.framework.name
yarn
# yarn-site.xml配置如下
$ vi yarn-site.xml
yarn.resourcemanager.hostname
node-1
yarn.nodemanager.aux-services
mapreduce_shuffle
# 修改 slaves 配置
$ vim salves
node-3
node-4
node-5
# 初始化HDFS
$ hadoop namenode -format
# 启动HDFS
$ $HADOOP_HOME/sbin/start-dfs.sh
# 启动yarn
$ $HADOOP_HOME/sbin/start-yarn.sh
# 启动hdfs和yarn
$ $HADOOP_HOME/sbin/start-all.sh
# hadoop常用命令
# 查看hadoop版本
$ hadoop verion
# 运行jar文件
$ hadoop jar
# 创建文件夹
$ hadoop fs -mkdir -p /data/input
# 递归查看文件夹
$ hadoop fs -ls -R /data/input
# 上传本地文件到HDFS
$ hadoop fs -put /root/words.txt /data/input
# 查看HDFS上的文件
$ hadoop fs -cat /data/input/words.txt
# 删除HDFS上的文件
$ hadoop fs -rm -f /data/input/words.txt
使用hadoop自带的例子程序,运行一个示例mr程序
$ hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount /data/input /data/output
可打开web控制台查看 HDFS 和 yarn 集群信息 hdfs 的 web 页面是 http://node-1:50070/ yarn 集群信息的 web 页面是http://node-1:8088/
mapreduce是hadoop中的分布式运算编程框架,只要按照其编程规范,只需要编写少量的业务逻辑代码即可实现一个强大的海量数据并发处理程序
设计思想
在大数据系统中作用:
重点概念
首先,它是一个文件系统,用于存储文件,通过统一的命名空间——目录树来定位文件
其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色
重要特性如下
HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M
HDFS文件系统会给客户端提供一个统一的抽象目录树,客户端通过路径来访问文件,形如:hdfs://host:port/xxx/xxx/file.data
目录结构及文件分块信息(元数据)的管理由namenode节点承担namenode是HDFS集群主节点,负责维护整个hdfs文件系统的目录树,以及每一个路径(文件)所对应的block块信息(block的id,及所在的datanode服务器)
文件的各个 block 的存储管理由datanode节点承担 datanode 是HDFS集群从节点,每一 个block 都可以在多个 datanode 上存储多个副本(副本数量也可以通过参数设置dfs.replication)
HDFS是设计成适应一次写入,多次读出的场景,且不支持文件的修改
(注:适合用来做数据分析,并不适合用来做网盘应用,因为,不便修改,延迟大,网络开销大,成本太高)
dfs == hadoop fs
# 在hdfs上创建目录
$ dfs -mkdir /xxx
# 显示目录信息
$ dfs -ls -r /xxx
# 递归查看HDFS目录文件
$ dfs -lsr /xxx
# 等同于copyFromLocal
$ dfs -put a.html /xxx
# 等同于copyToLocal,就是从hdfs下载文件到本地
$ dfs -get /xxx/a.html
# 删除文件夹下所有文件
$ dfs -rm -r -f /data
# 显示文件内容
$ dfs -cat /xxx/a.txt
# 从本地剪切粘贴到hdfs
$ dfs -moveFromLocal
# 从hdfs剪切粘贴到本地
$ dfs -moveToLocal
# 追加一个文件到已经存在的文件末尾
$ dfs -appendToFile
# 显示一个文件的末尾
$ dfs -tail
# 从hdfs的一个路径拷贝hdfs的另一个路径
$ dfs -cp
# 从hdfs的一个路径拷贝hdfs的另一个路径
$ dfs -mv
# 删除文件或文件夹
$ dfs -rm
概述
HDFS上传文件的步骤
客户端要向HDFS写数据,首先要跟namenode通信以确认可以写文件并获得接收文件block的datanode,然后,客户端按顺序将文件逐个block传递给相应datanode,并由接收到block的datanode负责向其他datanode复制block的副本
HDFS 读数据流程
客户端将要读取的文件路径发送给namenode,namenode获取文件的元信息(主要是block的存放位置信息)返回给客户端,客户端根据返回的信息找到相应datanode逐个获取文件的block并在客户端本地进行数据追加合并从而获得整个文件
负责客户端请求的响应,元数据的管理(查询,修改)
namenode对数据的管理采用了三种存储形式:
1.内存元数据(NameSystem)
2.磁盘元数据镜像文件
3.数据操作日志文件(可通过日志运算出元数据)
内存中有一份完整的元数据(内存meta data)
磁盘有一个“准完整”的元数据镜像(fsimage)文件在 namenode 的工作目录中
用于衔接内存metadata和持久化元数据镜像fsimage之间的操作日志 edits 文件
注:当客户端对hdfs中的文件进行新增或者修改操作,操作记录首先被记入edits日志文件中,当客户端操作成功后,相应的元数据会更新到内存meta.data中
每隔一段时间,会由secondary namenode将namenode上积累的所有edits和一个最新的fsimage下载到本地,并加载到内存进行merge(这个过程称为checkpoint)
在第一次部署好Hadoop集群的时候,我们需要在NameNode(NN)节点上格式化磁盘:
$ $HADOOP_HOME/bin/hdfs namenode -format
格式化完成之后,将会在$dfs.namenode.name.dir/current目录下如下的文件结构
current/
|-- VERSION
|-- edits_*
|-- fsimage_0000000000008547077
|-- fsimage_0000000000008547077.md5
|-- seen_txid
存储管理用户的文件块数据,定期向namenode汇报自身所持有的block信息(通过心跳信息上报,这点很重要,因为,当集群中发生某些block副本失效时,集群如何恢复block初始副本数量的问题)
dfs.blockreport.intervalMsec
3600000
datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30秒。如果定义超时时间为timeout,则超时时长的计算公式为:timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval。
而默认的heartbeat.recheck.interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。所以,举个例子,如果heartbeat.recheck.interval设置为5000(毫秒),dfs.heartbeat.interval设置为3(秒,默认),则总的超时时间为40秒。
heartbeat.recheck.interval
2000
dfs.heartbeat.interval
1
上传一个文件,观察文件的block具体的物理存放情况:
在每一台datanode机器上的这个目录中能找到文件的切块:
/export/data/hadoop/tmp/dfs/data/current/BP-193442119-192.168.2.120-1432457733977/current/finalized
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
/**
*
*
* @author leone
* @since 2018-05-06
**/
public class HdfsClientTest {
FileSystem fs = null;
/**
* 初始化
*/
@Before
public void init() throws Exception {
Configuration conf = new Configuration();
fs = FileSystem.get(new URI("hdfs://node-1:9000/"), conf, "root");
}
/**
* 上传文件
*
* @throws IOException
*/
@Test
public void putTest() throws IOException {
fs.copyFromLocalFile(new Path("file:///D:/tmp/hadoop/input1/words.txt"),
new Path("hdfs://node-1:9000/hadoop-2.7.7/input1/words.txt"));
}
/**
* 下载文件
*
* @throws Exception
* @throws IOException
*/
@Test
public void download() throws Exception, IOException {
fs.copyToLocalFile(new Path("/hadoop-2.7.7/input1/words.txt"), new Path("file:///E:/hadoop/words.txt"));
}
/**
* 创建目录
*
* @throws IllegalArgumentException
* @throws IOException
*/
@Test
public void mkdirTest() throws IllegalArgumentException, IOException {
fs.mkdirs(new Path("/test/input/"));
}
/**
* 删除文件或目录
*/
@Test
public void deleteTest() throws IOException {
fs.delete(new Path("/test"), true);
}
/**
* 移动文件
*
* @throws IllegalArgumentException
* @throws IOException
*/
@Test
public void mvFileTest() throws IllegalArgumentException, IOException {
fs.rename(new Path("/hadoop-2.7.7/input1/words.txt"), new Path("/hadoop-2.7.7/input3/words.txt"));
}
}