Apache ZooKeeperのトランザクションログとスナップショットの運用と削除

Zookeeperのトランザクションログの運用

Hadoopと組み合わせて使用されるZooKeeperは、タイミングが非常に重要な高可用性の分散協調システムです。NTPを設定してログの時刻ずれが無いように設定しておく必要があります。また、Zookeeperのトランザクションログとスナップショットは別のディスクドライブに保存することが望ましいとされています。ログが頻繁に書き込まれるため、I/O性能の良いSSDなどのフラッシュストレージに保存しておくことが望ましいです。これらはdataDirおよびDataLogDirプロパティによって設定が可能です。Zoopkeeperのトランザクションログが一定の設定値(デフォルト64MBまたは100,000回)以上に書き込まれると、znodeツリーのメモリダンプであるスナップショットが作成されます。スナップショットは基本、それ以前のトランザクションログに代替するものです。

トランザクションログ・スナップショットの削除

ZoopKeeperの標準状態ではトランザクションログやスナップショットも含めて削除されません。しばらく放っておくと膨大なデータが蓄積されてしまうことになります。また、このログは基本スケールアップできません。NFS上に置くなどいくつかの解決策はありますが、ログのクリーンアップを行うのが現実的かと思います。

ログのクリーンアップ方法

Apache Hadoopを使用している場合、ログは公式マニュアルに載っている以下のコマンドをcronに登録しておくことで毎日削除できます。 の値は3より大きい方が良いようです。

java -cp zookeeper.jar:log4j.jar:conf org.apache.zookeeper.server.PurgeTxnLog [dataDir] [snapDir] -n [count]

org.apache.zookeeper.server.PurgeTxnLogクラスの構成

org.apache.zookeeper.server.PurgeTxnLogクラスは、以下のメソッドで構成されています。

purge

public static void purge(File dataDir,
File snapDir,
int num)
throws IOException

purges the snapshot and logs keeping the last num snapshots and the corresponding logs.

パラメータ:
dataDir – the dir that has the logs
snapDir – the dir that has the snapshots
num – the number of snapshots to keep
例外:
IOException

main

public static void main(String[] args)
throws IOException

パラメータ:
args – PurgeTxnLog dataLogDir dataLogDir — txn log directory -n num (number of snapshots to keep)
例外:

パラメータとしてはdataDir、snapDir、countだけしかないです。countは公式マニュアル通り3で問題ないと思います。最悪の場合、3世代までさかのぼれるので。運用見合いで過去のスナップショットが重要な場合はcountを大きくされた方が良いと思います。ちなみスナップショットはそれ以前のログに置き換わるものなので、上記コマンドで現行のトランザクションログのオープンに失敗するケースはないと思います。

ClouderaのHadoopとZooKeeper構成の場合

ClouderaのHadoopとZooKeeper構成の場合は、ログの削除にはzkCleanup.shを使用するのが良いようです。これは通常、${ZK_HOME}/bin/zkCleanup.shのパスに配備されています。このコマンドを下記のように叩きます。

/usr/lib/zookeeper/bin/zkCleanup.sh -n 3

これでClouderaのZooKeeperでログの削除が行えます。

zkCleanup.shの構成

zkCleanup.shの構成ですが、中身としてはこんな感じになっているようです。

# use POSTIX interface, symlink is followed automatically
ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN=`dirname ${ZOOBIN}`
ZOOBINDIR=`cd ${ZOOBIN}; pwd`

if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
  . "$ZOOBINDIR"/../libexec/zkEnv.sh
else
  . "$ZOOBINDIR"/zkEnv.sh
fi

ZOODATADIR=$(grep "^[[:space:]]*dataDir=" "$ZOOCFG" | sed -e 's/.*=//')
ZOODATALOGDIR=$(grep "^[[:space:]]*dataLogDir=" "$ZOOCFG" | sed -e 's/.*=//')

if [ "x$ZOODATALOGDIR" = "x" ]
then
$JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
     -cp "$CLASSPATH" $JVMFLAGS \
     org.apache.zookeeper.server.PurgeTxnLog "$ZOODATADIR" $*
else
$JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
     -cp "$CLASSPATH" $JVMFLAGS \
     org.apache.zookeeper.server.PurgeTxnLog "$ZOODATALOGDIR" "$ZOODATADIR" $*
fi

基本org.apache.zookeeper.server.PurgeTxnLogのラッパーのようですが、一部環境変数の読み込みに違いがあります。