Hadoop2.0中,HDFS实现了HA,具体实现及原理请网上搜索。其中HDFS的配置包含以下几个必须参数:
<property>
<name>dfs.nameservices</name>
<value>cdh5</value>
<description>指定HDFS的命名服务,一般和fs.defaultFS中的authority一致。</description>
</property>
<property>
<name>dfs.ha.namenodes.cdh5</name>
<value>nn1,nn2</value>
<description>指定HDFS集群中的NameNode(ID)。</description>
</property>
<property>
<name>dfs.namenode.rpc-address.cdh5.nn1</name>
<value>hadoop10:9000</value>
<description>第一个NameNode ID对应的host和端口号</description>
</property>
<property>
<name>dfs.namenode.rpc-address.cdh5.nn2</name>
<value>hadoop20:9000</value>
<description>第二个NameNode ID对应的host和端口号</description>
</property>
之前觉得当客户端需要连接NN时候,会从ZK中获取到处于Active状态的NN进行连接,但最近在做调试的时候发现并非如此,无论哪个NN处于Active状态,客户端总是先尝试连接nn2,当nn2处于Standby状态时候,便会抛出下面的错误:
Operation category READ is not supported in state standby. Visit https://s.apache.org/sbnn-error
错误原因很明显,就是尝试连接standby状态的nn进行数据读取。
尝试连接失败之后,接着才去连接nn1,成功。
问题是,明明我的Active NN是nn1,为何先要去连一下nn2?
通过网上搜索,找到了原因《HA集群中如何判断ActiveNN》。
http://jxy.me/2015/04/09/hadoop-ha-active-nn/
原来,客户端并不是连接到ZK去获取Active NN的,而是去尝试上面配置的两个NN。
既然是尝试所有NN,那么就有顺序的问题,上面的文章中通过分析源码找到的最终的答案,就是把nn1和nn2的host和端口放入HashMap,然后通过values()方法拿到一个”顺序”的NN来依次尝试。
类似下面的代码:
HashMap<String, String> map = new HashMap<String, String>();
map.put(“nn2″, “hadoop20:9000″);
map.put(“nn1″, “hadoop10:9000″);
for (String x : map.values()) {
System.out.println(x);
}
而HashMap的values()方法,是不保证顺序的,但经过尝试,上面的代码,在java7中运行,输出的顺序总是”hadoop10:9000,hadoop20:9000”,而在java8中运行,输出的顺序总是” hadoop20:9000, hadoop10:9000”,我的环境中使用了java8,因此一直是先尝试连接nn2.
更多精彩内容学习 点我学
这种寻找Active NN的策略,是通过参数dfs.client.failover.proxy.provider. [nameservice ID]配置的,默认为:org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
比较合适的做法,其实是自己实现一个代理类,去ZK中获取Active状态的NN,然后配置在这个参数值中。这个后续再研究。
HAOXUAN168 发布了49 篇原创文章 · 获赞 30 · 访问量 7万+ 私信 关注