How to convert non-HA NameNode to QJM HA on CDH4

CDH3から始めてCDH4.1までアップグレードして利用し続けていますが、この過程でNameNodeの構成は変更せずに運用してきました。
当然、CDH4からの公式HA構成に関心はあったのですが、複数の更新を同時に行うと危ないとか、英語マニュアル読むのめんどくせー感からミドルレンジに距離を置いていたところに、もりす先生がトライしてくれて、乗るしかないビッグウェーブ到来。待つべきものは他人の検証とはよく言ったものですなぁ。

タイトルはNameNode構成の切り替え、となっていますが、これから新しくQJM HAで組む人にも役に立つ内容となっていますゆえ、私が血反吐を吐いてまとめた情報を是非ご覧くださいませ。




リンク

  • CDH4.1におけるクォーラムベースジャーナリング
  • Quorum-Journal Design
  • CDH4.1オーバービュー
  • Software Configuration for Quorum-based Storage – Cloudera Support
  • HDFS High Availability Initial Deployment – Cloudera Support
  • HDFS High Availability Using the Quorum Journal Manager
  • CDH4 NameNode HA (QJM)でクラスタ構成 – tagomorisのメモ置き場
  • “namenode -bootstrapStandby” failed always
  • CDH4.0.0のNameNode HAを触ってみて
  • QJM構成でデバッグを有効にするとネームノードが起動しない件
  • HDFS-1073 Simpler model for Namenode’s fs Image and edit Logs


  • QuorumJournalManagerによるHA構成の選択理由

    CDHに触れ始めて1年が経過しますが、振り返ると大きな更新はそう多く行っていません。
    CDH3で始めて、勢いでCDH4デビューし、ImpalaのためにCDH4.1にしました。
    よって、いままでクラスタを停止したのは2回だけになります。

    この間は全て、NameNodeはDRBD+VIPによるエセ冗長化で構成していました。とはいえ、特にHDFSに障害が発生したこともなく平和に運用してきたわけですが、CDH4における最大の利点である(NFSじゃない)公式HA構成は捨てがたく、3度目のクラスタ停止を決意したわけです。

    DRBD+VIPによるエセHAで問題が発生したことはないため、当然、QJMを導入することに意味はあるのか考えるわけですが、検証後の私の結論としてはこのような感じです。

  • エセHAだとスタンバイ機の本稼働(=SafeMode Off)まで時間を要するが、QJM HAだとフェイルオーバー時に待機時間無しに稼働するため、真のホットスタンバイとなり片OSの停止が容易になる
  • もともとDRBDがあまり好きじゃなく、JournalNode×3 に十分な安定感・使いやすさを感じた
  • SecondaryNameNodeが不要となり、大容量メモリのサーバを1つ削減できる

  • 今からCDH4.1以降を導入する人はQJM HAで必ず組んだほうが良いと思いますし、イニシエのDRBD構成や、NFS HAを既に組んでいる場合は機を見て早めに済ませた方が長い目で見てよろしいかと思います。


    QJM HAの仕組みの要点

    細かい仕組みは公式を見ていただくとして、私なりの要点は

  • HDFSに書き込むとActiveNameNode(ANN)のローカルにeditsログが保存される
  • 続いて3台のJournalNode(JN)にeditsログが保存される
  • JNが2/3台以上あれば正常に稼働し続ける
  • JNが1/3台以下になるとANNが停止し、当然StandbyNameNode(SBN)も昇格できない
  • JN不足状態ではクライアントにエラーが返る場合もあれば、タイムアウトせず待機状態になり続ける場合もある
  • JN3台にはeditsログを主体として、更新時間も含めて全て同じデータが保存される
  • ANN, JNのeditsログは dfs.ha.log-roll.period 秒間隔でローテートされる(default:120)
  • SBNはJNからeditsログを取得して逐一メモリのメタデータを更新している
  • SBNは dfs.namenode.checkpoint.period 秒毎に旧SecondaryNameNode(SNN)と似たような処理が走るため、SNNは不要となる
  • SBNは定期的にfsimageのローカルへの保存とANNへの転送、editsログの掃除を行う
  • ANN, JNのeditsログはSBNの同期処理と同時に不要ログが削除されるが、残るeditsファイル数の条件は後述
  • クライアントはANN, SBNどちらかにアクセスし、SBNの場合はエラーになるのでANNにアクセスする
  • Hadoop Confを利用せず直接NNを指定するクライアントは独自対応する必要がある


  • non-HAからQJM HAへの移行手順

    DRBD+VIPで動いている状態からQJM HAへ変更する手順を記します。VIP周りの扱いは人それぞれだと思うので適当に濁して書きます。今回はマニュアルで言う手動フェイルオーバー(=独自スクリプトによる自動化)を採用しているため、Zookeeper関係は不要となっています。

    パッケージのインストール

    もともと存在していた NN×2 と SNN×1 にJournalNodeを入れます。hadoop-hdfs-zkfc, zookeeper, zookeeper-server は自動フェイルオーバーにのみ必要なので入れません。

    HDFSクラスタの停止

    クライアントからNNへのアクセスはVIPのみだったので、ここでVIPを破棄することでHDFSの利用を完全停止。HDFS利用の停止後はできればSNNの最後の同期を確認してからNN, SNNを停止したいところ。とはいえ、NNは停止したらfsimageが最新に更新されるので、無理にSNNを待つ必要はありません。

    バックアップ

    DRBD丸ごとで十分なのですが、損失したら終わるので少し過剰にとっておきます。

    NNのメタデータ

    SNNのメタデータ

    DRBD丸ごと

    DRBDをXFSにフォーマット

    データの復旧

    ここの解凍と下記のログの削除はANN,SBN両方で行います。メタデータ部分は後でANNからSBNへscpコピーすることでも可能です。

    hdfs namenode -bootstrapStandby というSBN準備用コマンドがありますが、現状では丸ごとデータコピーじゃないと動かないようです

    不要なeditsログの削除

    editsログなどが残っているとこんなエラーが出て正常に稼働しないので

    新構成開始時にあってはならないファイルを削除しておきます。

    /etc/hostsの編集

    今までは fs.defaultFS にVIPを指定していればVIPでLISTENしてくれたのですが、HA設定では基本的には静的アドレスでLISTENされるようになりました。Hadoop Confを利用するクライアントは自動的にANNを使ってくれるものの、FluentdやFUSEは基本無理なので、VIPを使う必要がありどうしたものかと。

    調べても真の仕様ははっきりしなかったのですが、こうすることで 0.0.0.0:8020 でLISTENすることに成功しました。
  • /etc/hosts に 0.0.0.0 hostname.domain.com hostname を記述する(他のhostnameを含む行はコメントアウトかこれより下に)
  • hdfs-site-xml の dfs.namenode.rpc-address.CLUSTER.SERVERID のホスト部分をhostnameを含むFQDNにする
  • この2点を満たさなければいけなく、裏技に近いです。この辺の仕様はNN起動時にINFOログを追うことでなんとなくつかめますが、VIP不要なら通常のhostsルールのままが良いと思います。

    core-site.xml

    1項目だけ変更します。以降の設定はクライアントも含めて全台に更新してください。

    hdfs-site.xml

    全て追記となります。
    ホストはDNS管理にしています。元はNNとSNNですが、NNとJNは別名で登録してみました。

    ログ設定

    QJM構成でデバッグを有効にするとネームノードが起動しない件 のため threshold を all ではなくinfo にしないとSBNがeditsログローテート時にダウンするため変更しておきます。log4j.xml の場合は

    そしてフェイルオーバー具合によってはクライアントからStandBy側へアクセスが一度行ってからActiveへ再アクセスするために、StandByに大量のログレベル:ERRORが残ることになります。

    おそらく容量的に厳しい量が保存されるので、ログにフィルターを追加しておきます。

    クラスタ起動


    JournalNode×3
    止めたりしたので全部起動します。

    ANN
    JNのログを初期化します。ログ関係が変になってお掃除するときもこのコマンドです。

    SBN
    起動するだけで、そのままStandByとなります。

    DataNode
    全台で起動します。

    ResourceManager, HistoryServer
    ジョブマネージャを起動します。

    NodeManager
    全台で起動します。

    確認

    QJM HAクラスタの動作確認事項は

  • クライアントから読み書きできる(hadoop fs, Hive, FUSE, Fluentd)
  • デフォルトで120秒間隔のeditsログのローテートタイミングでANN,SBNともに落ちない
  • SBNが dfs.namenode.checkpoint.period 秒毎にfsimageを正常に更新する
  • ANN, JNのeditsログがSBNの同期処理時に一定ファイル数を残して削除される(残るファイル数の条件は後述)
  • JNが2/3台になっても正常稼働し、3/3に戻しても同様である
  • フェイルオーバー(hdfs haadmin -failover master01 master02)させても上記動作確認がとれる

  • 最初はINFOログを残して確認するとよいです。


    editsログの保管条件

    だいぶ検証しましたが、情報の少なさもあり、まだ間違っているかもしれませんので、ご容赦を。

    トランザクションID

    HDFSへの書込番号みたいなものですが、一応おさらい
  • edits_0000000000002690663-0000000000002690674 のIDはSTART-ENDを表している
  • edits_inprogress_0000000000002690687 は今追記中のログでIDはSTART
  • seen_txid には今追記中のEND IDのみが記録されている
  • fsimage_0000000000002690500 はこのIDまで適用したという意味

  • 保管条件(=削除条件)

    時間単位とトランザクション単位の2つの条件を合わせた結果が保管条件となります。

    時間単位
    まずeditsログのローテートは dfs.ha.log-roll.period 秒間隔で行われます。
    default:120 なので、ANNとJNには2分で1ファイル作られていくことになります。

    次に dfs.namenode.checkpoint.period 秒毎にSBNから同期処理が走るので、default:3600 だと fsimage 2世代保存(dfs.namenode.num.checkpoints.retained : 2)の場合、最長で60分前と120分前まで適用されたfsimageができることになります。

    そしてこの古い方のfsimageの”120分前”までのeditsログが確実に保管されることになります。
    つまり、1ファイル2分なので、60ファイルです。

    トランザクション単位
    そこからさらに追加で、dfs.namenode.num.extra.edits.retained(default:1000000)トランザクション数を含むeditsログが確実に保管されます。例えば、1editsログ当り約10,000トランザクションとすると、100ファイル保管されることになります。

    これを時間単位と合わせると、60 + 100 = 160 で160editsログが残り、それより前のファイルは削除されていくことになります。
    だいぶわかりづらいですが、dfs.namenode.num.extra.edits.retained は最も古いfsimageに適用されたトランザクションIDより前のトランザクションをいくつ残すかの設定、ということです(ファイル数ではないです)。

    この例だと普通の残数になりますが、テスト環境などもっと書き込みが少ない場合を考えてみると、例えば 1editsログ(2分当り) に 10トランザクションしかない場合、時間単位の 60ファイル残 は同じですが、トランザクション単位で残るファイル数が 100,000 となり、NN, JNのデータディレクトリが大変なことになります。

    少なくともテスト環境では dfs.namenode.num.extra.edits.retained を少なくしておくべきですが、本番環境でも果たしてfsimageに適用済みのeditsログを多く残すことに意味があるかというと・・・あまりない気がします。ANNが落ちたらフェイルオーバーするし、SBNが落ちたらfsimage同期&editsログ掃除処理が走らないので、どうも公式設定マニュアルの説明はしっくりきていません。

    なので私としては 1,000 ~ 10,000 くらいにしておいて、気に食わなければ後でフェイルオーバーさせながらNN再起動して反映すればいいや、くらいに考えています。


    自動フェイルオーバー

    もともとVIPを利用していて、監視&独自フェイルオーバーをしていたので、手動コマンドである hdfs haadmin -failover をスクリプトに組み込むことで自動フェイルオーバーを実現しました。

    監視系統からのスクリプト実行などを組んでいない場合は、公式の自動フェイルオーバーの方が簡潔になるかもなので、マニュアルのZookeeper関連を入れる手順を続けて試し、ANNを落としたりして検証してみてください。


    メタデータのバックアップ

    これまでメタデータのアーカイブ化&転送はSNNで行っていました。が、SNNはなくなったので、バックアップはANN, SBN両方で走らせて、StandBy状態だったらバックアップ処理に入るようにしています。


    QJM HAの不満点

  • SERVER_IDが不明な条件ではローカルがANNなのかSBNなのか判断できないため、必要ならば設定ファイルと静的アドレスから判断することになる
  • Active/StandByの切り替わりによっては、クライアントからのリクエストが必ずStandByに出されてエラーを受けてからActiveで正常処理に入る場合がある。よってSBNへのエラーログ(ERROR … : Operation category WRITE is not supported in state standby)など無駄な処理が出ることになる
  • Hadoop Confを利用しないクライアントのことが考慮されていないため、VIPやDNSで独自に対応する必要がある



  • NameNodeのメモリ増設が必要になった時にHDFSクラスタの停止なしに運用できる、といった大きなメリットがあるため導入必須とは思いますが、予想していたよりも正しく構成するまで手間取ったのもあり、おいそれと導入したらいいよ!とは言い難いものがあります。(2つ目のテスト環境で検証し、1つ目のテスト環境で手順を確立し、本番でさらに手こずりました)

    まぁより強固になったのは事実だし、新年一発目の激しいウォーミングアップになったので、今年もより良質なブログにしていけるよう精進して参りたいと思います。よろしくお願いします。

    この投稿をHadoop Conference Japan 2013 Winterに捧げます
    外道父