ちょっと前々から気になっていた、NoSQL、Aerospikeで遊んでみました。
Aerospike
http://www.aerospike.com/
日本語の参考情報は、こちらに。
Aerospikeを採用した話
http://tech.im-dmp.net/archives/421
Aerospikeを採用した話2
http://tech.im-dmp.net/archives/1551
高速なNoSQLらしく、今月のWEB+DB PRESSにも載っていましたね。SSDに対しての最適化があるらしいですが、メモリでも普通にディスクも使えるようです。
OSSになったあたりから、ちょこちょこと気になっていたものです。
ま、さわりだけですけど、遊んでみました。クラスタ構成もできるようなのですが、今回は単一Nodeとします。
インストール
こちらのドキュメントを見ながら、インストール。
Install on Ubuntu
ww.aerospike.com/docs/operations/install/linux/ubuntu/
その他のOSは、こちらからリンクをたどってみてください。
Install Aerospike
http://www.aerospike.com/docs/operations/install/
で、自分の場合はUbuntuなので、以下のコマンドでインストール。
$ wget -O aerospike.tgz 'http://aerospike.com/download/server/latest/artifact/ubuntu12' $ tar -xvf aerospike.tgz $ cd aerospike-server-community-*-ubuntu12* $ sudo ./asinstall
このコマンドでは、Aerospike ServerとAerospike Toolsが入るようです。
起動。
$ sudo service aerospike start
Javaからアクセスしてみる
Aerospike Serverが起動したので、Javaからアクセスしてみます。
Introduction
http://www.aerospike.com/docs/client/java/
プログラムを書くのに記述した、Maven依存関係は以下のとおり。
<dependency> <groupId>com.aerospike</groupId> <artifactId>aerospike-client</artifactId> <version>3.1.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.1.0</version> <scope>test</scope> </dependency>
JUnitとAssertJはテスト用ですね。
で、先ほどのIntroductionに習ってまずはこんなコードを書いてみました。
src/test/java/org/littlewings/aerospike/AerospikeClientTest.java
package org.littlewings.aerospike; import java.util.stream.IntStream; import com.aerospike.client.AerospikeClient; import com.aerospike.client.Bin; import com.aerospike.client.Key; import com.aerospike.client.Record; import com.aerospike.client.policy.Policy; import com.aerospike.client.policy.QueryPolicy; import com.aerospike.client.policy.WritePolicy; import com.aerospike.client.query.Filter; import com.aerospike.client.query.RecordSet; import com.aerospike.client.query.Statement; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; public class AerospikeClientTest { @Test public void testAerospikeClientGettingStarted() { try (AerospikeClient client = new AerospikeClient("localhost", 3000)) { // String namespace = "my-namespace"; // デフォルトで、「test」というnamespaceが用意してある String namespace = "my-namespace"; String setName = "my-set"; Key key1 = new Key(namespace, setName, "key1"); Bin bin1 = new Bin("m1", "value1"); Bin bin2 = new Bin("m2", "value2"); WritePolicy writePolicy = new WritePolicy(); client.put(writePolicy, key1, bin1, bin2); Policy policy = new Policy(); Record record = client.get(policy, key1); assertThat(record.getString("m1")) .isEqualTo("value1"); assertThat(record.getString("m2")) .isEqualTo("value2"); assertThat(client.get(policy, new Key("test", "my-set", "key2"))) .isNull(); } } }
Aerospikeへの接続ポートは3000で、さらにデータ構造にアクセスするにはnamespaceとsetを指定する必要があるようです。データベースとテーブルに近いもの…かな…。
Data Model
http://www.aerospike.com/docs/architecture/data-model.html
管理単位としては、namespace、set、recordという感じらしいです。
また、データの保存先はnamespace単位で指定するようです。
で、プログラムを実行してみます。
com.aerospike.client.AerospikeException: Error Code 20: Namespace not found at com.aerospike.client.command.WriteCommand.parseResult(WriteCommand.java:72) at com.aerospike.client.command.SyncCommand.execute(SyncCommand.java:56) at com.aerospike.client.AerospikeClient.put(AerospikeClient.java:310) at org.littlewings.aerospike.AerospikeClientTest.testAerospikeClientGettingStarted(AerospikeClientTest.java:33)
エラーになりました。
今回、「my-namespace」というnamespaceを指定したのですが、先にnamespaceは作成しておく必要があるようです。
// String namespace = "my-namespace"; // デフォルトで、「test」というnamespaceが用意してある String namespace = "my-namespace";
Aerospikeはデフォルトで「test」というnamespaceが用意されており(あと、「bar」もあるみたい…)、こちらならすぐに使えますがここはnamespaceを追加してみます。
Namespace Configuration
https://www.aerospike.com/docs/operations/configure/namespace/
Add Namespace: Adding New Namespace
https://discuss.aerospike.com/t/add-namespace-adding-new-namespace/680
以下のファイルを編集します。
$ sudo vim /etc/aerospike/aerospike.conf
ここでは、単純に「test」namespaceの内容をコピーして作成しました。データの保存先は、メモリになります。
namespace my-namespace { replication-factor 2 memory-size 4G default-ttl 30d # 30 days, use 0 to never expire/evict. storage-engine memory }
この内容を、「/etc/aerospike/aerospike.conf」ファイルの1番したに追記しています。
編集したら、Aerospike Serverを再起動します。
$ sudo service aerospike restart
この状態でプログラムを実行すると、今度はうまく動くようになります。
Queryを実行してみる
続いて、今度はQueryを実行してみます。
Query Records
http://www.aerospike.com/docs/client/java/usage/query/query.html
こんなプログラムを書いてみます。
@Test public void testQuery() { try (AerospikeClient client = new AerospikeClient("localhost", 3000)) { String namespace = "my-namespace"; String setName = "query-set"; WritePolicy writePolicy = new WritePolicy(); IntStream .rangeClosed(0, 100) .forEach(i -> client.put( writePolicy, new Key(namespace, setName, "key" + i), new Bin("member", "value" + i))); Statement statement = new Statement(); statement.setNamespace(namespace); statement.setSetName(setName); statement.prepare(true); statement.setFilters( Filter.equal("member", "value1") ); QueryPolicy queryPolicy = new QueryPolicy(); try (RecordSet recordSet = client.query(queryPolicy, statement)) { while (recordSet.next()) { Key key = recordSet.getKey(); Record record = recordSet.getRecord(); assertThat(record.getString("member")) .isEqualTo("value1"); } } } }
実行。
com.aerospike.client.AerospikeException: Error Code 201: Index not found at com.aerospike.client.command.MultiCommand.parseGroup(MultiCommand.java:96) at com.aerospike.client.command.MultiCommand.parseResult(MultiCommand.java:71) at com.aerospike.client.command.SyncCommand.execute(SyncCommand.java:56) at com.aerospike.client.query.QueryExecutor$QueryThread.run(QueryExecutor.java:137) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
エラーになりました。どうやら、インデックスが必要なようです。
ちなみに、全件スキャンならインデックスはいらないらしく、以下の部分を削除すると動作するようになります。
statement.setFilters( Filter.equal("member", "value1") );
では、インデックスを作ってみます。
aql – Index Management
http://www.aerospike.com/docs/tools/aql/index_management.html
今回、「member」というものに対してQueryを投げようとしているので、
statement.setFilters( Filter.equal("member", "value1") );
ここに対してインデックスを貼ることにします。
aqlを起動。
$ aql Aerospike Query Copyright 2013 Aerospike. All rights reserved. aql>
インデックス作成。
aql> CREATE INDEX my-index ON my-namespace.query-set (member) STRING OK, 1 index added.
できました。
ここまですると、先ほどのQueryを投げるプログラムを動作させることができます。
Dockerイメージ
Docker HubにAerospike ServerのDockerイメージがあるので、こちらでも簡単に遊べます。
docker run -tid --name aerospike -p 3000:3000 -p 3001:3001 -p 3002:3002 -p 3003:3003 aerospike/aerospike-server
Dockerfileの雰囲気からすると、Aerospike ServerのみでAerospike Toolsは入ってなさそうな感じです。
https://registry.hub.docker.com/u/aerospike/aerospike-server/
この場合、「test」などの用意されているnamespaceしか使えない気がしますが、簡単に試すならこちらでもよいと思います。