2012年11月29日木曜日

ZK is null on connection event (HBase)

HBase clients (such as HBase shell) may throw an exception with a message "ZK is null on connection event" under some conditions, especially, in my case, on a slow machine.

This exception is raised when ZooKeeperWatcher (a part of HBase client) fails to connect to ZooKeeper in a certain period of time. The code snippet below is an excerpt from ZooKeeperWatcher.java.

// Now, this callback can be invoked before the this.zookeeper is set.
// Wait a little while.
long finished = System.currentTimeMillis() +
   this.conf.getLong("hbase.zookeeper.watcher.sync.connected.wait", 2000);
while (System.currentTimeMillis() < finished) {
  Threads.sleep(1);
  if (this.recoverableZooKeeper != null) break;
}
if (this.recoverableZooKeeper == null) {
  LOG.error("ZK is null on connection event -- see stack trace " +
    "for the stack trace when constructor was called on this zkw",
    this.constructorCaller);
  throw new NullPointerException("ZK is null");
}

We can see that this code is waiting for the milliseconds specified by the property hbase.zookeeper.watcher.sync.connected.wait or 2000 milliseconds (the default value) if the property is not set.

So, a simple solution to stop the exception is to set a long-enough value to the property in hbase-site.xml like below.

<property>
  <name>hbase.zookeeper.watcher.sync.connected.wait</name>
  <value>10000</value>
</property>

At least in my case, the above setting made the exception disappear.

2012年11月28日水曜日

yum リポジトリのセットアップ方法 (createrepo)

http://yum.baseurl.org/wiki/RepoCreate のさらっと訳です(「覚え書き」だけに)。

パッケージリポジトリのセットアップ方法

数多くの RPM パッケージ群を一箇所に集め、yum が動作するシステムに提供したいと思うことがあります。この作業はとても簡単です。

概要

yum が使用するパッケージリポジトリは、一つ以上の RPM と、それらの RPM の情報 (依存関係やファイルリストなど) へのアクセスを容易にする「メタ情報」を含む、単なるディレクトリです。yum はこのディレクトリに、FTP や HTTP、(NFS を含む) ファイル URI を用いてアクセスすることができます。

手順

  1. パッケージを一つのディレクトリに集めます。必要な数だけサブディレクトリを作成することができますが、それらをまとめるトップディレクトリが必要です。そこが、リポジトリを形成する場所となります。

  2. Yum は、各 RPM に格納されている情報をまとめた情報を使用します。この情報は createrepo プログラムで作成します。まだ createrepo がインストールされていなければ、次のコマンドでインストールできます。

    yum install createrepo

    RPM を使用していないマシン上にリポジトリを作ろうとしているなら、http://createrepo.baseurl.org/ から createrepo をダウンロードし、手作業でビルドとインストールをおこないます。

    インストール後、createrepo を実行する必要があります。必須の引数は一つで、リポジトリデータを格納するディレクトリを指定します。手順 1 で作成したパッケージディレクトリが /srv/my/repo だとした場合、次のコマンドを実行します。

    createrepo /srv/my/repo

    表示はどんどん流れていってしまいますが、エラーは起こらないでしょう。最終的に /srv/my/repo/repodata という名前のディレクトリが作成され、そこには少なくとも 4 つのファイルができますが、たぶんもっと多いでしょう。

  3. このリポジトリを yum に認識させるため、yum の設定に .repo ファイルを追加する必要があります。このリポジトリを使いたいシステム上で、/etc/yum.repos.d/ に新しいファイルを作成します。ファイル名は何でもよいですが、拡張子は .repo でなければなりません。仮にこのファイルを myrepo.repo としましょう。

    そのファイルに、次の内容を記述します。

    [myrepo]
    name = This is my repo
    baseurl = url://to/get/to/srv/my/repo/

    このファイルに対する編集作業は以上です。baseurl は、リポジトリへのパスです。当該マシンからリポジトリに直接アクセス可能であるか、もしくはそのリポジトリがファイルシステムとしてマウントされているのであれば、baseurl を次のように記述することができます。

    baseurl = file:///srv/my/repo/
        注意: file: の後ろのスラッシュは二つではなく三つです。

    HTTP もしくは HTTPS 経由でアクセスするなら、次のようになります。

    baseurl = http://servername/my/repo

    クライアント側のリポジトリ設定の詳細については yum.conf の man ページに記述されています。

  4. 以後、/srv/my/repo の変更や削除、新しい RPM パッケージの追加のたびに、リポジトリメタデータを作成しなおす必要があります。手順 2 と同様に createrepo でおこないます。

推奨オプション

単純に createrepo と打つだけでも動作しますし、ほとんどの場合それがもっとも互換性のあるやり方ですが、手元の yum クライアントが新しいものであることが分かっているのであれば、追加でオプションを指定することをお勧めします。

  1. --database

    サーバー側に .sqlite データベースを作成します。全てのクライアントの時間削減に寄与します。このオプションを使用しても何も不都合なことはおきません。というのは、古いバージョンの yum は .sqlite ファイルを無視して .xml ファイルを取得しにいくだけだからです。

  2. --unique-md-filenames

    これにより、全てのメタデータファイルが一意の名前を持つことになります。ミラーを使用している場合、このオプションは一番役に立ちます。ただし 3.2.10 より前のバージョンの yum では正しくクリーンアップできません。

  3. --changelog-limit

    ダウンロード時間を削減するため、changelog のエントリー数を制限します。

  4. --deltas --oldpackagedirs

    ダウンロード時間を削減するため、差分情報を作成します。このデータを活用するためにはクライアント側に yum-presto をインストールしておかなければなりません。

上級オプション

  1. createrepo --update

    リポジトリ内に大量のパッケージがあるとき、数個のパッケージを追加・変更するためだけに全パッケージのメタデータを再生成するのは、時間がかかりすぎます。このような場合は --update が便利です。これまで通りに createrepo を実行しますが、次のように --update オプションを渡します。

    createrepo --update /srv/my/repo

    これにより、メタデータの最終生成日時以降に変更・追加・削除のあった項目だけが更新されます。

  2. createrepo -x パッケージファイル名

    リポジトリディレクトリ内に幾つかパッケージがあるものの、疑うことも知らずにアクセスしてくる人達の目には触れさせたくない、と思ったとしましょう。createrepo コマンドで簡単にパッケージを除外することができます。
    createrepo -x filename -x filename2 -x filename* /srv/my/repo

  3. リポジトリ作成後、次のコマンドでリポジトリに署名することができます。

    gpg --detach-sign --armor repodata/repomd.xml

    これにより repodata ディレクトリ内に repomd.xml.asc ファイルが作成されます。新しい yum であれば、リポジトリのメタデータが、その GPG キーの所有者によるものであるかを検証することができます。

  4. 内部で使用するチェックサムを変更することができます。

    createrepo --checksum /srv/my/repo

    このオプションは、repodata を作成しようとしているマシンの Python のバージョンがクライアントのものよりも新しい場合(もしくは python-hashlib がインストールされている場合) のみ必要です。

createrepo によるパッケージリポジトリの生成・管理についてもっと知りたい場合は、createrepo の man ページ、もしくはこのドキュメント集の他の文書を参照してください。