设为首页 加入收藏

TOP

hdfs的federation以及ha部署说明
2019-04-23 00:16:10 】 浏览:51
Tags:hdfs federation 以及 部署 说明

一、hdfs的federation说明

A、经典架构说明

这里说一下我自己的理解,什么叫federation?首先我们知道hdfs的经典架构是这样的:

一个namenode负责管理四大块:

a、命名空间目录树

b、文件与blocks映射关系

c、datanode与blocks之间映射关系

d、datanode异常处理

多个datanode,dn负责:

i、存储blocks

ii、接受Namenode命令,管理blocks

iii、与Client交互,参与读写过程
这种架构随着数据量数量级的增长,出现了一些明显的瓶颈和缺陷:
1、namenode内存瓶颈
由于namenode需要负责前面提到的那四种重要职能,目前的架构存储1亿个inode及其相关块信息大约需要30G内存,而企业应用数据超过10亿文件的情况很普遍,而高配的内存一般在128G+,内存瓶颈明显。
2、datanode节点数扩展瓶颈
存储型服务器一般挂载12个2T盘,存储10亿文件需要接近上万台datanode甚至更多,这种情况下,上万datanode与block的映射关系即故障处理全部交给namenode,一方面加重内存、cpu负载,同时rpc处理并发性能受到严峻考验。
3、namenode存在单点故障
namenode存在明显的单点故障,一旦挂点影响全集群用户,影响很大。

B、federation架构说明

为了解决上面的问题,社区开发了新的hdfs架构,并实现了HA,先来看一下federation思想的架构图:
如图所示,这是官方的一个架构图,整个架构其实变动不是很大,刨除HA不考虑,我们来分析一下这个架构:

1、架构仍然分为两层,一层是namespace,完成老架构namenode的全部功能,二层还是datanode负责数据存储和管理。
2、namespace隔离扩展
关于这一点,从这张图上并不能完全理解架构的意图,一种可能得想法是:是不是将命名空间管理的目录树和数据块映射表全部平坦化?
即将namenode的元数据按照某种策略平均分给多个namenode,一个namenode只负责管理元数据的一部分?这种设计思想的确有实际的应用,但是社区版本的federation并不是这样做的,因为如果把元数据分开由不同的namenode节点各自管理一部分,则需要设计一个数据请求的分发器,将读写等客户端请求分发到具体的namenode上。
社区的federation的设计思想是namenode完全隔离,每一个namenode各自维护自己的元数据,彼此没有任何依赖关系,但是引入了数据池的概念,一个集群中有多个namenode,每个namenode管理的数据块拥有一个poolID,所有的namenode公用所有的datanode,而datanode向所有的namenode汇报,保持心跳连接。
这种架构原理相当于有多个集群,区别在于他们公用datanode,为了说明这一点,我们举个例子:
假如不同的银行的资金和货币都存放在同一个金库,这个金库有很多仓储单位可以满足存储需求;建设银行、中国银行、农业银行等都租用这个金库的仓促空间,这些空间有金库统一管理。用户去各个银行存钱、取钱。银行账目独立,维护了一套用户信息以及资金关系的信息系统。
有了上面的模型之后,我们就非常容易理解federation的架构,namenode相当于各个银行,它的元信息就是各种账目,金库就相当于datanode,而客户端就是存钱取钱的用户,只不过实际hdfs存取是先从namenode获取数据的位置信息,从datanode直接获取,而银行既有控制流也有数据流。这仅是一个简单地例子希望能帮助大家理解federation的架构。
federation架构解决了老架构namenode的内存瓶颈和数据节点扩展的瓶颈问题,同时对用户进行了有效的隔离,这种架构下,namenode个数理论上可以无限扩展,同时不同产品线的业务数据可以使用不同的namenode存储管理,一个namenode挂了,不会影响到其它业务的数据服务。

C、多namenode对客户端的透明化

federation另一个特点是用户可以透明使用所有的namenode的数据服务,什么意思呢?
我们之前使用hdfs客户端的时候,通过配置core-site.xml的fs.default.name指定我们要访问的namenode,这里仍然使用这种配置方式,尽管key变成了fs.defaultFS。假如我们有2个namenode(federation),那么我如果配置了nn1,那么我的所有操操作都由nn1来管理,比如我往集群上put了一个文件,那么在nn1上我是能看到的,nn2是没有的,因为它倆完全独立,这个非常容易理解,但是如果我想使用两个集群上的数据该怎么办?
这种应用场景非常普遍,比如两条不同的产品线将数据存储在不同的namenode上,那么数据分析部门需要同时使用两个namenode上管理的数据,难道我还要重新配置fs.defaultFS吗?
为了解决上面这种问题,尽量减小系统架构变化对客户端的影响,社区提供了一种挂载的解决方案。
比如我需要获取hdfs://nn1/data_ns1和hdfs://nn2/data_ns2,那么我将fs.defaultFS配置成<property>
<name>fs.defaultFS</name>
<value>viewfs://nsX</value>
</property>
同时在core-site.xml中添加<configuration>
<property>
<name>fs.viewfs.mounttable.nsX.link./virtual_dir1</name>
<value>hdfs://nn1/data_ns1</value>
</property>
<property>
<name>fs.viewfs.mounttable.nsX.link./virtual_dir2</name>
<value>hdfs://nn2/data_ns2</value>
</property>
</configuration>
这样我们执行./hdfs dfs -ls /将会看到/virtual_dir1和/virtual_dir2两个目录
这里简要说明一下:
viewfs是federation实现的一种访问hdfs的文件系统实例,你可以把它理解成类似nfs的文件系统协议,nsX是我们任意指定的名称fs.viewfs.mounttable.nsX.link./virtual_dir1中的virtual_dir1是我们起的一个名字,任意的
virtual_dir1可以理解成是hdfs://nn1/data_ns1的别名,同样的virtual_dir2是hdfs://nn2/data_ns2的别名,这样用户使用的时候只看到两个别名,但是实际操作的对象就是那两个namenode管理的那两个文件。
这样就实现了namenode对客户端的透明化处理。

二、HA的设计及部署情况

首先说什么是HA?HA是High Availability(高可用性的缩写)
那什么是高可用,HA的设计目的就是为了解决老架构的第三个问题,即单点故障,分布式系统中普遍存在的经典问题就是单点故障,老架构中一个namenode挂了,整个服务不可用;federation之后,虽然各个namenode完全独立,挂了一个namenode,其它namenode上的数据还是可以使用,但是挂掉的那个节点管理的数据不可访问,这种局部不可用有时候在生产环境中也是不能容忍的。
那怎么才能算高可用呢,事实上,hdfs的HA试图解决这样一个问题,即一个独立的namode挂了,能立即(对用户透明)切换到另一个namenode,提供相当的一致的服务。
hdfs ha的解决方案可为百花齐放,linux HA,VMwareFT,shared NAS+NFS,Bookkeeper,QJM,BackupNode等,知名度比较高是facebook的Avatar,它就是使用nfs实现的ha方案。社区默认的ha方案是使journalnode作为共享editslog的中间媒介,说到这里你可能还不能理解这种HA方案的原理,下面给出一张社区的方案图,帮助大家理解,然后给出详细的配置实例,供大家参考。
架构说明如下:
对集群中的任意一个独立的namnode,配给一个机器作为它的备机,对外提供服务的机器我们成为active,另一个叫做standby,ha实现之后,我们希望active绝对地停止对外服务,而standby透明切换过来,这样对用户来讲,完全感知不到服务的中断。
要做到这一点,至少需要解决以下2个问题:
1、元数据的同步
standby必须在内存中不断地同步active的元数据,因为如果元数据存在磁盘再去加载的话,将会有半小时甚至更长的中断,这是不好的方案。
2、角色切换的触发
active出现故障或者挂点之后,standby如果立即接管active工作,它需要做哪些事情,响应时间如何控制?
首先来说第一个问题:
元数据如何同步,那么什么是元数据,大家都知道,元数据主要包括两部分,一个是命名空间,即目录树;二是数据块的映射表,这部分主要是datanode汇报上来的,持久化保存的不包括数据块的映射表,这是因为数据块映射表变动非常频繁,不适合持久化保存,因此,想要保证active和standby元数据一致,必须同步持久化出处的元数据即fsimage和edits,同时所有的datanode需要向standby实时汇报。实际上几乎所有的ha解决方案中并不共享fsimage,只要共享元数据增量即可,即editslog,因为fsimage比较大,另外共享增量完全能满足同步需要。下面介绍的方案是使用journalnode来共享edits存储。
如何触发active和standby的状态切换?这里使用了zookeeper,active和standby在本机上分别启动了DFSZKFailoverController进程,这个进程负责对本机nn状态进行监控,同时更新和获取在zookeeper上建立的znode数据,当active发生故障,它倆分别敦促两个nn进行状态转换,同时进行相应的数据同步和其它一些操作。这时候用户实际访问请求从active转移到了standby上,原来的standby变成了active,原来的active变成了standby状态。
关于上述技术细节,后续将继续补充,供大家参考。
下面我来介绍一下如何搭建这样的一套既有federation又实现了ha的hdfs系统。
首先,我们准备一下机器列表:
master:
10.4.19.44
10.4.19.46

10.4.19.48
10.4.19.52
以上4台就是我们的namenode,两个一对构成ha,这样一个集群中实现了federation,有两个active namenode对外提供服务。
zookeeper.list
zookeeper服务要使用奇数台服务器,这里我们使用下面3台
10.4.19.49
10.4.19.50
10.4.19.51
端口是2181
journalnode复用上面三台机器
datanode列表如下:
10.4.19.45
10.4.19.46

10.4.19.47

10.4.19.48

10.4.19.49

10.4.19.50
10.4.19.51

配置文件说明

a、core-site.xml

的关键配置很少,就两个,其中fs.defaultFS你也可以不用配置,只要写好zk服务器列表和端口就行了。

<configuration>

<property>

<name>fs.defaultFS</name>

<value>hdfs://10.4.19.44:8020</value>

</property>

<property>

<name>ha.zookeeper.quorum</name>

<value>10.4.19.49:2181,10.4.19.50:2181,10.4.19.51:2181</value>

</property>//DFSZKFailoverController根据这个地址格式化znode,获取相应信息。

</configuration>

b、hdfs-site.xml

hdfs-site.xml的目的主要是告诉系统所有的namenode包括standby,包括所有的namespace的namenode地址,同时设置ha的active和standby自动切换,然后需要配置editslog共享存储的位置。

<configuration>

<!- configure for NameNode->

<property>

<name>dfs.nameservices</name>

<value>ns1,ns2</value>

</property>

<property>

<name>dfs.ha.namenodes.ns1</name>

<value>nn1,nn2</value>

</property>

<property>

<name>dfs.namenode.rpc-address.ns1.nn1</name>

<value>10.4.19.44:8020</value>

</property>

<property>

<name>dfs.namenode.rpc-address.ns1.nn2</name>

<value>10.4.19.46:8020</value>

</property>

<property>

<name>dfs.namenode.http-address.ns1.nn1</name>

<value>10.4.19.44:50070</value>

</property>

<property>

<name>dfs.namenode.http-address.ns1.nn2</name>

<value>10.4.19.46:50070</value>

</property>

<property>

<name>dfs.ha.namenodes.ns2</name>

<value>nn3,nn4</value>

</property>

<property>

<name>dfs.namenode.rpc-address.ns2.nn3</name>

<value>10.4.19.48:8020</value>

</property>

<property>

<name>dfs.namenode.rpc-address.ns2.nn4</name>

<value>10.4.19.52:8020</value>

</property>

<property>

<name>dfs.namenode.http-address.ns2.nn3</name>

<value>10.4.19.48:50070</value>

</property>

<property>

<name>dfs.namenode.http-address.ns2.nn4</name>

<value>10.4.19.52:50070</value>

</property>

<property>

<name>dfs.client.failover.proxy.provider.ns1</name>

<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>

</property>

<property>

<name>dfs.client.failover.proxy.provider.ns2</name>

<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>

</property>

<property>

<name>dfs.namenode.shared.edits.dir</name>

<value>qjournal://10.4.19.49:8485;10.4.19.50:8485;10.4.19.51:8485/ns1</value>

</property>

<property>

<name>dfs.journalnode.edits.dir</name>

<value>/data/journalnode/ns1/edits</value>

</property>

<property>

<name>dfs.ha.automatic-failover.enabled.ns2</name>

<value>true</value>

</property>

<property>

<name>dfs.ha.automatic-failover.enabled.ns1</name>

<value>true</value>

</property>

<property>

<name>dfs.ha.fencing.methods</name>

<value>sshfence</value>

</property>

<property>

<name>dfs.ha.fencing.ssh.private-key-files</name>

<value>/home/hadoop/rsa</value>

</property>

<property>

<name>io.file.buffer.size</name>

<value>131072</value>

</property>

<property>

<name>dfs.namenode.name.dir</name>

<value>/data/hadoop-yarn/namenode.name.dir.1,/data/hadoop-yarn/namenode.name.dir.2</value>

<final>true</final>

</property>

<property>

<name>dfs.replication</name>

<value>3</value>

</property>

<property>

<name>dfs.blocksize</name>

<value>268435456</value>

</property>

<property>

<name>dfs.namenode.handler.count</name>

<value>100</value>

</property>

</configuration>

<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://10.4.19.44:8020</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/hadoop/hadoop-tmp</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>10.4.19.49:2181,10.4.19.50:2181,10.4.19.51:2181</value>
</property>
</configuration>
特别需要注意一点,dfs.namenode.shared.edits.dir配置的value是qjournal://10.4.19.49:8485;10.4.19.50:8485;10.4.19.51:8485/ns1,editslog存储位置在/data/journalnode/ns1/edits,这里适用的是nameservice1,即44和46节点适用的配置,相应的48和52节点,需要将ns1改成ns2,即不同的namenode,使用不同的journalnode地址

部署过程

1、启动zookeeper,这个比较简单,这里不多说了。

2、格式化zookeeper,目的是在zookeeper上建立namenode的状态znode,由于集群有两个namenode,它倆需要分别执行

bin/hdfs zkfc --formatZK,即在44节点(或者46)和48(或者52)节点分别执行

这时候你会看到zk上已经成功建立了znode,每个namenode有一个,分别是/hadoop-ha/ns1和/hadoop-ha/ns2:
3、启动journalnode,去我们选定的3台journalnode上执行:

sbin/hadoop-daemon.sh start journalnode,之后jps能看到JournalNode进程,查看日志可以发现journalnode正监听在8485端口
4、启动namenode,还记得上面的配置吗44,46互为主备,48,52互为主备。

我们44或者46上(主备随意)上执行格式化:

bin/hdfs namenode -format -clusterId beihai

这里我们给整个集群取个名字叫beihai(北海),注意,clusterId将成为集群元数据的一部分,dn注册的时候必须要clusterId一致才行。

格式化完毕之后,启动这个namenode,假设我们在44上操作,sbin/hadoop-daemon.sh start namenode

5、同步元数据,我们已经启动了44节点的namenode,那么与它互为主备的节点46不必也不能自己格式化,二是需要从44拖拽格式化好的元数据,在46节点上执行bin/hdfs namenode --bootstrapStandby

这时46根据hdfs-site.xml的配置知道要去44上拖拽元数据,44上已经架设好了rpc服务器,等待46的同步请求,46发起rpc同步请求,完成元数据同步,这里元数据包括fsimage+edits

元数据同步后,执行sbin/hadoop-daemon.sh start namenode启动46节点,注意这时候44和46页面上看到的都是(standby)状态:
原因在于这时候集群还没启动DFSZKFailoverController进程,但是集群配置了ha,所有当前属于未配置完毕状态,集群对外不可用。

48和52节点执行相同的操作,起来两个standby状态的namenode。

6、启动所有的datanode

注意如果之前系统启动过,namenode重新格式化需要把datanode配置的数据目录的VERSION文件清理掉,否则clusterId不拼配,dn找不到它认为合法的namenode,但是一定也要注意,如果是线上升级,切不可删除VERSION再启动,因为这样dn会把它上面的数据块全部清除掉。

datanode成功启动之后你会发现所有的namenode,4个目前处于standby状态的namenode都收到了这些datanode的心跳汇报。

7、启动DFSZKFailoverController监视进程

44,46,48,52节点都执行 sbin/hadoop-daemon.sh start zkfc

正常情况下,jps你会看到DFSZKFailoverController进程已经起来了。这时46成了active状态,44为standby;同样的,52成了active,48还是standby

我们再来查看zookeeper
每个nameservice对应的znode节点下有了神奇的内容,这些东西干啥用的,active怎么切换成standby的,后续再贴出详细解释。

这时候我们可以验证hdfs的可用性,通过put文件,可以发现只有配置了active namenode地址的客户端才能读写集群。

同时提醒状态为standby的节点不能执行相应的操作。

对于ha,我们可以做下面的测试,往一个nameservice put一个比较大的文件,目的是使put的时间足够长,然后干掉active namenode,我们观察3点:

1、standby是否切成了active状态

2、put操作是否受影响中断或者发生错误

3、如果put成功了,校验md5,检查数据是否损坏。

未完待续)

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇通过java操作Hadoop中zookeeper和.. 下一篇再理解HDFS的存储机制

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目