CDH4 NameNode HA (QJM)でクラスタ構成
CDH4と延々格闘してたが、ようやくひととおり設定が終わったのでまとめ。
特にNameNode HA QJM版はドキュメントもけっこうグチャグチャで何をどうすればいいのかの把握が困難だった。また Auto Failover は設定するとマトモに動かなかったので無効にした。そのうち調べてもいいけど、実運用上も特に要らなそうだし、まあいいかな、と。
で、手順と設定のポイントについていくつか。なおNameNode Federationは使ってないので知らん。使うならクラスタ名の指定とかに影響があるはず。
セットアップ順序
基本的にはこのドキュメントを読む。
Redirecting...
が、通常のセットアップとの関係やどういう順序で全体を進行すればいいかがいまいちちゃんと書いてなくて不明なところが多い。簡単に概要をまとめると以下のようになる。パッケージ名はyumでのものなので適当に読み替えを。
- Journal用の3台にインストールするもの (うち2台はNameNode)
- NameNode用の2台にインストールするもの
- その他ノードにインストールするもの
これらは適当にインストールしておく。そのほか hive などは必要に応じて入れておく。またOS設定は最初にやっとく。
- limits変更
- kernel option変更
- vm.swappiness とか適当に /etc/sysctl.conf を変更したり sysctl -p したりする
- mount option変更
- noatime, nodiratime を有効にするようfstabに書く
- rebootがめんどうなら mount -o remount,noatime,nodiratime /path/to/mount
- resolv.conf をチェック
- この問題の対策をやっとく
設定を放り込む。内容についてはあとで。基本的に /etc/hadoop/conf とかから読めるようにしておくのと、必要な環境変数は /etc/hadoop/conf/hadoop-env.sh に書いておくのを忘れないこと。
各ノードの起動等を以下の順序でやる。journalnodeが動いてないと hdfs namenode -format が成功しない。またstandby側NameNodeの起動時注意事項についてはたぶんドキュメントのどこにも書いてない……と思う。
なお Auto Failover を結局やっていないのでZookeeper(やZKFC)要らない気はするんだけど、まあとりあえず入れとくといいと思う。心変わりするかもしれないし。
- Journal用ノード3台で zookeeper-server
- service zookeeper-server init
- service zookeeper-server start
- Journal用ノード3台で journalmanager
- active側namenodeで初期化と起動
- standby側namenodeの起動
- active namenodeの指定
2台目のNameNodeでは1台目からデータをコピってきて置いてやったらうまくいった。 @choplin さんにおしえてもらった。(2/2追記: 見付けられていなかったドキュメント に正確な方法があったようだ)
(2014/5/21追記:) ひさびさにクラスタを作ってたら、この -bootstrapStandby はこのエントリの記述時点では正常に動作しなかったようだ。ええええええ。まじかよ。HDFS HA構成のガイド は -bootstrapStandby だけでうまくいくみたいに書いてあるが Known Issues にうまくいかないからrsyncしろって書いてある。えええー。
で、試してみたら CDH4.4.0 ではダメで CDH4.5.0 以降だとちゃんと動いた。やれやれ。
(追記ここまで)
ここで書いている "master01" とか "master02" はコマンドのUsageを見ると
activeな側で port 50070 をブラウザから見るとちゃんと Active って書かれて QJM まわりのステータスなんかも出てくるので確認する。またWebHDFSは active のほうに繋がないと使えない。逆に言うと failover してactiveノードが切り替わったら、新しくactiveになった方に繋げばちゃんと使える。アクセス系はPowerDNSで切り替えてDNS based failoverやるかなあ。
QJMベースのHA設定について
zookeeper以外はほとんど hdfs-site.xml にまとまってるので、なんとかなる。頑張る。まず fs.defaultFS だけはこんな。
<!-- core-site.xml --> <property> <name>fs.defaultFS</name> <value>hdfs://hacluster</value> </property>
名前は適当につける。ここだけ変更したら、あとは hdfs-site.xml であれこれやっつける。
<property> <name>dfs.nameservices</name> <value>hacluster</value> </property> <property> <name>dfs.ha.namenodes.hacluster</name> <value>master01,master02</value> <!-- list of serviceId --> </property> <!-- dfs.namenode.rpc-address.CLUSTER.SERVICEID --> <property> <name>dfs.namenode.rpc-address.hacluster.master01</name> <value>master01.cdh4.local:8020</value> </property> <!-- dfs.namenode.http-address.CLUSTER.SERVICEID --> <property> <name>dfs.namenode.http-address.hacluster.master01</name> <value>master01.cdh4.local:50070</value> </property> <property> <name>dfs.namenode.rpc-address.hacluster.master02</name> <value>master02.cdh4.local:8020</value> </property> <property> <name>dfs.namenode.http-address.hacluster.master02</name> <value>master02.cdh4.local:50070</value> </property>
クラスタ名と serviceId をこういうふうにつける。dfs.ha.namenode.hacluster でリストアップしたノードごとに rpc-address と http-address を入れていく。まあ並べるだけですね。
<property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://master01.cdh4.local:8485;master02.cdh4.local:8485;master03.cdh4.local:8485/mycluster</value> </property> <property> <name>dfs.journalnode.edits.dir</name> <value>/disk01/dfs/jn</value> </property> <property> <name>dfs.client.failover.proxy.provider.hacluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property> <property> <name>dfs.ha.fencing.methods</name> <value>shell(/bin/true)</value> <describe> If you choose to use no actual fencing methods, you still must configure something for this setting, for example shell(/bin/true). </describe> </property> <property> <name>dfs.ha.automatic-failover.enabled</name> <value>false</value> </property> <property> <name>ha.zookeeper.quorum</name> <value>master01.cdh4.local:2181,master02.cdh4.local:2181,master03.cdh4.local:2181</value> </property>
dfs.namenode.shared.edits.dir でeditsを書き込むQJMのリストをURI形式で指定する。ホスト部をセミコロンで並べるのがだいぶ変な表記だけど。また dfs.ha.fencing.methods にはfailover時に本当に active になって良いかどうかのチェックに使う処理を記述する、が、まあ特にチェックすること無いよねって場合は常に成功するコマンドを指定しとけばいい。無指定はできないらしい。
そして dfs.ha.automatic-failover.enabled は false にしてZKFCは使わない。 ha.zookeeper.quorum という指定が混乱を招くが、これはたぶんjournalnodeまわりとは関係のない話、だと思う、たぶん。
基本的にQJM based HAの設定はこれで全部のはず。そんなに変なものは無い。
ログ設定
なんのことかというと、このエントリの問題ですが。その回避をしておく。
Yet Another HDIF? — QJM構成でデバッグを有効にするとネームノードが起動しない件
log4jの設定でDEBUG LOGを受け入れる設定になった状態だと standby namenode が起動しなくなる(すぐ落ちる)。これを回避するために log4j.properties で以下のように設定する。"all"とかになってると死亡。
log.threshold=info
自分の場合は設定として log4j.xml を使っていた。こちらのエントリの通りにして作ったやつ。
これだと以下のようになってしまっていた。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration threshold="all" xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender class="org.apache.log4j.ConsoleAppender" name="console"> <param value="System.err" name="target"/> <layout class="org.apache.log4j.PatternLayout"> <param value="%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n" name="ConversionPattern"/> </layout> </appender> <!-- 省略 --> <appender class="org.apache.log4j.RollingFileAppender" name="RFA"> <param value="${hadoop.log.dir}/${hadoop.log.file}" name="File"/> <!-- <param value="${hadoop.log.maxbackupindex}" name="MaxBackupIndex"/> --> <param value="5" name="MaxBackupIndex"/> <!-- <param value="${hadoop.log.maxfilesize}" name="MaxFileSize"/> --> <param value="10MB" name="MaxFileSize"/> <layout class="org.apache.log4j.PatternLayout"> <param value="%d{ISO8601} %p %c: %m%n" name="ConversionPattern"/> </layout> <filter class="org.apache.log4j.varia.StringMatchFilter" > <param name="StringToMatch" value="FileNotFoundException" /> <param name="AcceptOnMatch" value="false" /> </filter> <filter class="org.apache.log4j.varia.LevelRangeFilter"> <param name="levelMin" value="WARN"/> <param name="levelMax" value="FATAL"/> <param name="acceptOnMatch" value="true"/> </filter> </appender> <!-- 後略 --> <root> <appender-ref ref="RFA" /> <!-- <appender-ref ref="EventCounter"/> --> </root> </log4j:configuration>
これだと RFA で LevelRangeFilter に WARN から FATAL を指定してるんでいいかと思ってた、ら、先頭のほうのこれがひっかかってた。
<log4j:configuration threshold="all" xmlns:log4j="http://jakarta.apache.org/log4j/">
こいつを "info" に変更してnamenodeふたつを再起動したら対処完了。
以上!