HDP2.1からHDP2.5.3へアップグレードした

約1年前に別のHadoopクラスタをHDP2.1からHDP2.4にアップグレードした話はHadoopソースコードリーディング 第20回で発表しました。

Hadoopソースコードリーディング 第20回で発表してきました - wyukawa’s blog

このクラスタはデータソースがFluentdからのほぼ書き込みのみでバッチの数もazkabanのflowでいったら実質2個だったのでアップグレードは容易でした。

アップグレード方法はクラスタを新規に用意してFluentdから両方に書き込んでバッチも両方動かして、過去データはdistcpでコピーというやり方です。

今回はこれとは別のクラスタをアップグレードしました。

このクラスタの特徴は下記の通りです。

  • 各サービスのDBからsqoop importでデータを取ってくる。DBの数は50個以上
  • バッチの数が多い。azkabanでスケジューリングしているflowの数は100以上
  • 複数人でバッチ開発が行なわれている
  • Hiveで集計した結果を別DB(例:InfiniDB, Netezza)に書き込んでいる
  • Prestogres経由でBIツールで参照している
  • Fluentdは使っているがバックアップ用途なので事実上無視して良い。

今回もクラスタを新規に用意しています。
しかしデータを同時に両方に書き込んで、バッチを両方で動かすことはやりませんでした。
理由は、同時にバッチを動かすとサービス側のDBの負荷が2倍になることや、InfiniDB, Netezzaをさらに別途用意する必要があったからです。まあその辺はモックで騙す手はあったかもしれません。

新規クラスタを用意せずに休日に上書きアップグレードすることも考えましたが、マシンの保守切れが近いこともあってそれはやめました。

アップグレードしたかったもう一つの理由はHDP2.1付属のAmbariで構築するとresource managerがSPOFになるからというのもありました。

そんなわけでアップグレードをしたわけですが、下記のようにやりました。

  • HDFS SnapshotsとDistCpを利用したHDFSデータの差分更新を参考にしてsnapshotを使ってdistcpで差分コピー
  • 上記でコピーしている間もバッチは動いているのでデータは追加され続ける。その分はさらに差分コピーする
  • 差分が十分に少なくなった段階でバッチを止める。
  • 差分コピーして新旧クラスタでデータを同じ状態にする。
  • 新環境でバッチ開始

ざっくりいうとこんな感じですが、コピーの部分をもうちょっと詳しく書きます。

今回はhiveのdb単位で移行しました。
まず移行元でdb単位にhdfs snapshotを作成します。最初はs1

for db in ...
do
  sudo -u hdfs hdfs dfsadmin -allowSnapshot /apps/hive/warehouse/${db}.db
  sudo -u hdfs hdfs dfs -createSnapshot /apps/hive/warehouse/${db}.db s1
done

移行先でdistcpします。-mとか-bandwidthとかのネットワーク帯域に関してはネットワークチームの人と相談して決めました。

for db in ...
do
  sudo -u ... hadoop distcp ... -update hdfs://oldservice/apps/hive/warehouse/${db}.db/.snapshot/s1 /apps/hive/warehouse/${db}.db
done

ここでhdfs://oldserviceって書いてあるところがちょっと肝で、webhdfsを使っていません。というのも後述する差分コピーのhadoop distcp -update -diffでwebhdfsが使えないからです。

下記のように言われると思います。

The FileSystems needs to be DistributedFileSystem for using snapshot-diff-based distcp

そのため移行先のバッチサーバー(distcpを実行するマシン)の/etc/hadoop/conf/hdfs-site.xmlをいじって下記のようにして、hdfs://oldserviceとして移行元のHDFSを以降先から参照できるようにします。
なおoldserviceは適当につけた名前です。わかりやすければなんでもいいと思います。namenodeのホストやポートは環境に合わせて設定してください。

    <property>
      <name>dfs.nameservices</name>
      <value>..., oldservice</value>
    </property>

    <property>
      <name>dfs.client.failover.proxy.provider.oldservice</name>
      <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>
    
    <property>
      <name>dfs.ha.namenodes.oldservice</name>
      <value>nn3,nn4</value>
    </property>
    
    <property>
      <name>dfs.namenode.http-address.oldservice.nn3</name>
      <value>active-namenode:port</value>
    </property>

    <property>
      <name>dfs.namenode.http-address.oldservice.nn4</name>
      <value>stanby-namenode:port</value>
    </property>
    
    <property>
      <name>dfs.namenode.rpc-address.oldservice.nn3</name>
      <value>active-namenode:another-port</value>
    </property>

    <property>
      <name>dfs.namenode.rpc-address.oldservice.nn4</name>
      <value>stanby-namenode:another-port</value>
    </property>

最初のコピーは当然ですが、時間がかかります。僕の環境では3,4日かかりました。
時間を計算する際にはhadoop fs -du -hで出した容量を3倍するのはお忘れなく。

1回目コピーが終わったら差分コピーします。

移行元でsnapshot s2を作ります。

sudo -u hdfs hdfs dfs -createSnapshot /apps/hive/warehouse/${db}.db s2

移行先でsnapshot s1を作成してから差分コピーします。

sudo -u hdfs hdfs dfsadmin -allowSnapshot /apps/hive/warehouse/${db}.db
sudo -u hdfs hdfs dfs -createSnapshot /apps/hive/warehouse/${db}.db s1
sudo -u ... hadoop distcp ... -update -diff s1 s2 hdfs://oldservice/apps/hive/warehouse/${db}.db /apps/hive/warehouse/${db}.db

あとはこれを繰り返します。hiveのパーティション作成はmsck repair tableで一気に作れますが、パーティションの数が4000とかになってくると返ってこなかったです。
DDLはshow create tableで作りました。

ほかにやっかいなのは外部テーブルでhdfs://を使っているとselectできないことです。
https://issues.apache.org/jira/browse/HIVE-11116
っぽいですが、回避策がわからなかったのでwebhdfs://にしています。

そうすると今度はprestoでselectできないという問題があるのですが、jersey-bundle-1.19.3.jarを入れれば見れるというワークアラウンドはあります。
Google グループ


hive, sqoop周りでいじったのは下記です。


hive.auto.convert.join=false


sqoop import時にエラーになるのでambariでsqoop-site.xmlをorg.apache.sqoop.splitter.allow_text_splitter=trueに変更
Sqoop Import: "-Dorg.apache.sqoop.splitter.allow_text_splitter=true" - Hortonworks


カラム名にdateを使えなくなったのでambariでhive.support.sql11.reserved.keywords=falseに変更
hadoop - Using reserved words in Hive - Stack Overflow


アップグレード前がmapreduceだったのでそのままにしていたが以下のエラーに遭遇したバッチに関してはtezに変更
Solution for "Hive Runtime Error while processing row" (only on MR) - Hortonworks


ORA-00904がでたものは--split-byをやめて--queryや--boundary-queryを使うように変更


hivemallのsha1コメントアウト
question about hivemall install · Issue #331 · myui/hivemall · GitHub


あとはUNIONしてるクエリの間で型が違うエラーになるのでcastして合わせる。


他にもあった気がしますが、こんな感じです。


大事なことはアップグレードは週の初めにやることと翌日のバッチエラー対応は2人以上やることです。
間違っても金曜日にアップグレードをするのはお勧めしませんし、木曜日もやめたほうがいいです。バッファが1日しかないから。
今回は火曜日にアップグレードしました。

そんな感じです。ではでは。