前言
初学hadoop,网上的相关资料很多,讲解大同小异:一堆专业术语+火星文
学习起来很困难,很难探究出它的存在意义,因此本文结合自己的理解,用地球人的语言来描述hadoop
HADOOP
hadoop解决的是海量数据的存储和计算问题,为什么会有这种问题?
因为现在是一个信息爆炸的时代,数据量大到的一台电脑硬盘存不下,且这么大的数据量在数据汇总计算时一台电脑又算不过来
hadoop怎么解决这个问题呐,就在于其提供的三大核心HDFS
,YARN
,MAPREDUCE
,其中HDFS
用来解决大文件的存储难题,YARN
用于解决大文件的计算难题,MAPREDUCE
是一种具体的计算方式
HDFS
概念
HDFS可以说是一个hadoop下独立的产品,可以单独运行
HDFS主要是用来解决大文件的存储,对应痛点是大数据文件的存储一台电脑硬盘有限存不下,先抛开HDFS,我们自己想一下解决方案
-
加硬盘,简单粗暴
-
加电脑,文件拆分存储(分布式存储)
第一种方案,最简单,一个容量很大的超级电脑,但有终归是有上限,硬盘不可能无限扩容,成本也比较高,舍弃
与其对比,第二种方案就靠谱的多,我可以用很多廉价电脑共同承担存储工作,每个电脑存储一部分,随着数据量不断增多,不断的增加电脑就可以,这就是一种分布式的存储
但实现起来真的很困难,需要做的事情有很多
- 把文件拆分成块,存入不同的电脑
- 记录每台电脑的存储位置,以便取文件
- 取文件要每台电脑取分块
- 取回所有分块后再合并恢复原文件
一次存取要同时操作多台电脑,又要进行拆分合并的操作
而HDFS的存在就是为了让文件的存取者从这繁杂的工作中解脱出来:
HDFS整合了每台电脑的资源,对外抽象出一个类似linux系统的目录结构,用户使用HDFS只需要像操作单机一样存取文件即可,HDFS内部完成文件的分块、分布式存储等功能,并且还额外提供了自动备份功能防止丢失
并且HDFS还提供了类似linux的文件操作命令:mkdir
/rm
/cd
/ls
/cat
等,俨然成了一个和linux文件系统使用基本一致的分布式文件系统
- 传统的文件系统(linux/windows),基于单机磁盘,抽象出文件夹,我们不用关心文件到底存在哪块硬盘上
- 分布式文件系统(hdfs),基于多个传统文件系统集群,抽象出文件夹,我们不用关心文件到底存在哪个电脑上
原理
HDFS是如何实现做到的呐
DataNode
首先要在集群每台机器上运行一个节点:DataNode
,实际上就是一个运行在服务器上的常驻java程序,这个DataNode
承担的主要责任很简单
- 接收上传的文件块并落盘
- 确保数据完整性(未损坏)
- 根据下载指令获取某文件块
每台机器都有一个DataNode可以承担存取的任务,但有上传任务时怎么选择,取文件有去哪几个取呐,真是三个和尚没水喝
NameNode
因此这些分布在各个机器上的DataNode
需要有一个统一的协调者、管理者、门面担当,就是NameNode
NameNode
同样是一个运行在服务器的常驻java进程,它本身不具有存取功能,但他负责管理协调所有的DataNode
(就像产品经理,可能自己不会写代码,但手下员工都会写,那么对于客户来说,产品经理就有写代码的能力)
一个NameNode
+多个DataNode
构成了master/slave集群(主从架构)
NameNode
对外抽象出一个类似linux系统的文件夹,用户存文件时,只需告知存储在哪个文件夹下,NameNode
内部会协调具体存在哪个DataNode
节点上,取文件同理,只需告知取哪个文件夹下的哪个文件即可
同时NameNode
可以提数据供备份能力,可以根据用户配置的备份数量自动选择备份的节点
Fsimage和Edits
NameNode
作为DataNode
管理者,程序内部维护了一个目录数据结构,记录了文件系统有哪些目录,每个目录有什么文件,文件被分成多少块,每一块具体存在哪个节点上
那么有个问题,这些数据存在哪里?
- 首先,为了快速响应,作为一个java程序,这些数据内存中肯定要存一份的
- 其次,为了重启后恢复数据,这些数据又一定要持久化到磁盘
所以内存和磁盘中都要有完整的最新数据,这就比较麻烦,因为我们知道磁盘IO操作性能是很差的,如果每次有文件变动,都修改磁盘数据,这会导致程序很慢
其实这种问题早就有解决方案,比如redis就常用用这种方式持久化:快照+日志
Fsimage
文件就是NameNode
在磁盘中保存的快照,存储了某一时刻的内存完整数据,但会有延迟,一般隔很长时间才快照一次,因为这个快照的磁盘IO操作很耗时
因为使用Fsimage
恢复数据肯定会损失很多新数据,所以需要配合日志文件:Edits
,日志文件就是每来一条修改数据的命令(创建文件夹或上传文件)就追加一条操作日志到Edits
文件,虽然同样是磁盘操作,但这属于顺序读写的磁盘操作,速度是很快的
重启时,只需某一时刻的快照Fsimage
+之后的Edits
文件就可以还原完整数据
同时生成新快照时也可以使用Fsimage
+Edits
生成新的快照文件,一般隔一小时生成一次
SecondaryNameNode
每隔一段时间/日志文件太大情况下,需要生成新的Fsimage快照文件,这个过程叫checkpoint
,这个活本该又管理者NameNode来做,但毕竟这个工作量比较负责又涉及磁盘IO,做这些事会耽误NameNode的效率
既然领导有更重要的活要做,这种繁琐浪费时间的活就交给秘书来做就可以,这个负责checkpoint
的秘书就是SecondaryNameNode
SecondaryNameNode
同样是一个java程序,一般运行在与NameNode不同的服务器上,她负责询问NameNode是否需要chekpoint
,得到肯定答复就开始执行checkpoint
操作,最终生成新的快照文件传给NameNode
HDFS客户端
以上讲述DataNode负责存储,NameNode负责管理DataNode并对外提供一个文件夹目录,在上传时指定负责存储的DataNode,并且记录文件存储的节点(实际上文件存储节点并没有存储,而是动态更新),在下载时告诉客户去哪里取文件
那么作为用户就需要完成其余的工作:
- 文件上传前分块
- 与NameNode沟通获取要上传/下载的DataNode节点信息
- 与指定的DataNode节点交互,完成上传/下载
- 下载后合并恢复文件
还是很麻烦,于是HDFS又提供了一个客户端,这些活它来干,客户还是只是单纯的上传下载文件即可
客户端本质就是一个写好的java代码,我们执行这个代码就可以很轻松的完成上传/下载,包括创建目录
在hadoop服务器上,我们可以通过hadoop fs
命令或者hadoop dfs
命令执行客户端上传/下载/目录操作
在本地ide中,我们可以引入hadoop-client
(包含了分块,与NameNode和DataNode交互的逻辑)依赖来用自己的代码实现客户端的上传/下载/目录操作
总结
最终HDFS示意图如下
总结一下:
HDFS是一个分布式文件系统,与我们用的windows/linux文件系统功能基本一致,只不过它的底层是把文件存储在了分布式的计算机上
YARN
概念
yarn是hadoop的另一重要组件,hdfs是解决大数据的存储问题,yarn是解决大数据的计算问题的
大数据的存储我们用多台电脑解决了,大数据的计算一样可以用这个思维:
一台电脑算不过来,多来几个电脑同时算就好了
且yarn完善了hadoop,如果只有hdfs,集群中的每台电脑只贡献了磁盘和支持NameNode、DataNode运行的少部分内存和cpu,剩余很多内存和cpu限制,我们知道程序的运行最需要的资源就是内存和CPU资源
YARN把这些分布在不同电脑的cpu和内存组织调度起来,统一对外部形成了一个庞大的可扩展的超级电脑
有了yarn提供的庞大的cpu和内存资源,我们就可以把应用程序作业的压力分布在不同计算机上,就解决了大数据的计算难题
yarn就像是一个大的操作系统,我们可以编写应用程序在yarn上运行,程序中我们可以向yarn再次申请资源并在其它电脑上执行子程序,这就好比我们java程序新建一个线程去跑子任务,只不过yarn中新建的子任务可能运行在其它电脑上
- 传统的操作系统(linux/windows),基于单机cpu和内存,我们可以开发应用程序,程序中可以创建子线程,线程具体执行在哪个cpu上我们不用关心,操作系统负责调度
- 分布式操作系统(yarn),基于多个传统操作系统集群,我们可以开发应用程序,程序中可以创建子进程,进程具体执行在哪个电脑上我们不用关心,yarn系统负责调度
Container
container的概念
container是yarn中的资源抽象,所有人都这么说,但这句话本身就够抽象了。。。
可以这么理解,container是一个进程(程序)或其子进程(子程序)运行的资源限制,运行在某个container上的进程只能使用container规定的资源,这里的资源主要指cpu和内存
我们描述某个container可以这么描述
192.168.1.X这台机器上的1G内存和两个cpu
那么运行在这个container上的进程上的应用只能使用1G的内存和两个CPU(yarn内部使用linux的cgroup进行资源限制)
所以container是一个程序可使用的资源范围,这个范围在程序启动前就限制住了,所以container确实是一个资源的抽象,也是一个进程运行的容器
container的大小
那么一个container具体是多大内存多少cpu呐?
这主要取决于我们的应用程序到底需要多少,比如某个应用程序需要2G内存和4个CPU,那么可以向yarn申请,yarn如果有足够的剩余资源就可以给应用分配,所分配的container就是某单台机器上的2G内存和4个CPU
当然container的大小是有限制的,不可能随意申请,但这个限制可以自己配置
container的作用
为什么yarn要用container限制进程的资源使用呐?
主要是为了合理调度,比如一台机器有8个CPU、8G内存,某个应用程序申请了container占用了4个CPU和4G内存,这台机器剩余就是4个CPU和4G内存,下次再有任务时就可以根据剩余资源考虑要不要在这台机器上运行
再就是这种资源隔离也避免了多应用程序之间互相争抢,这就是刘华强口中的先明后不争
container总结
yarn使用container这个概念更加细粒度的管理集群中每台机器的资源,container作为容器使各程序之间资源隔离
原理
接下来讲一下yarn是如何实现的多台机器的统一调度,以及如何划分管理container
NodeManage(NM)
和HDFS的DataNode类似,Yarn的集群每台机器也跑了一个常驻jvm进程:NodeManage
,它是单台机器的资源管理者,承担以下责任
- 记录机器的所有资源
- 可以按命令运行应用程序,并按规定的container限制应用程序的资源使用,即在container容器中运行程序
- 实时记录抛去运行container占用后的剩余资源
ResourceManager(RM)
与HDFS的NameNode类似,是所有机器上的NodeManage的统一管理者和门面,主要承担以下责任
- 管理NM,NM要与RM进行心跳来回报自己的状态,剩余资源等信息
- 对外抽象出一个大的程序可用资源:所有机器的内存/CPU之和
- 管理所有应用程序,主要为了调度其运行时机
- 按照应用程序的要求选择合适的NM,以便后续运行程序
-
通过调度调节多应用程序的执行顺序,执行节点等
其中RM的调度器有很多种方式,是一种可插拔的调度器(可以自定义),比较常用的有
- FIFo Scheduler(先进先出调度器,Hadoop自带的)
- Capacity scheduler(容量调度器,Yahoo写的)
- Fair scheduler(公平调度器 FaceBook写的)
调度器主要作用就是控制多程序谁先执行谁后执行,穿插执行等,主要为了资源更好的被利用,提升程序运行速度,就像windows操作系统也有自己的调度器,它会决定哪些线程先执行,哪些后执行,如何执行
应用
上文说yarn相当于一个操作系统,我们可以编写应用程序在yarn上运行
yarn上运行的最经典的应用当属hadoop自带的MapReduce
还有很多第三方开发的运行在yarn上的程序,如大名鼎鼎的HBase、Spark等
当然我们也可以自己写一个应用程序运行在yarn上
当然运行在yarn上的程序就要遵守yarn的规矩
因为在Yarn上运行的程序一般都会有子程序(否则就是单机运行了,没有必要在yarn上跑),所以Yarn中应用的主程序成为ApplicationMaster
,简称AM
,就相当于Java单机开发中的主线程Main-Thread
AM
代码中需要注册到RM,也可以向RM申请额外的container来运行子程序
有了HDFS的磁盘管理,加上YARN的CPU和内存管理,HADOOP就成为了一个可扩展的超级操作系统,大数据的存储和计算也就不在话下了
MapReduce
上面也提到了,YARN相当于操作系统,MapReduce是运行在其上的一种应用程序
准确的说MapReduce更像spring这样的一个程序框架,我们可以定制map和reduce方法,最终打包成应用程序jar包运行在yarn上
MapReduce特别适合大文本文件的内容分析,比如日志分析
MapReduce分为Map和Reduce,其中
- Map主要进行每行的分析,把关键标志信息作为key,value存储相关要计算的信息,生成一个Map结构
- Reduce翻译过来是“减少”,减少的方式就是针对map相同key的合并,类似于sql中的group by,通过合并加计算可以得到最终的结果
那hadoop官方WordCount程序举例,该方法主要统计每个单次出现的次数
最终计算出java出现2次,hadoop出现2次。。。
由于计算文件一般超大,一台电脑计算太慢,MapReduce会把文件切片,MapReduce的AM程序会申请多个container执行Map任务,所有Map结束后又会申请多个container执行Reduce任务,这样就把超大文件的计算压力分布在各个机器上
最后
最后在再次总结一下:
hadoop的hdfs+yarn组成了一个可扩展的的超级操作系统,在这个操作系统上我们可以存储超大数据,也可以通过执行MapReduce这样的应用程序来完成大数据的处理
之后我会介绍如何在Yarn上运行一个自己写的分布式小程序