HDFS Multiple Standby的优化实践
Posted Android路上的人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDFS Multiple Standby的优化实践相关的知识,希望对你有一定的参考价值。
文章目录
- 前言
- Multiple Standby的checkpoint行为影响
- Client failover retry行为优化
- Block access token的变化
- Multiple Standby的failover失败问题
前言
在前面的文章中,笔者介绍过一篇关于介绍HDFS Multiple Standby功能的原理文章(HDFS Multiple Standby原理分析)。从代码改动来看,HDFS Multiple Standby并没有对NameNode的核心机制做大的改动,而是进行了多Standby模式的一个适配。关于Multiple Standby这个功能本身,它确实能够增强NameNode服务的整体可靠性。假设我们使用普通性能的机器部署NameNode这样的核心服务时,这种对于服务的可靠性要求就很关键了,在这种情况下Multiple Standby无疑将会发挥很大的作用。从再长远的角度来看,我们甚至能够利用多Standby NN来提供对外的读请求服务,以此来减少主NN的压力。总的来讲, Multiple Standby这个功能还是有着恨着很高的使用价值,本文笔者来简单聊聊我们内部在这段时间对这个功能进行的一些实践分享,包括这个功能本身还存在的一些问题点。
Multiple Standby的checkpoint行为影响
之前文章也介绍过Multiple Standby相较于原先HA主备模式最大的一个区别是它内部的checkpoint行为的改动。在Multiple Standby下会有多个Standby NN能够同时向Active NN进行fsimage的传送。尽管Multiple Standby功能实现里通过新增checkpoint quiet的时间判断优化fsimage upload行为,但是为了避免依然潜在的频繁fsimage上传行为,我们内部对相关的checkpoint参数进行了调整。
目前Standby NN中控制checkpoint行为的影响条件有下面2个:
boolean needCheckpoint = lastCheckpointTime >= checkpoint period || uncheckpointed txn >= txn count
通常我们知道的是checkpoint的时间,往往忽略的是这里transaction的控制。尤其当集群RPC压力很大的时候,第二个条件往往会优先成为触发checkpoint的行为。在NN里会有下面的log表示checkpoint行为由transaction所触发。
org.apache.hadoop.hdfs.server.namenode.ha.StandbyCheckpointer: Triggering checkpoint because there have been 15431844 txns since the last checkpoint, which exceeds the configured threshold 15000000
我们内部按照Multiple Standby中Standby NN的数量,进行checkpoint时间和transaction数阈值的等倍放大,以此保证在Multiple Standby模式下,Standby NN向Active NN上传FSImage的频率基本保持不变。
相关配置如下:
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>xxx</value>
</property>
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>xxx</value>
</property>
另外一个与checkpoint密切相关的行为是Active NN的log roll行为。我们知道,Active NN上的log roll行为是Standby NN定期所触发的。在Multiple Standby NN情况下,多个Standby NN会同时向Active NN发起log roll的命令,这样带来的结果是Active NN这边会看到更多的finalized editlog文件。如下所示:
-rw-r--r-- 1 hdfs hdfs 42 Dec 13 02:52 edits_0000000000173384510-0000000000173384511
-rw-r--r-- 1 hdfs hdfs 42 Dec 13 02:52 edits_0000000000173384512-0000000000173384513
-rw-r--r-- 1 hdfs hdfs 42 Dec 13 02:55 edits_0000000000173384514-0000000000173384515
-rw-r--r-- 1 hdfs hdfs 42 Dec 13 02:55 edits_0000000000173384516-0000000000173384517
默认情况,Active NN的log roll行为2分钟一次,如果有2个Standby NN都配置了2分钟的log roll间隔,那就会出现2分钟2次log roll的情况,就是上图出现的情况。因此log roll的时间也应该做相关的调整,相关配置为:dfs.ha.log-roll.period。
Client failover retry行为优化
在Multiple Standby的功能实现里,绝大部分的改动都集中的Server端的改动,但对于Client这边的改动几乎没有。因为在设计上来说,确实不管是1个Standby还是多个Standby NN模式,Client最终都是能找到Active NN并且进行数据的读写访问的。简单来说,就是Multiple Standby这个功能是完全兼容Client的,当Client不去升Hadoop包只改动conf的情况下。
但我们在实际Client行为测试的时候,还是发现了下面2个问题。
第一个问题是Client的频繁failover行为。我们内部配置的是ConfiguredFailoverProxyProvider这个类来进行Client failover行为的控制。这个类在寻找Active NN采用的顺序比较固定,总是会从第一个NN开始进行访问,直到访问到的NN是Active NN为止。于是这里有个极端情况,当目前的Active NN是NN列表里的最后一个NN的时候,前面就会访问到(NN数-1)个Standby NN
。每访问一个Standby NN,Client就会收到StandbyException的异常然后进行下一次failover重试。在每次failover后,还会进行一定时间的sleep等待,显然这样的方式是很低效的。
21/12/09 02:43:08 INFO retry.RetryInvocationHandler: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.ipc.StandbyException): Operation category READ is not supported in state standby
at org.apache.hadoop.hdfs.server.namenode.ha.StandbyState.checkOperation(StandbyState.java:87)
at org.apache.hadoop.hdfs.server.namenode.NameNode$NameNodeHAContext.checkOperation(NameNode.java:2066)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkOperation(FSNamesystem.java:1531)
at ….
, while invoking ClientNamenodeProtocolTranslatorPB.getFileInfo over xx.xx.xx.xx:xxxx after 1 failover attempts. Trying to failover after sleeping for 1211ms.
第二个问题是Client log的问题,目前Client对第一次failover的行为是做了容忍处理的,容忍错误log的打印,而且它不会进行failover sleep等待。相关代码如下:
RetryInvocationHandler.java
private void log(final Method method, final boolean isFailover,
final int failovers, final long delay, final Exception ex)
// log info if this has made some successful calls or
// this is not the first failover
final boolean info = hasMadeASuccessfulCall || failovers != 0;
if (!info && !LOG.isDebugEnabled())
return;
...
RetryPolicies.java
/**
* @return 0 if this is our first failover/retry (i.e., retry immediately),
* sleep exponentially otherwise
*/
private long getFailoverOrRetrySleepTime(int times)
return times == 0 ? 0 :
calculateExponentialTime(delayMillis, times, maxDelayBase);
这个很好理解,因为HA模式只有2个节点,第一个节点如果是Stanby的话,那么下一个节点就是Active了,所以没有必要进行异常错误的输出并且failover等待了。但是在Multiple Standby模式下,是最多可能出现Standby数的failover行为。如果我们还是只容忍第一次的failover行为的话,就会出现第二次failover的错误信息以及retry等待行为。
笔者在测试的时候,频繁遇到failover错误信息的情况,尽管最终还是能访问到数据的,但体验非常不好,而且还可能造成log flood。
$ /apache/hadoop//bin/hadoop fs -ls /xxx_dir
21/12/09 02:43:08 INFO retry.RetryInvocationHandler: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.ipc.StandbyException): Operation category READ is not supported in state standby
at org.apache.hadoop.hdfs.server.namenode.ha.StandbyState.checkOperation(StandbyState.java:87)
at org.apache.hadoop.hdfs.server.namenode.NameNode$NameNodeHAContext.checkOperation(NameNode.java:2066)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkOperation(FSNamesystem.java:1531)
at ….
, while invoking ClientNamenodeProtocolTranslatorPB.getFileInfo over xx.xx.xx.xx after 1 failover attempts. Trying to failover after sleeping for 1211ms.
Found 1 items
drwxrwxrwx - hdfs hadoop 0 2021-05-19 06:29 /xxx_dir
但显然Multiple Standby的failover语义已经和原先HA模式的相违背了,在Multiple Standby模式下,Client应该要能够容忍first failover到一个NN失败的情况。
面对上面2个问题,我们做了下面3个优化改动:
- 引入社区client random failover选择的改进,开启random选择模式后,client就不会每次按照固定的顺序进行Active的查找了,相关JIRA:HDFS-6648。
- 跳过failover错误输出,按照节点维度来进行failover错误的容忍,这个优化也是来自于社区,相关JIRA: HADOOP-17116.
- 在第二点改动的基础上,我们内部对failover的sleep行为做了改进,当failover失败发生在第一次访问到的节点时,不进行sleep的等待。现有逻辑只按照failover次数做判断是存在问题的。
Block access token的变化
Multiple Standby实现中另外一块的变化是block access token的变动。在原先HA主备模式里,token key的划分是2段式的,Active NN和Standby NN各占据一半区间段的key值。
this.serialNo = (serialNo & LOW_MASK) | (nnIndex << 31);
在多Standby场景,要保证key值不重叠,这里改变了原先的计算方式,按照指定区间range的计算方法,
this.intRange = Integer.MAX_VALUE / numNNs;
public synchronized void setSerialNo(int serialNo)
this.serialNo = (serialNo % intRange) + (nnRangeStart);
我们看上面改动前的方法和改动后的方法,它的本质核心都是让各个NN拥有自己独立的区间段去生产一个token key来进行access token的生成。另外这个key会通过DN的心跳由NN发给DN,然后DN通过收到的这个key值做token有效性的验证。
TokenID = expirationDate, keyID, ownerID, blockID, accessModes
这里关于Multiple Standby的token改动的逻辑笔者认为到是没什么问题,但是这里有个key重叠的特殊情况需要考虑:当我们的集群从HA模式原地升级到多Standby,1个Active模式时,是否会存在key重叠的问题。这个情况是说老的Active,Standby NN依然在使用2段式区间内的值,而新的Standby已经配置成多Standby模式。那么这个时候,原先HA里第二个NN的key区间是可能与多Stanby内使用的key出现重叠的情况的。那么这个key重叠会不会引发后续DN访问block的失败以及其他潜在的问题?关于这点,社区的设计文档中也没有提及到这个问题。
为了避免上面这个问题,我们推荐的Multiple Standby部署方式是:先用最新配置(拥有多Standby NN的配置)升级老的Active/Standby NN,然后再加入新的Standby NN,以此保证key使用的区间段是区分开的。这个细节还是需要注意一下,假设我们的集群是开了block access token验证的话。
Multiple Standby的failover失败问题
笔者在测试Multiple Standby功能的时候还遇到了一次failover失败问题。这个failover问题发生的场景比较特别,发生在我们刚刚加入新的Standby到老的HA的集群里,步骤如下:
1)老的Active(nn1),Standby NN(nn2)正常服务,但是还不知道另外新的Standby NN的存在
2)新的Standby NN(nn3)通过最新配置已经重启成功
3)这个时候我们进行nn1到nn2的正常failover,然后failover失败了
我们后来在分析这个问题的时候,发现这是因为当failover发生的阶段,nn2和nn3都在尝试着成为Active,因为这里我们在nn1上跑的程序并没有通知到nn3,让它暂时别竞选成为active。然后在nn1退出它当前Active身份的时候,nn3立马监控到了当前集群无Active NN的情况,然后它就尝试让自己变成了Active。
归根结底这个问题的本质还是老的NN节点没有事先提前配置成多Standby的模式,导致中间出现一些信息的gap。像这种情况还可能会造成出现2个Active的脑裂问题,因此在这里Multiple Standby的升级步骤还是得需要注意一下,避免出现一些不必要的问题。
以上就是本文分享的关于HDFS Multiple Standby的实践经验。
以上是关于HDFS Multiple Standby的优化实践的主要内容,如果未能解决你的问题,请参考以下文章
HDFS之存储优化纠删码原理纠删码案例实操 异构存储(冷热数据分离)