本帖最后由 javaanddonet 于 2018-4-26 15:00 编辑
我看了很多帖子,大多数都是如下吗的这段描述,感觉都是互相复制的。我阅读完后,有以下几点疑惑,希望大佬给指点解惑。多谢~
社区的NN HA包括两个NN,主(active)与备(standby),ZKFC,ZK,share editlog。流程:集群启动后一个NN处于active状态,并提供服务,处理客户端和datanode的请求,并把editlog写到本地和share editlog(可以是NFS,QJM等)中。另外一个NN处于Standby状态,它启动的时候加载fsimage,然后周期性的从share editlog中获取editlog,保持与active的状态同步。为了实现standby在sctive挂掉后迅速提供服务,需要DN同时向两个NN汇报,使得Stadnby保存block to datanode信息,因为NN启动中最费时的工作是处理所有datanode的blockreport。为了实现热备,增加FailoverController和ZK,FailoverController与ZK通信,通过ZK选主,FailoverController通过RPC让NN转换为active或standby。 2.关键问题: (1) 保持NN的状态同步,通过standby周期性获取editlog,DN同时想standby发送blockreport。 (2) 防止脑裂 共享存储的fencing(我英文不行,这个fencing该怎么理解?查询了翻译软件,仍然难题理解,该怎么翻译这个词?),确保只有一个NN能写成功。使用QJM实现fencing,下文叙述原理。 datanode的fencing。确保只有一个NN能命令DN。HDFS-1972(这个又是什么?1972是什么?一本书名?)中详细描述了DN如何实现fencing (a) 每个NN改变状态的时候,向DN发送自己的状态和一个序列号。 (b) DN在运行过程中维护此序列号,当failover时,新的NN在返回DN心跳时会返回自己的active状态和一个更大的序列号。DN接收到这个返回是认为该NN为新的active。 (c) 如果这时原来的active(比如GC)恢复,返回给DN的心跳信息包含active状态和原来的序列号,这时DN就会拒绝这个NN的命令。(基于abc三点描述,我有一个疑问:意思是NN和DN心跳检测通讯的时候,每次都携带这个序列号吗? 假设我原先active NN的序号为1,standby NN的序列号此时也是1吗?应该是比1要小吧?不然两个NN都是1,DN也不知道哪个序列号大呀,一样大的,DN听谁的?所以我感觉应该是比1要小,我就暂时将standby NNd的序号标记为0。 现在active NN的序号为1,standby NN的序号为0,1>0, DN听从序号为1的NN的命令,也就是active NN的命令。 okay, 继续,那么此时active NN挂了,根据上面的描述,standby NN会代替active NN,并且返回给DN一个更大的序列号?那是几?比1要大,那是2?暂标记为2吧。那standby NN怎么知道要比1大呢?那他得知道active NN的序列号原先为1,问题:它是怎么知道的? 避免脑裂的关键来了:DN接到一个序号大于原先的1的NN的命令,也就是standby NN,那么DN认为此时的standby NN为acitve的NN。没问题,我能理解。但是如果原先挂掉的active NN恢复了,他的序列号还是原来的1,那就不能命令DN来干活了。也能理解。问题:如果standby的NN 挂掉了,此时该怎么办?active NN将自己原来的序列号1改变为比standby NN序列号2更大的?改为3吗?这两个NN之间是如何更改他们的序列号的呢?) (d) 特别需要注意的一点是,上述实现还不够完善,HDFS-1972中还解决了一些有可能导致误删除block的隐患,在failover后,active在DN汇报所有删除报告前不应该删除任何block。 客户端fencing,确保只有一个NN能响应客户端请求。让访问standby nn的客户端直接失败。在RPC层封装了一层,通过FailoverProxyProvider以重试的方式连接NN。通过若干次连接一个NN失败后尝试连接新的NN,对客户端的影响是重试的时候增加一定的延迟。客户端可以设置重试此时和时间。
|