Voldemortのストア(テーブル)定義では、読込専用(readonly)を指定することが出来る。
Voldemortのストア(テーブル)定義では、読込専用(readonly)を指定することが出来る。
更新が無いので、効率よいアルゴリズムが使えるから高速になるということだと思う。
readonlyの説明(Javadocとか)では触れられていないが、読込専用のデータを作るには、データ作成用のプログラムを動かす必要があるようだ。このプログラムがHadoopを利用するようになっている。
Hadoopの出力はキーと値という形式であり、KVSであるVoldemortもキーと値を扱う。つまりHadoopの出力がそのままKVSに適用できるということなのかもしれない。
以下、Hadoopのチュートリアルでよく出てくるWordCountの出力結果を読込専用ストアにしてみる。
まず、読込専用のストアを定義しておく必要がある。
<stores> 〜 <store> <name>wordcount1</name> <persistence>read-only</persistence> <routing>client</routing> <replication-factor>1</replication-factor> <required-reads>1</required-reads> <required-writes>1</required-writes> <key-serializer> <type>string</type> </key-serializer> <value-serializer> <type>json</type> <schema-info>"int32"</schema-info> </value-serializer> </store> </stores>
WordCountの出力結果は単語(文字列)とその個数(数値)なので、ストアの型もそれに合わせる。
(実際にはWordCountの出力はタブ区切りの文字列だから、個数の方も文字列でも構わないんだろうけど。ストアを使う人から見れば、数値型の方が分かりやすいんじゃないかな)
また、読込専用ストアを使う為には、それを扱うクラスを有効にしておく必要がある。
〜 enable.readonly.engine=true file.fetcher.class=voldemort.store.readonly.fetcher.HdfsFetcher storage.configs=voldemort.store.bdb.BdbStorageConfiguration, voldemort.store.readonly.ReadOnlyStorageConfiguration
HdfsFetcherを入れておかないと、swap-store.shでHDFSを扱うことが出来ない。
ストアを定義してVoldemortを再起動すれば、ファイルシステム上に保存領域は勝手に作られる。
したがって、クライアントからアクセスすることは出来る。が、最初は何を取ってきてもnullだし、書き込むことも出来ない。
bin> voldemort-shell.bat wordcount1 tcp://localhost:6666
> get "Hello"
null
> put "Hello" 123
Exception thrown during operation.
voldemort.store.InsufficientOperationalNodesException: No master node succeeded!
↓サーバー側のログ
Exception in thread "voldemort-server-0" java.lang.UnsupportedOperationException : Put is not supported on this store, it is read-only. at voldemort.store.readonly.ReadOnlyStorageEngine.put(ReadOnlyStorageEngine.java:381)
Hadoopを起動し、WordCountを実行して、ストアに保存する元データを作成する。
(まぁたぶん、読込専用ストアを試したいだけなら、わざわざWordCountを実行しなくても、それらしい出力結果ファイルを手で作ればいいだけだけど^^;)
手順 | Cygwinから実行するコマンド |
---|---|
Hadoopの起動 |
$ cd /usr/local/hadoop $ bin/start-all.sh |
WordCountの実行準備 |
$ cd /home/hadoop/tutorial $ hadoop fs -put input/ wordcount/input $ hadoop fs -ls wordcount/ Found 1 items drwxr-xr-x - hishidama supergroup 0 2010-06-06 18:43 /user/hishidama/wordcount/input |
WordCountの実行 |
$ hadoop jar wordcount.jar jp.hishidama.hadoop.tutorial.WordCount wordcount/input wordcount/output |
WordCountの結果確認 |
$ hadoop fs -ls wordcount/ Found 2 items drwxr-xr-x - hishidama supergroup 0 2010-06-06 18:43 /user/hishidama/wordcount/input drwxr-xr-x - hishidama supergroup 0 2010-06-06 18:47 /user/hishidama/wordcount/output |
ストアへ取り込むプログラムでは、元データ(今回の例では、WordCountの出力結果)を読み込むクラスを自作する必要がある。
元データのファイル内の形式からストアに取り込む形式に自動的に変換することは出来ないから。
読み込みにはHadoopが使われるので、Mapperを作成することになる。
package jp.hishidama.sample.voldemort;
import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import voldemort.store.readonly.mr.AbstractHadoopStoreBuilderMapper;
public class WordCountImportMapper extends AbstractHadoopStoreBuilderMapper<LongWritable, Text> { @Override public Object makeKey(LongWritable key, Text value) { String line = value.toString(); String word = line.split("\t")[0]; return word; } @Override public Object makeValue(LongWritable key, Text value) { String line = value.toString(); String count = line.split("\t")[1]; return Integer.valueOf(count); } }
jarファイル | 備考 | |
---|---|---|
VOLDEMORT_INSTALL/dist/ | voldemort-contrib-0.80.2.jar | AbstractHadoopStoreBuilderMapper Eclipseのソースの添付は「C:/voldemort-0.80.2/contrib」 |
VOLDEMORT_INSTALL/contrib/hadoop-store-builder/lib/ | hadoop-0.18.1-core.jar | Hadoop本体(LongWritableやText等) 実際に実行に使うHadoopがこのバージョンでないなら、 対応したバージョン(HADOOP_HOMEにあるjarファイル) を使うべき。[2010-06-12] |
AbstractHadoopStoreBuilderMapperがファイルを読み込むMapper。
型引数は、ファイルを読み込んだ際の出力型なので、TextInputFormatと同じくLongWritableとTextになる。
ファイルの行ごとにmakeKey()とmakeValue()が呼ばれるので、ストアに格納したいキーと値の型に分割・変換して返す。
WordCountの出力結果はタブ区切りで単語と個数になっているので、makeKey()では単語を、makeValue()では個数部分を切り出している。
そして、個数は今回のストア定義では数値型(int32)にしているので、Integerに変換して返している。
実際に出力される際には、ストア定義のkey-serializerとvalue-serializerに従って自動的にシリアライズされる。
(上記の例では、makeValue()はIntegerを返しているが、value-serializerに則ってJSONのint32に変換される)
これを実行する際には(Hadoopのジョブだから)jarファイルになっている必要があるので、jarファイル化しておく。
作成する場所をVOLDEMORT_INSTALL/libの下にしておけば、自動的に起動シェル(起動バッチ)で読み込まれる。
また、起動時の引数でjarファイルの場所を指定することも出来る。
(Hadoopの分散環境で実行させることを考えれば、後者の方がいいだろう)
とりあえず「C:/cygwin/home/hadoop/tutorial/voldemort-sample.jar」としてみた。
読込専用ストアへ読み込ませるデータ(SequenceFile)を作成するには、hadoop-build-readonly-store.shを使う。
内部でHADOOP_HOME/bin/hadoopシェルを呼び出している為、Windowsから実行する際もバッチファイルにはせず、Cygwinから実行する。
環境変数HADOOP_CLASSPATHを使ってVoldemortのクラスパスを指定している為、別のシェル(HADOOP_HOME/conf/hadoop-env.shとか)でHADOOP_CLASSPATHを上書きしない(追加する)ようにしなければならない。
指定する引数input・output・tmpdirは、Hadoopの環境による。つまり単独環境ならローカルディレクトリーだし、擬似分散環境ならHDFSになる。
$ export HADOOP_HOME=/usr/local/hadoop
$ cd /cygdrive/c/voldemort-0.80.2/
$ bin/hadoop-build-readonly-store.sh \
--input wordcount/output \
--output voldemort/wordcount \
--tmpdir hadoop-readonly-tmp \
--mapper jp.hishidama.sample.voldemort.WordCountImportMapper \
--jar $(cygpath -m /home/hadoop/tutorial/voldemort-sample.jar) \
--cluster config/single_node_cluster/config/cluster.xml \
--storename wordcount1 \
--storedefinitions config/single_node_cluster/config/stores.xml \
--chunksize 1073741824 \
--checksum md5
2010/06/06 21:56:32 WARN cluster.Node: admin-port not defined for node:0 using default value(socket_port + 1):6667
2010/06/06 21:56:33 INFO mr.HadoopStoreBuilder: Data size = 26253, replication factor = 1, numNodes = 1, chunk size = 1073741824, num.chunks = 1
2010/06/06 21:56:33 INFO mr.HadoopStoreBuilder: Number of reduces: 1
2010/06/06 21:56:33 INFO mr.HadoopStoreBuilder: Building store...
2010/06/06 21:56:34 INFO mapred.FileInputFormat: Total input paths to process : 1
2010/06/06 21:56:34 INFO mapred.JobClient: Running job: job_201006062155_0001
2010/06/06 21:56:35 INFO mapred.JobClient: map 0% reduce 0%
2010/06/06 21:57:00 INFO mapred.JobClient: map 50% reduce 0%
2010/06/06 21:57:03 INFO mapred.JobClient: map 100% reduce 0%
2010/06/06 21:57:18 INFO mapred.JobClient: map 100% reduce 100%
2010/06/06 21:57:23 INFO mapred.JobClient: Job complete: job_201006062155_0001
$ hadoop fs -ls drwxr-xr-x - hishidama supergroup 0 2010-06-06 21:57 /user/hishidama/hadoop-readonly-tmp drwxr-xr-x - hishidama supergroup 0 2010-06-06 21:57 /user/hishidama/voldemort drwxr-xr-x - hishidama supergroup 0 2010-06-06 21:56 /user/hishidama/wordcount $ hadoop fs -ls voldemort/wordcount Found 1 items drwxr-xr-x - hishidama supergroup 0 2010-06-06 21:57 /user/hishidama/voldemort/wordcount/node-0
@rem Voldemort swap-storeバッチ by ひしだま 2010-06-06 @echo off setlocal set base_dir=%~dp0.. set CLASSPATH=%CLASSPATH%;%base_dir%/dist/* set CLASSPATH=%CLASSPATH%;%base_dir%/lib/* set CLASSPATH=%CLASSPATH%;%base_dir%/dist/resources java -Xmx128M -cp "%CLASSPATH%" voldemort.store.readonly.StoreSwapper %*
↓コマンドプロンプトから実行
> cd c:\voldemort-0.80.2
> bin\swap-store.bat ^
--cluster config/single_node_cluster/config/cluster.xml ^
--file hdfs://localhost:9000/user/hishidama/voldemort/wordcount ^
--name wordcount1
[2010-06-12 04:27:39,062 voldemort.cluster.Node] WARN admin-port not defined for node:0 using default value(socket_port + 1):6667
[2010-06-12 04:27:39,187 voldemort.store.readonly.StoreSwapper] INFO Invoking fetch for node 0 for hdfs://localhost:9000/user/hishidama/voldemort/wordcount/node-0
[2010-06-12 04:27:41,156 voldemort.store.readonly.StoreSwapper] INFO Fetch succeeded on node 0
[2010-06-12 04:27:41,156 voldemort.store.readonly.StoreSwapper] INFO Attempting swap for node 0 dir = C:\WINDOWS\TEMP\hdfs-fetcher\hdfs-fetcher\wordcount1_1276284461046\node-0
[2010-06-12 04:27:41,187 voldemort.store.readonly.StoreSwapper] INFO Swap succeeded for node 0
[2010-06-12 04:27:41,187 voldemort.store.readonly.StoreSwapper] INFO Swap succeeded on all nodes in 2 seconds.
> bin\voldemort-shell.bat wordcount1 tcp://localhost:6666 [2010-06-12 04:29:13,171 voldemort.client.DefaultStoreClient] INFO bootstrapping metadata. Established connection to wordcount1 via tcp://localhost:6666 > get 'Hello' version(): 3
--fileは、hadoop-build-readonly-store.shで指定した出力先(--output)の場所を絶対URI形式で指定する。
(ここでHDFSを使うので、server.propertiesでHdfsFetcherを指定しておく必要がある)
また、サーバー側でUNIXコマンド(whoami)を使っているので、voldemort-server.batを(コマンドプロンプトやエクスプローラーからでなく)Cygwinから起動しておく。
$ /cygdrive/c/voldemort-0.80.2/bin/voldemort-server.bat
swap-storeを実行すると、--fileで指定されたディレクトリー(HDFS)をローカルのTEMP/hdfs-fetcher/hdfs-fetcher/〜にコピーし、それをストアの実体に反映させているようだ。[2010-06-12]
反映後、「node-0」というディレクトリーは削除される。(「TEMP/〜/wordcount1_*」は残る…空っぽだから要らんのに(苦笑))
以下のようなエラーが出る場合、Hadoopのバージョンが違っているせいかもしれない。[/2010-06-12]
Exception in thread "main" voldemort.VoldemortException: voldemort.VoldemortException:
Swap request on node 0 (http://localhost:8081/read-only/mgmt) failed: Error while performing operation: Call failed on local exception
とりあえずはHDFSから直接読み込むのではなく、一旦ローカルディレクトリーに移したら出来るようだが。
$ mkdir -p /home/hadoop/voldemort $ cd /home/hadoop/voldemort $ hadoop fs -get voldemort/wordcount . $ ls -lR 〜 ./wordcount/node-0: total 3 -rwxrwxrwx 1 hishidama なし 45 2010-06-12 03:26 0.data -rwxrwxrwx 1 hishidama なし 100 2010-06-12 03:26 0.index -rwxrwxrwx 1 hishidama なし 16 2010-06-12 03:26 md5checkSum.txt
> cd c:\voldemort-0.80.2
> bin\swap-store.bat ^
--cluster config/single_node_cluster/config/cluster.xml ^
--file C:/cygwin/home/hadoop/voldemort/wordcount ^
--name wordcount1
[2010-06-12 03:41:49,640 voldemort.cluster.Node] WARN admin-port not defined for node:0 using default value(socket_port + 1):6667
[2010-06-12 03:41:49,765 voldemort.store.readonly.StoreSwapper] INFO Invoking fetch for node 0 for C:/cygwin/home/hadoop/voldemort/wordcount/node-0
[2010-06-12 03:41:49,921 voldemort.store.readonly.StoreSwapper] INFO Fetch succeeded on node 0
[2010-06-12 03:41:49,921 voldemort.store.readonly.StoreSwapper] INFO Attempting swap for node 0 dir = C:\WINDOWS\TEMP\hdfs-fetcher\hdfs-fetcher\wordcount1_1276281709875\node-0
[2010-06-12 03:41:49,953 voldemort.store.readonly.StoreSwapper] INFO Swap succeeded for node 0
[2010-06-12 03:41:49,953 voldemort.store.readonly.StoreSwapper] INFO Swap succeeded on all nodes in 0 seconds.
> bin\voldemort-shell.bat wordcount1 tcp://localhost:6666
[2010-06-12 03:43:13,171 voldemort.client.DefaultStoreClient] INFO bootstrapping metadata.
Established connection to wordcount1 via tcp://localhost:6666
> get 'Hello'
version(): 3
VoldemortにはVOLDEMORT_INSTALL/contrib/hadoop-store-builder/libにHadoopのjarファイルが入っているのだが、
Voldemort0.80.2の場合、hadoop-0.18.1-core.jarとなっている。[2010-06-12]
実行しているHadoopがそのバージョンでない場合(今回はHadoop0.20.2を使っていた)、バージョンが不一致なので何かが不整合になって例外が発生するようだ。
したがって、Voldemort起動用のVOLDEMORT_INSTALL/bin/voldemort-server.bat(voldemort-server.sh)のHadoopのライブラリーを、実行するバージョンのHadoopに置き換える必要がある。
voldemort-server.sh | voldemort-server.bat | |
---|---|---|
変更前 |
for file in $base_dir/contrib/hadoop-store-builder/lib/*.jar; do CLASSPATH=$CLASSPATH:$file done |
set CLASSPATH=%CLASSPATH%;%base_dir%/contrib/hadoop-store-builder/lib/* |
変更後 |
for file in $HADOOP_HOME/*.jar; do CLASSPATH=$CLASSPATH:$file doneちなみにJREのバージョンは1.6だから、 javaコマンドのクラスパスワイルドカードが使えるはずなんだけどね。 (シェルのfor文を使ってjarファイルを1つずつ指定しなくてもいい) |
if not defined HADOOP_HOME ( set HADOOP_HOME=C:/cygwin/usr/local/hadoop-0.20.2 ) set CLASSPATH=%CLASSPATH%;%HADOOP_HOME%/*もしくは set CLASSPATH=%CLASSPATH%;%HADOOP_HOME%/hadoop-0.20.2-core.jar |
下記のURIにアクセスすると、「Voldemort Administration」というタイトルの画面が開く。[/2010-06-12]
swap-storeを使う代わりに、手動で読込専用ストアのフェッチ(HDFSからローカルへのデータコピー)・スワップ(データ格納)が出来る。
(この画面の処理を行っているのはReadOnlyStoreManagementServletクラス)
http://localhost:8081/read-only/mgmt
HDFSに入っているデータ(SequenceFile)をローカルにコピーするメニュー。[2010-06-12]
手順 | 実施内容 | 備考 | ||||||
---|---|---|---|---|---|---|---|---|
データファイルのフェッチ |
C:\WINDOWS\TEMP\hdfs-fetcher\hdfs-fetcher\wordcount1_1276286512437\node-0 |
ブラウザーから実行する。 「Store」には(読込専用の)ストア名を選択する。 「Store Directory」にHDFSのパスを指定する。 成功すると、ローカルディレクトリーがフルパスで表示される。 このパスをSwap Data Filesメニューに指定する。 |
||||||
フェッチしたデータの確認 |
> cd C:\WINDOWS\TEMP\hdfs-fetcher\hdfs-fetcher\wordcount1_1276286512437 > dir node-0 2010/06/12 05:01 <DIR> . 2010/06/12 05:01 <DIR> .. 2010/06/12 05:01 45 0.data 2010/06/12 05:01 100 0.index |
ローカルにある元データ(SequenceFile)をVoldemortのDBに反映させるメニュー。[2010-06-12]
「Store Directory」には、元データのあるローカルのディレクトリーを指定する。HDFSは指定できない。
したがって、HDFSに作った元データを一旦ローカルにコピーする必要がある。
自分でbin/hadoopコマンドを使ってコピーしてもいいし、Fetch Data Filesメニューでコピーしてもいい。
手順 | 実施内容 | 備考 | |||||||
---|---|---|---|---|---|---|---|---|---|
元データの、HDFSからローカルへのコピー (hadoopコマンドでコピーする場合) |
$ mkdir -p /home/hadoop/voldemort $ cd /home/hadoop/voldemort $ $HADOOP_HOME/bin/hadoop fs -get voldemort/wordcount . $ ls -lR 〜 ./wordcount/node-0: total 3 -rwxrwxrwx 1 hishidama なし 45 2010-06-12 02:42 0.data -rwxrwxrwx 1 hishidama なし 100 2010-06-12 02:42 0.index -rwxrwxrwx 1 hishidama なし 16 2010-06-12 02:42 md5checkSum.txt $ echo $(cygpath -ma wordcount/node-0) C:/cygwin/home/hadoop/voldemort/wordcount/node-0 |
Cygwinから左記のコマンドを実行する。 「hadoop -fs -get」によってHDFSからローカルに元データをコピーする。 「ls」によってコピーされた事を確認し、 「cygpath」によってWindowsのパス名を確認する。 |
|||||||
データファイルのスワップ |
Swap completed. |
ブラウザーから実行する。 「Store Directory」にローカルディレクトリーを指定する。 成功すると、画面に「Swap completed」と表示される。 |
|||||||
テーブル内容の確認 | > cd \voldemort-0.80.2 > bin\voldemort-shell.bat wordcount1 tcp://localhost:6666 Established connection to wordcount1 via tcp://localhost:6666 > get 'Hello' version(): 3 > get 'Hadoop' version(): 2 |
クライアントシェルを(コマンドプロンプトから)起動して、ストアの内容を確認する。 (読取専用なので、バージョン情報は無いようだ) |
|||||||
ローカルディレクトリーの確認 | $ cd /home/hadoop/voldemort $ ls wordcount $ ls -l wordcount/ total 0 |
スワップを実行すると、スワップ元となったローカルディレクトリーは削除される。 |