虽说主从结构相对简单,但是公司中不会采用这种简单的主从结构,因为这会带来两个严重问题
- 若主节点发生故障,即单点故障,会造成整个集群不可用
- 主节点内存受限,压力过大
这是两个独立的问题,业内对于这两个问题给出了不同的解决方案,下面具体说明
Hadoop—高可用解决方案(HA)
所谓Hadoop高可用(HA)实际上就是配置多个Namenode,一个作为主机(Active),其他作为备机(Standby),以便主机出现故障时进行主备切换。Hadoop 2.x只支持一主一备,Hadoop 3.x最高支持一主五备。在HA模式中,只有Active对外提供服务,Standby只是正常运行,不与外界产生交互。高可用的最终目的就是:即使发生了主备切换,在外界看来没有发生任何变化,所以这个方案重点就在于,如何保证主备机子的数据一致、可用、低延迟。
下图是高可用解决方案的示意图
下面具体解释这张图
当主机挂机了,client切换至standby遇到的第一个问题就是:Namenode间的数据同步问题。
Namenode上的元数据实际上可分为两类:1. 由client交互操作产生(如mkdir之类的操作);2. 由Datanode提交的数据。
由于Datanode的block汇报同时向Active和Standby汇报,所以由Datanode提交的元数据不会遇到数据同步问题,于是关键就在于由client交互产生的元数据
同步client交互操作产生的元数据实际上就是同步Namenode的Editlog,由如下几种方案(以mkdir操作为例):
- 同步阻塞:client需要mkdir,将指令告诉Active,Active告诉Standby有一个mkdir要执行,当Standby执行完了,返回OK给Active,Active返回OK给客户端,这样mkdir才执行完成。
这种方案若Standby宕机了,则client的mkdir就永远执行不成功,所以这种方案是强一致性的但是破坏了可用性。
为防止萌新不懂什么是一致性和可用性,这里简单回顾一下CAP原则:C:Consistence一致性;A:Availability可用性;P:Partition Tolerance分区容忍性。在分布式环境中,集群必须满足CAP原则,CAP原则告诉我们CAP是永远无法同时满足的,但应该要满足其中两个。 - 异步非阻塞:client需要mkdir,将指令告诉Active,Active告诉Standby有一个mkdir要执行,但Active返回OK给client,并不关心Standby是否成功执行了mkdir。
这种方案保证了可用性,但Standby可能在接受到mkdir时就宕机了,所以无法保证一致性。
所以最终我们应当折中这两个方案,产生的一致性称为弱一致性,或称为最终一致性。这时我们需要在Active和Standby中间加入一个相对可靠的组件,Active将mkdir写入该组件且信任该组件(相信mkdir绝对会成功写入组件,且可靠安全),这样即使Standby宕机了,将来都可以从跟这个组件中读到这个操作并恢复(从而也说明了这个组件具有存储的功能)。
若这个组件是单点的,根据墨菲定律也必将不可靠,所以组件也是集群的(上图中的JN),可是此时产生了新的问题,Active要将mkdir写到一个JN,两个JN,还是几个JN中。
于是我们考虑,Active给过半的JN都传递了mkdir,我们就返回OK给client,Standby在读的时候,判断存储了mkdir操作的JN数量过半,这样就保证了mkdir最终会被Standby执行到,且是最新的操作,这就解决了消息一致性的问题。
Paxos算法是一种基于消息传递的一致性算法,该算法覆盖全部场景的一致性问题,各技术会根据自己的技术特种简化算法并实现,该算法的具体内容这里不再赘述,主要说明一下Paxos在这里的体现。
简化一下Paxos的思路,JN的具体方案是这么做的:首先要明确JN的数量,明确JN的权重,在启动集群瞬间,JN就根据权重选举出一个主JN,在JN集群中也构建出了主从结构。以后Active发来的关于增删改查的功能由主JN负责,从JN只负责查询的功能,若从JN收到增删改的请求,也会将该信息传递给主JN,主JN做完增删改再将结果同步到所有的从JN中,有超过一半的从JN同步成功,就给Active返回OK。若主JN宕机了,则会马上再选举出新的主JN。权重可手动分配,也可根据ip地址(全网唯一)由算法算出一个不与其他JN冲突的唯一权重。
综上,Namenode的高可用已基本实现,但还有一个问题,设置Namenode为Active还是Standby,以及Active宕机之后切换Standby为Active是我们手工完成的,如何自动化完成这件事?
使用分布式协调服务Zookeeper就可以完成这件事,这也是一个可靠性很高的服务,符合CAP原则并采用了Paxos算法,实现了自己的算法Zab(Paxos的一个简化实现)。
这时我们要向集群中增加新的角色—ZKFC (Zookeeper FailoverController,Zookeeper故障转移),注意这是一个实实在在的JVM进程,与Namenode运行在同一个机器上。这个进程用于
- 监视Namenode状态
- 连接Zookeeper(下文简称ZK)
接下来说明如何实现自动化确定主备,下文用NN简称Namenode
当ZKFC与ZK和NN连上之后,两个ZKFC都会尝试在ZK的目录树下某结点上创建一把锁(简单说明一下Zookeeper,Zookeeper的数据结构有点像Linux的文件系统,可以看作是一个树,树中每一个节点代表一个文件路径,称这个树为目录树,结点分为两种:临时(Ephemeral)和永久(Persistent),当连接断开,临时结点会自动删除,永久结点则不会),谁创建成功,对应的NN就是Active,失败的NN就是Standby,这一过程成为抢锁。注意:抢锁时ZKFC还会在该锁上注册一个回调函数,以便ZK通知ZKFC下次抢锁。之后若Active宕机了,对应的ZKFC就会删去这把锁,这时ZK就会触发删除事件,然后ZK就会触发当初所有ZKFC们注册的回调函数(注意:当时ZKFC只是在ZK上注册了一个回调函数以便ZK触发,触发之后真正的具体业务逻辑代码还是在ZKFC上运行的,而不是在ZK上运行),通知其余ZKFC重新抢锁。当有一个ZKFC抢到锁后,该ZKFC会去check刚才宕机的NN是否真的宕机,只有确认了才会将自己对应的NN升级为Active。
可是,ZKFC也是一个进程,若对应的Active还活着而ZKFC发生异常宕机了怎么办?注意:当时创建锁的结点可以是临时结点,那么当ZKFC宕机与ZK连接断开之后,这个结点就会被自动删除,对应的锁也就不复存在了,这时同样触发删除事件,触发回调函数通知其余ZKFC来抢锁,抢到锁的ZKFC同样会去check刚才的Active NN,将其降级为Standby,再将自己对应的NN升级为Active。
综上就是Hadoop的HA方案,谨记Datanode是向所有的NN汇报block信息的,且在HA模式中没有SecondaryNamenode(由于只有Active对外服务,Standby只是正常运行着不对外服务,所以Standby可以周期性地生成FsImage,并及时给Active推送,可以说在HA模式中,Standby替代了SecondaryNamenode的工作)。
我将在下篇博客中详细说明如何配置Hadoop的HA模式。
Hadoop—联邦机制(Federation)
联邦机制比较简单,就是多设置几个Namenode,将数据对应的元数据分别存在不同的Namenode中,以缓解单点Namenode的压力。所以联邦机制的特点是:元数据分治,复用Datanode存储,不同Namenode的元数据有隔离性,无法互相访问。
我将在下一篇博客中介绍如何搭建Hadoop的HA模式
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/20597.html