一、定义:
狭义上来说,
hadoop
就是单独指代
hadoop
这个软件,
广义上来说,
hadoop
指代大数据的一个生态圈,包括很多其他的软件
二、分布式文件系统架构
分布式文件系统:将数据存放在多台电脑上存储。
分布式文件系统很多,HDFS是mapreduce计算的基础。
2.1 文件切分思想
源文件直接存放在一个磁盘上效率肯定很低(读取效率低,如果文件太大会超出单机存储的范围)
字节数组:文件在磁盘上真实存储文件的抽象概念
数组可以进行拆分合并,源文件不会收到影响。
切分数据:对数组进行拆分
拼接数据:按照数组偏移量将字节数组拼接到一起。
偏移量:当前数据在数组中的相对位置,可以理解为下标。
数组都有对应的下标,可以快速的定位数据。
不管文件的的大小,所有的文件都是由字节数组构成
如果我们要切分文件
,
就是将一个字节数组分成多份
我们将切分后的数据拼接到一起,数据可以继续使用
我们需要根据数据的偏移量将他们重新拼接到一起
2.2 Block拆分标准
拆分的数据快需要等大
数据计算的时候简化问题的复杂度
进行分布式算法设计的时候,数据不统一,算法很难设计
数据拉取的时候时间相对一致
通过偏移量就知道这个块的位置
相同文件,分成的数据块大小应该相等
数据块
Block
数据被切分后的一个整体称之为块
在
H1
默认大小为
64M,
在
H2
及其以后默认大小为
128M
同一个文件中,每个数据块大小要一致除了最后一个节点外
不同文件中,块的大小可以不一致
文件大小不同可以设置不同的块的数量
真实情况下,会根据文件大小和集群节点的数量综合考虑块的大小
数据块的个数
=Ceil
(
文件大小
/
每个块的大小)
注意事项
HDFS
中一旦文件被存储,数据不允许被修改
修改会影响偏移量
修改会导致数据倾斜
修改数据会导致蝴蝶效益
但是可以被追加,但是不推荐
追加设置需要手动打开
一般
HDFS
存储的都是历史数据。所以 将来
Hadoop
的
mr
都用来进行离线数据的处理
块的大小一旦文件上传之后就不允许被修改
128m -512M
如果数据文件的切割点
128M
整好是一个单词的中间部分,切分数据如何保证数据的完整性?
2.3 Block数据安全
肯定要对存储数据做备份
备份的数据肯定不能存放在一个节点上
使用数据的时候可以就近获取数据
所以备份的数量要小于等于节点的数量
每个数据块会有
3
个副本,相同副本是不会存放在同一个节点上
副本的数量可以变更
可能近期的数据被分析的可能性跟大,副本数可以多设置几个
后期数据很少被分析,可以减少副本数
2.4. Block
的管理效率
需要专门给节点进行分工
存储
DataNode
记录
NameNode
日志
secondaryNameNode
2.5. HDFS
的特点
优点
a)
高容错性
i.
保存多个副本,且提供容错机制。
ii.
副本丢失或宕机自动恢复。默认存
3
份。
b)
运行在廉价的机器上(商用机)
i.
通过副本提高可靠性
ii.
提供了容错和恢复机制
c)
适合批处理
i.
移动计算而非数据
ii.
数据位置暴露给计算框架。
NameNode
上有位置
d)
适合大数据的处理
i.TB
,甚至
PB
级数据
ii.
百万规模以上的文件数量
iii.10K+
节点规模
e)
流式数据访问
i.
一次写入,多次读取,高吞吐量,所以可以同时处理大量数据
缺点
a)
不擅长低延迟数据访问
比如毫秒级
b)
不擅长小文件的分区
i.
占用
NameNode
大量内存
ii.
磁盘寻道时间超过读取时间
c)
不擅长并发写入,文件随机修改
i.
一个文件只能有一个写入者
ii.
仅支持
append,
也就是添加(有组件实现删等)
三、NameNode
3.1 功能
接受客户端的读写服务
NameNode
存放文件与
Block
的映射关系
NameNode
会记录
Block
与
DataNode
的映射关系,但是不会持久化
保存文件的元数据信息
文件的归属
文件的权限
文件的大小时间
Block
信息,但是
block
的位置信息不会持久化
,
需要每次开启集群的时候
DN
上报
收集
Block
的信息
系统启动时
NN
关机的时候是不会存储任意的
Block
与
DN
的映射信息
DN
启动的时候,会将自己节点上存储的
Block
信息汇报给
NN
NN
接受请求之后重新生成映射关系
Block--DN3
如果某个数据块的副本数小于设置数,那么
NN
会将这个副本拷贝到其他节点
集群运行中
NN
与
DN
保持心跳机制
,
三秒钟发送一次
如果客户端需要读取或者上传数据的时候,
NN
可以知道
DN
的健康情况
可以让客户端读取存活的
DN
节点
如果
DN
超过三秒没有心跳,就认为
DN
出现异常
不会让新的数据读写到
DataNode
-
客户访问的时候不提供异常结点的地址
如果
DN
超过
10
分钟
+30
秒没有心跳,那么
NN
会将当前
DN
存储的数据转存到其他节点
超时时长的计算公式为:
timeout = 2 * heartbeat.recheck.interval + 10 *
dfs.heartbeat.interval
。 而默认的
heartbeat.recheck.interval
大小为
5
分钟,
dfs.heartbeat.interval
默认为
3
秒。
3.2 性能
NameNode
为了效率,将所有的操作都在内存中完成
NameNode
不会和磁盘进行任何的数据交换
问题
:
数据的持久化
数据保存在内存中,掉电易失
四、DataNode
4.1 功能
存放的是文件的数据信息和验证文件完整性的校验信息
数据会存放在硬盘上
1m=1
条元数据
1G=1
条元数据
NameNode
非常排斥存储小文件,一般小文件在存储之前需要进行压缩
汇报
启动时
汇报之前先验证
Block
文件是否被损坏
向
NN
汇报当前
DN
上
block
的信息
运行中
向
NN
保持心跳机制
客户可以向
DN
读写数据,
当客户端读写数据的时候,首先去
NN
查询
file
与
block
与
dn
的映射
然后客户端直接与
dn
建立连接,然后读写数据
五、
SecondaryNameNode
5.1 传统解决方案
日志机制
做任何操作之前先记录日志
当
NN
下次启动的时候,只需要重新按照以前的日志
“
重做
”
一遍即可
缺点
edits
文件大小不可控,随着时间的发展,集群启动的时间会越来越长
有可能日志中存在大量的无效日志
优点
绝对不会丢失数据
拍摄快照
我们可以将内存中的数据写出到硬盘上
序列化
启动时还可以将硬盘上的数据写回到内存中
反序列化
缺点
关机时间过长
如果是异常关机,数据还在内存中,没法写入到硬盘
如果写出频率过高,导致内存使用效率低(
stop the world
)
JVM
优点
启动时间较短
5.2 SNN解决方案
解决思路(日志edit+快照fsimage)
让日志大小可控
快照定时保存
NameNode文件目录
查看目录
/var/yjx/hadoop/full/dfs/name/current
edits_0000000000000000001-0000000000000000019
edits_inprogress_0000000000000000020
当前正在执行操作的日志信息
这些日志信息还没有被合并到镜像中
fsimage_0000000000000000000
fsimage_0000000000000000000.md5
fsimage_0000000000000000019
fsimage_0000000000000000019.md5
完整性校验规则
seen_txid -->19
VERSION
解决方案
当我们启动一个集群的时候,会产生四个文件
edits_0000000000000000001
fsimage_
edits_000000000000000000
seen_txid
VERSION
我们每次操作都会记录日志-->edits-inprogress-
edits_00000001
随着时间的推移,日志文件会越来越大-当达到阈值的时候(64M或3600秒)
会生成新的日志文件
edits_inprogress-000000001 -->edits_0000001
创建新的日志文件
edits_inprogress-0000000016
六、安全模式
集群启动时的一个状态
安全模式是
HDFS
的一种工作状态,处于安全模式的状态下,只向客户端提供文件的只读视
图,不接受对命名空间的修改;同时
NameNode
节点也不会进行数据块的复制或者删除,
NameNode
启动时,
首先将镜像文件(
fsimage
)载入内存,并执行编辑日志(
edits
)中的各项操作。
一旦在内存中成功建立文件系统元数据的映像,则创建一个新的
fsimage
文件和一个空的编辑
日志。
NameNode
开始监听
RPC
和
Http
请求。
此时
NameNode
处于安全模式,只接受客户端的读请求。
系统中的数据块的位置并不是由
NameNode
维护的,而是以块列表的形式存储在
DataNode
中。
[root@node01 ~]# rm -rf /var/yjx/hadoop/full/dfs/name/current/*
[root@node01 ~]# scp -r
root@node02:/var/yjx/hadoop/full/dfs/namesecondary/current/*
/var/yjx/hadoop/full/dfs/name/current
安全模式下
安全模式下,各个
DataNode
会向
NameNode
发送自身的数据块列表
当
NameNode
有足够的数据块信息后,便在
30
秒后退出安全模式
NameNode
发现数据节点过少会启动数据块复制过程
如果
NN
收集的
Block
信息没有达到最少副本数,就会将缺失的副本
,
从有的
DN
上拷贝到其他
DN
dfs.replication.min=2
但是默认最低副本数为
1
在拷贝的过程中系统还是处于安全模式
安全模式相关命令
hadoop dfsadmin -safemode leave
强制
NameNode
退出安全模式
hadoop dfsadmin -safemode enter
进入安全模式
hadoop dfsadmin -safemode get
查看安全模式状态
hadoop dfsadmin -safemode wait
等待一直到安全模式结束
七、HDFS权限
HDFS
对权限的控制
只能防止好人做错事
不能防止坏人做坏事
你告诉他你是谁,他就认为你是谁!
八、机架感知策略
8.1 节点距离
distance(/D1/R1/H1,/D1/R1/H1)=0
相同的
datanode
distance(/D1/R1/H1,/D1/R1/H3)=2
同一
rack
下的不同
datanode
distance(/D1/R1/H1,/D1/R2/H4)=4
同一
IDC
下的不同
datanode
distance(/D1/R1/H1,/D2/R3/H7)=6
不同
IDC
下的
datanode
8.2 机架感知
机架感知是为了保证副本在集群中的安全性
我们需要将节点放在不同的DN节点上,节点也需要一定的考量
可靠性,可用性,带宽消耗
第一个节点:
集群内部(优先考虑和客户端相同的节点作为第一个节点)
集群外部(选择资源丰富且不繁忙的节点作为第一个节点)
第二个节点:
第二个节点选择与第一个节点不同机架的其他节点
第三个节点:
与第二个相同机架相同的其他节点
第N个节点:
与前面节点不重复的其他节点
九、HDFS写数据流程
写数据就是将客户端上的数据上传到HDFS
9.1 宏观过程
1.客户端向HDFS发送写数据请求
hdfs dfs -put tomcat.tar.gz /yjx/
2. filesystem通过rpc调用namenode的create方法
nn首先检查是否有足够的空间权限等条件创建这个文件,或者这个路径是否已经存在,权限
有:NN会针对这个文件创建一个空的Entry对象,并返回成功状态给DFS
没有:直接抛出对应的异常,给予客户端错误提示信息
3.如果DFS接收到成功的状态,会创建一个FSDataOutputStream的对象给客户端使用
4.客户端要向nn询问第一个Block存放的位置
NN通过机架感知策略 (node1 node 2 node8)
5.需要将客户端和DN节点创建连接
pipeline(管道)
客户端和node1
创建连接
socket
node1和
node2
创建连接
socket
node2 和
Node8
创建连接
socket
6.客户端按照文件块切分数据,但是按照packet发送数据
默认一个packet大小为64K,Block128M为2048个packet
7.客户端通过pipeline管道开始使用FDSOutputStream对象将数据输出
1. 客户端首先将一个
packet
发送给
node1,
同时给予
node1
一个
ack
状态
2. node1接受数据后会将数据继续传递给
node2,
同时给予
node2
一个
ack
状态
3. node2接受数据后会将数据继续传递给
node8,
同时给予
node8
一个
ack
状态
4. node8将这个
packet
接受完成后,会响应这个
ack
给
node2
为
true
5. node2会响应给
node1 ,
同理
node1
响应给客户端
8.
客户端接收到成功的状态
,
就认为某个
packet
发送成功了,直到当前块所有的
packet
都发送完成
9.
如果客户端接收到最后一个
pakcet
的成功状态
,
说明当前
block
传输完成,管道就会被撤销
10.
客户端会将这个消息传递给
NN
,
NN
确认传输完成
1. NN会将
block
的信息记录到
Entry,
客户端会继续向
NN
询问第二个块的存储位置
,
依次类推
2. block1 (node1 node2 node8)
3. block2 (node1 node8 node9)
4. ....
5. blockn(node1 node7 node9)
11.
当所有的
block
传输完成后,
NN
在
Entry
中存储所有的
File
与
Block
与
DN
的映射关系关闭
FsDataOutPutStream
9.2 微观过程
1.客户端首先从自己的硬盘中以流的形式将自己的数据读取到缓存中
2.然后将缓存中的数据以chunk(512B)和checksum(4B)的方式放入到packet(64k)
1. chunk:checksum=128:1
2. checksum:在数据处理和数据通信领域中,用于校验目的的一组数据项的和
3. Packet中的数据分为两类,一类是实际数据包,另一类是
header
包。
4. 一个
Packet
数据包的组成结构
3.当packet满的时候添加到dataqueue
4.datastreamer开始从dataqueue队列上读取一个packet,通过FDSDataOPS发送到Poepleline
在取出的时候,也会将
packet
加入到
ackQueue,
典型的生产者消费者模式
5.
客户端发送一个
Packet
数据包以后开始接收
ack
,会有一个用来接收
ack
的
ResponseProcessor
进
程,如果收到成功的
ack
1. 如果某一个
packet
的
ack
为
true,
那么就从
ackqueue
删除掉这个
packet
2. 如果某一个
packet
的
ack
为
false,
将
ackqueue
中所有的
packet
重新挂载到 发送队列
,
重新发送
十、HDFS读数据流程
首先客户端发送请求到
DFS
,申请读取某一个文件
/yjx/tomcat.tar.gz
DFS
去
NN
查找这个文件的信息
(
权限
,
文件是否存在
)
如果文件不存在,抛出指定的错误
如果文件存在,返回成功状态
DFS
创建
FSDataInputStream
对象,客户端通过这个对象读取数据
客户端获取文件第一个
Block
信息
,
返回
DN1 DN2 DN8
客户端直接就近原则选择
DN1
对应的数据即可
依次类推读取其他块的信息,直到最后一个块
,
将
Block
合并成一个文件
关闭
FSDataInputStream
十一、Hadoop1
的困境
单点故障
每个群集只有一个
NameNode
,
NameNode
存在单点故障(
SPOF
)。
如果该计算机或进程不可用,则整个群集在整个
NameNode
重新启动或在另一台计算机上启
动之前将不可用
如果发生意外事件(例如机器崩溃),则在操作员重新启动
NameNode
之前,群集将不可
用。
计划内的维护事件,例如
NameNode
计算机上的软件或硬件升级,将导致群集停机时间的延
长。
水平扩展
将来服务器启动的时候,启动速度慢
namenode
随着业务的增多,内存占用也会越来越多
如果
namenode
内存占满,将无法继续提供服务
业务隔离性差
存储:有可能我们需要存储不同部门的数据
计算:有可能存在不同业务的计算流程
项目后期
namenode
的吞吐量将会是集群的瓶颈
客户端所有的请求都会先访问
NameNode
Hadoop2.x
NameNode
节点的高可用
HA--high availability
NameNode
业余的水平扩展
Federation
十二、Hadoop-HA
12.1 设计思想
hadoop2.x
启用了主备节点切换模式(1主
1
备)
当主节点出现异常的时候,集群直接将备用节点切换成主节点
要求备用节点马上就要工作
主备节点内存几乎同步
有独立的线程对主备节点进行监控健康状态
需要有一定的选举机制,帮助我们确定主从关系
我们需要实时存储日志的中间件
12.2 ANN
Active NameNode
的功能和原理的
NN
的功能是一样的
接受客户端请求,查询数据块
DN
信息
存储数据的元数据信息
数据文件:
Block
:
DN
的映射关系
工作
启动时:接受
DN
的
block
汇报
运行时:和
DN
保持心跳
(3s,10m30s)
存储介质
完全基于内存
优点:数据处理效率高
缺点:数据的持久化
(
日志
edits+
快照
fsimage)
12.3 SNN
Standby NameNode
:
NN
的备用节点
他和主节点做同样的工作,但是它不会发出任何指令
存储:数据的元数据信息
数据文件:
Block
:
DN
的映射关系
它的内存数据和主节点内存数据几乎是一致的
工作:
启动时:
接受
DN
的
block
汇报
运行时:
和
DN
保持心跳
(3s,10m30s)
存储介质
完全基于内存
优点:数据处理效率高
缺点:数据的持久化
合并日志文件和镜像
当搭建好集群的时候,格式化主备节点的时候,
ANN
和
SNN
都会会默认创建
fsimage_000000000000000
当我们操作
HDFS
的时候
ANN
会产生日志信息
edits_inprogress_0000000000001
主节点会将日志文件中新增的数据同步到
JournalNode
集群上
所以只需要
snn
有操作的日志信息,就可以合并
fsImage
与
edits
信息
,
理论上是一直在合并数据
fsimage -->
初始化创建
edits-->
从
JournalNode
集群上定时同步
只要同步到
edits
文件,就开始于
fsimage
合并
当达到阈值的时候,直接拍摄快照即可
SNN
将合并好的
Fsimage
发送给
ANN,ANN
验证无误后,存放到自己的目录中
12.4 DataNode(DN)
存储
文件的
Block
数据
介质
硬盘
启动时:
同时向两个
NN
汇报
Block
信息
运行中
同时和两个
NN
节点保持心跳机制
12.5 QJM
Quorum JournalNode Manager
共享存储系统,
NameNode
通过共享存储系统实现日志数据同
步。
JournalNode
是一个独立的小集群,它的实现原理和
Zookeeper
的一致
( Paxos)
ANN
产生日志文件的时候,就会同时发送到
JournalNode
的集群中每个节点上
JournalNode
不要求所有的
jn
节点都接收到日志,只要有半数以上的(
n/2+1
)节点接受收到日
志,那么本条日志就生效
SNN
每间隔一段时间就去
QJM
上面取回最新的日志
SNN
上的日志有可能不是最新的
HA
集群的状态正确至关重要,一次只能有一个
NameNode
处于活动状态。
JournalNode
只允许单个
NameNode
成为作者。在故障转移期间,将变为活动状态的
NameNode
将承担写入
JournalNodes
的角色,这将有效地防止另一个
NameNode
继续处于活动状态,从而使
新的
Active
节点可以安全地进行故障转移。
12.6 ZKFC
Failover Controller(
故障转移控制器
)
对
NameNode
的主备切换进行总体控制,能及时检测到
NameNode
的健康状况
在主
NameNode
故障时借助
Zookeeper
实现自动的主备选举和切换
为了防止因为
NN
的
GC
失败导致心跳受影响,
ZKFC
作为一个
deamon
进程从
NN
分离出来
启动时:
当集群启动时,主备节点的概念是很模糊的
当
ZKFC
只检查到一个节点是健康状态,直接将其设置为主节点
当
zkfc
检查到两个
NN
节点是的健康状态,发起投票机制
选出一个主节点,一个备用节点,并修改主备节点的状态
运行时:
由
ZKFailoverController
、
HealthMonitor
和
ActiveStandbyElector
这
3
个组件来协同实现
主备切换
ZKFailoverController
启动的时候会创建
HealthMonitor
和
ActiveStandbyElector
这两
个主要的内部组件
HealthMonitor
主要负责检测
NameNode
的健康状态
ActiveStandbyElector
主要负责完成自动的主备选举,内部封装了
Zookeeper
的处理逻
辑
主备节点正常切换
NameNode
在选举成功后,
ActiveStandbyElector
会在
zk
上创建一个
ActiveStandbyElectorLock
临时节点,而没有选举成功的备
NameNode
中的
ActiveStandbyElector
会监控这个节点
如果
Active NameNode
对应的
HealthMonitor
检测到
NameNode
的状态异常时,
ZKFailoverController
会主动删除当前在
Zookeeper
上建立的临时节点
ActiveStandbyElectorLock
如果是
Active NameNode
的机器整个宕掉的话,那么跟
zookeeper
连接的客户端线程也挂
了
,
会话结束
,
那么根据
Zookeepe
的临时节点特性,
ActiveStandbyElectorLock
节点会自动被
删除,从而也会自动进行一次主备切换
处于
Standby
状态的
NameNode
的
ActiveStandbyElector
注册的监听器就会收到这个节点
的
NodeDeleted
事件,并创建
ActiveStandbyElectorLock
临时节点,本来处于
Standby
状
态的
NameNode
就选举为
Active NameNode
并随后开始切换为
Active
状态。
12.7
Zookeeper
为主备切换控制器提供主备选举支持。
辅助投票
和
ZKFC
保持心跳机制,确定
ZKFC
的存活
12.8
脑裂
brain-split
定义
脑裂是
Hadoop2.X
版本后出现的全新问题,实际运行过程中很有可能出现两个
namenode
同
时服务于整个集群的情况,这种情况称之为脑裂。
原因
脑裂通常发生在主从
namenode
切换时,由于
ActiveNameNode
的网络延迟、设备故障等问
题,另一个
NameNode
会认为活跃的
NameNode
成为失效状态,此时
StandbyNameNode
会
转换成活跃状态,此时集群中将会出现两个活跃的
namenode
。因此,可能出现的因素有网
络延迟、心跳故障、设备故障等。
脑裂场景
NameNode
可能会出现这种情况,
NameNode
在垃圾回收(
GC
)时,可能会在长时间内整
个系统无响应
zkfc
客户端也就无法向
zk
写入心跳信息,这样的话可能会导致临时节点掉线,备
NameNode
会切换到
Active
状态
这种情况可能会导致整个集群会有同时有两个
Active NameNode
脑裂问题的解决方案是隔离(
Fencing
)
1.
第三方共享存储:任一时刻,只有一个
NN
可以写入;
2.DataNode
:需要保证只有一个
NN
发出与管理数据副本有关的命令;
3.Client
需要保证同一时刻只有一个
NN
能够对
Client
的请求发出正确的响应。
(a)
每个
NN
改变状态的时候,向
DN
发送自己的状态和一个本次选举对应的序列号。
(b) DN
在运行过程中维护此序列号,当
failover
时,新的
NN
在返回
DN
心跳时会返回自己
的
active
状态和一个更大的序列号。
DN
接收到这个返回是认为该
NN
为新的
active
。
(c)
如果这时原来的
active
(比如
GC
)恢复,返回给
DN
的心跳信息包含
active
状态和原来
的序列号,这时
DN
就会拒绝这个
NN
的命令。
解决方案
ActiveStandbyElector
为了实现
fencing
,当
NN
成为
ANN
之后创建
Zookeeper
临时节点
ActiveStandbyElectorLock
,创建
ActiveBreadCrumb
的持久节点,这个节点里面保存了这个
Active NameNode
的地址信息
(node-01)
Active NameNode
的
ActiveStandbyElector
在正常的状态下关闭
Zookeeper Session
的时
候,会一起删除这个持久节点
但如果
ActiveStandbyElector
在异常的状态下关闭,那么由于
/hadoop
ha/${dfs.nameservices}/ActiveBreadCrumb
是持久节点,会一直保留下来,后面当另一个
NameNode
选主成功之后,会注意到上一个
Active NameNode
遗留下来的这个节点,从而
会回调
ZKFailoverController
的方法对旧的
Active NameNode
进行
fencing
。
首先尝试调用这个旧
Active NameNode
的
HAServiceProtocol RPC
接口的
transitionToStandby
方法,看能不能把它转换为
Standby
状态;
如果
transitionToStandby
方法调用失败,那么就执行
Hadoop
配置文件之中预定义的
隔离措施。
1. sshfence
:通过
SSH
登录到目标机器上,执行命令
fuser
将对应的进程杀死
2. shellfence
:执行一个用户自定义的
shell
脚本来将对应的进程隔离
在成功地执行完成
fencing
之后,选主成功的
ActiveStandbyElector
才会回调
ZKFailoverController
的
becomeActive
方法将对应的
NameNode
转换为
Active
状态,开始
对外提供服务。
新的主创建临时节点
ActiveStandbyElectorLock
,创建持久化节点
ActiveBreadCrumb
,并将
自己的主机地址
Node02
赋值给初始化节点
所有评论(0)