- -copyright Fringe81 Co.,Ltd.
Aerospike Tech Deep Dive
v3新機能 Large Data Typesを中心に
- -copyright Fringe81 Co.,Ltd.
・@mtoyoshi
・Fringe81
・Java, Scala
・アドテク畑
 DSP→DMP→ADNW
・Aerospike歴1年
自己紹介
- -copyright Fringe81 Co.,Ltd.
Aerospikeは...
速い
運用コストが低い
スケーラビリティ高い
etc...
- -copyright Fringe81 Co.,Ltd.
インフラ的な話が多い?
今日はプログラミング話
- -copyright Fringe81 Co.,Ltd.
2015/04 Aerospike行ってきた
- -copyright Fringe81 Co.,Ltd.
ステーキの写真
- -copyright Fringe81 Co.,Ltd.
クライアントライブラリ
新機能の実装優先度
- -copyright Fringe81 Co.,Ltd.
1st Priority
- -copyright Fringe81 Co.,Ltd.
2nd Priority
- -copyright Fringe81 Co.,Ltd.
Aerospike
↓
アドテク?
↓
Scala??
- -copyright Fringe81 Co.,Ltd.
Aerospike Community Labs
http://www.aerospike.com/community/labs/
- -copyright Fringe81 Co.,Ltd.
大体の使い方を知るには
サンプルプログラムを読む/実行する
のが手っ取り早い
あと
ドキュメントが充実してきている
- -copyright Fringe81 Co.,Ltd.
https://www.aerospike.com/docs/operations/install/vagrant/mac/
- -copyright Fringe81 Co.,Ltd.
http://localhost:8081
- -copyright Fringe81 Co.,Ltd.
% vagrant ssh
$ cd ClientInstall
$ ./as_java_install.sh
$ cd ~/aerospike-client-java-3.1.2/examples
$ ./run_examples all
- -copyright Fringe81 Co.,Ltd.
- -copyright Fringe81 Co.,Ltd.
ここまで
30分で出来た
※Vagrant自体のインストールは除く
- -copyright Fringe81 Co.,Ltd.
GitHubで公開されている
clientライブラリにも
examplesが同梱
但しクライアントライブラリ(プログラミング言語)
によってexamplesの充実度が異なる
※例えばLDTsはrubyやphpには2015/06時点で
無かったり一部だったり
※充実度ではJavaが一番良さそう
- -copyright Fringe81 Co.,Ltd.
基本の「保存」&「検索」
- -copyright Fringe81 Co.,Ltd.
client.put(
new WritePolicy(),
new Key(“namespace”, “setname”, “key1”),
new Bin(“num”, 1),
new Bin(“bool”, true));
Bin部は可変長引数
- -copyright Fringe81 Co.,Ltd.
getBooleanとgetObjectで挙動が異なる
Record record =
client.get(
new Policy(),
new Key(“namespace”, “setname”,“key1”),
“num”);
int n = record.getInt(“num”); // 1
boolean b = record.getBoolean(“bool”); // false
Object o = record.getValue(“bool”); // null
- -copyright Fringe81 Co.,Ltd.
Serializableを実装している
任意のクラスも保存可能
Record#getList
Record#getMap
はない
Record#getObject
を使用してダウンキャスト
boolean
int
long
float
double
String
List
Map
Object
byte[]
- -copyright Fringe81 Co.,Ltd.
msgpackの
仕様に基づき
シリアライズ
されて保存
- -copyright Fringe81 Co.,Ltd.
val list = List(“x”, “a”, “c”)
list :+ “f” // 追加
list.dropWhile(_ == “a”) // 削除
list.find(_ == “c”) // 検索
list.sorted // ソート
Aerospike上にListが保存されていても
プログラミング言語のListのように
1要素だけ追加とか出来ない
取得→Listの操作→保存
Scala
- -copyright Fringe81 Co.,Ltd.
でも
ver.3から
できる
- -copyright Fringe81 Co.,Ltd.
ver.3から
Aerospike DBとして
List / Set / Map / Stackを
サポート
それが
Large Data Types(LDTs)
- -copyright Fringe81 Co.,Ltd.
LargeList llist =
client.getLargeList(
writePolicy,
key,
binName);
llist.add(Value.get(“z”))
getLargeList時点では通信は発生しない。
“z”だけの追加が可能。
- -copyright Fringe81 Co.,Ltd.
add / update
scan / find / range / filter
remove / destroy
size
LargeListはkeyのASCでソートされる
O(logN)の探索となる
LargeListのメソッド
- -copyright Fringe81 Co.,Ltd.
llist.add(Value.get(“a,99”));
llist.add(Value.get(“b,1”));
これだと文字列順でa,bとソート
- -copyright Fringe81 Co.,Ltd.
上記だとkeyの数字順でb,aとソート
※“key”が特殊な意味を持つ
Map<String,Value> m = new HashMap<>();
m.put(“key”,Value.get(99));
m.put(“value”, Value.get(“a,99”));
list.add(Value.get(m));
※もう1つは省略
- -copyright Fringe81 Co.,Ltd.
どうやって1要素だけの
差分追加等を実現しているのか?
public void add(Value v) {
client.execute(policy, key, PackageName, "add", binName, v);
}
private static final String PackageName = "llist";
LargeList.javaのaddメソッドのソースコード
- -copyright Fringe81 Co.,Ltd.
サーバーに配置されたluaプログラムを実行
するためのメソッド。
LDT処理はサーバーのluaで実行される。
インストール時に/opt/aerospike/sys/udf/luaにluaスクリプトが配
置される。
function llist.add (topRec, ldtBinName, newValue, createSpec, src)
local meth = "llist.add()";
local rc = aerospike:set_context( topRec, UDF_CONTEXT_LDT );
if (rc ~= 0) then
error(ldte.ERR_NS_LDT_NOT_ENABLED);
end
if newValue == nil then
...略...
end
/opt/aerospike/sys/udf/lua/ldt/lib_llist.lua
AerospikeClient#execute
- -copyright Fringe81 Co.,Ltd.
Luaスクリプトは
自分で書くことも出来る
UDF
(User-Defined Functions)
と呼ぶ
- -copyright Fringe81 Co.,Ltd.
val l = List(1,2,3)
val addr = (a:Int, b:Int) => a + b
l.map(n => addr(1, n))
Scala
(ちょっと苦しいが)UDFで実現してみる
List(1,2,3) -> +1 -> List(2,3,4)
- -copyright Fringe81 Co.,Ltd.
・クライアント:
 いくら足すのかを指定
・サーバー:
 udfにて、指定された値を全要素に足す
 ※replaceできない(?)ので削除&追加で表現
シナリオ
- -copyright Fringe81 Co.,Ltd.
LargeList llist =
client.getLargeList(
writePolicy,
key,
binName);
llist.add(
Value.get(1), Value.get(2), Value.get(3));
1,2,3というLListを保存しておく
- -copyright Fringe81 Co.,Ltd.
local llist_lib = require(‘ldt/lib_llist’);
function addr(rec, binName, numVal)
local l = list()
elems = llist_lib.scan(rec, binName, nil, nil, nil, nil)
for e in list.iterator(elems) do
list.append(l, e + numVal)
end
llist_lib.destroy(rec, binName)
llist_lib.add_all(rec, binName, l);
return numVal
end
aql> register module ‘myfunc.lua’
- -copyright Fringe81 Co.,Ltd.
client.execute(
writePolicy,
key,
“myfunc”,
“addr”,
Value.get(“binName”), Value.get(1)
);
クライアントで
myfunc.addrを引数2つで呼び出し
- -copyright Fringe81 Co.,Ltd.
System.out.println(llist.scan());
[2,3,4]と表示される。
もとのListに+1された事が確認できた。
※List<?>が返る
- -copyright Fringe81 Co.,Ltd.
・ソート順は昇順のみ
・aerospike.confのwrite block size設定によっ
て1要素の容量が制限される
- 1Mbなら200kb
- 128Kbなら30kb
- なお要素数の制限は無い
・add_all()/update_all()での実行で挿入できる
データ容量は1GBまで(luaの限界)
・BinaryDataTypeおよびmin()/max()はunder
construction
http://www.aerospike.com/docs/guide/llist.html
Limitation:
- -copyright Fringe81 Co.,Ltd.
他にも制限がある
・XDR(※1)ではLDTは対象外
・aql(※2)で内容を確認できない
※1 Cross Datacenter Replication
※2 SQLライクな対話型ツール
- -copyright Fringe81 Co.,Ltd.
制限とはちょっと違うが
・LDTのデータは1つのサーバーノードで保存され
クラスタ内に分散するわけではない
・TTLはRecord単位で、LDTのデータ(要素)単位
ではない
・LDT処理はlua使う分CPU消費する
・LDT x Luaはサンプル少なくちょっと苦労
- -copyright Fringe81 Co.,Ltd.
aqlの話を少ししてみる
- -copyright Fringe81 Co.,Ltd.
aql> select * from test.hoge where pk='addkey'
+------+
| bool |
+------+
| 1 |
+------+
aql> select * from test.hoge where pk='addkey2'
+--------+
| addbin |
+--------+
| 45 |
+--------+
aql> select * from test.hoge
+--------+------+
| addbin | bool |
+--------+------+
| 45 | |
| | 1 |
+--------+------+
limit句欲しい、が難しいらしい
- -copyright Fringe81 Co.,Ltd.
aql> select * from test.hoge where pk='addkey'
+------+
| bool |
+------+
| 1 |
+------+
aql> select * from test.hoge where pk='addkey2'
+--------+
| addbin |
+--------+
| 45 |
+--------+
aql> select * from test.hoge
+--------+------+
| addbin | bool |
+--------+------+
| 45 | |
| | 1 |
+--------+------+
Keyが表示されない。が...
- -copyright Fringe81 Co.,Ltd.
WritePolicy wp = new WritePolicy();
wp.sendKey = true;
client.put(wp, ...
- -copyright Fringe81 Co.,Ltd.
aql> select * from test.hoge where pk='addkey'
+------+
| bool |
+------+
| 1 |
+------+
aql> select * from test.hoge where pk='addkey2'
+--------+
| addbin |
+--------+
| 45 |
+--------+
aql> select * from test.hoge
+-----------+--------+------+
| key | addbin | bool |
+-----------+--------+------+
| "addkey2" | 45 | |
| "addkey" | | 1 |
+-----------+--------+------+
Keyが表示される
なおaqlでの表示以外にも...
- -copyright Fringe81 Co.,Ltd.
client.scanAll(
new ScanPolicy(),
“namespace”,
“setname”,
new ScanCallback {
public void scanCallback(Key k, Record r) {
k.userKey(); // これでkeyの値が取得可能
}
}); scanAllはSetのレコードを全走査する際に使用。
この時Keyの値が必要になることが多い。
- -copyright Fringe81 Co.,Ltd.
OSS化
2014.6.24
- -copyright Fringe81 Co.,Ltd.
Community Edition?
Enterprise Edition?
- -copyright Fringe81 Co.,Ltd.
あまり使われていない機能
(主に新機能)や
環境を使う場合は
Enterprise Editionを
推奨
- -copyright Fringe81 Co.,Ltd.
Aerospike自身のバグの可能性も
米国チームや
インドチームに
調査依頼出来る
※日本語でOK
※英語チャットもOK
日本に来てくれることも
- -copyright Fringe81 Co.,Ltd.
でも
Community Edition利用も
広がって欲しい
- -copyright Fringe81 Co.,Ltd.
- -copyright Fringe81 Co.,Ltd.
- -copyright Fringe81 Co.,Ltd.
- -copyright Fringe81 Co.,Ltd.
自分で薄いScalaラッパー作ってしまった。
みんなはどうしているんだろう?
調査発表とかソースコードリーディング勉強会?
- -copyright Fringe81 Co.,Ltd.
最後に...
- -copyright Fringe81 Co.,Ltd.
We’re hiring!
- -copyright Fringe81 Co.,Ltd.
参考資料
GitHub上のClientライブラリ以外の
サンプルコード
https://github.com/aerospike/ldt-examples
https://github.com/aerospike/url-tracker

Aerospike deep dive LDTs

  • 1.
    - -copyright Fringe81Co.,Ltd. Aerospike Tech Deep Dive v3新機能 Large Data Typesを中心に
  • 2.
    - -copyright Fringe81Co.,Ltd. ・@mtoyoshi ・Fringe81 ・Java, Scala ・アドテク畑  DSP→DMP→ADNW ・Aerospike歴1年 自己紹介
  • 3.
    - -copyright Fringe81Co.,Ltd. Aerospikeは... 速い 運用コストが低い スケーラビリティ高い etc...
  • 4.
    - -copyright Fringe81Co.,Ltd. インフラ的な話が多い? 今日はプログラミング話
  • 5.
    - -copyright Fringe81Co.,Ltd. 2015/04 Aerospike行ってきた
  • 6.
    - -copyright Fringe81Co.,Ltd. ステーキの写真
  • 7.
    - -copyright Fringe81Co.,Ltd. クライアントライブラリ 新機能の実装優先度
  • 8.
    - -copyright Fringe81Co.,Ltd. 1st Priority
  • 9.
    - -copyright Fringe81Co.,Ltd. 2nd Priority
  • 10.
    - -copyright Fringe81Co.,Ltd. Aerospike ↓ アドテク? ↓ Scala??
  • 11.
    - -copyright Fringe81Co.,Ltd. Aerospike Community Labs http://www.aerospike.com/community/labs/
  • 12.
    - -copyright Fringe81Co.,Ltd. 大体の使い方を知るには サンプルプログラムを読む/実行する のが手っ取り早い あと ドキュメントが充実してきている
  • 13.
    - -copyright Fringe81Co.,Ltd. https://www.aerospike.com/docs/operations/install/vagrant/mac/
  • 14.
    - -copyright Fringe81Co.,Ltd. http://localhost:8081
  • 15.
    - -copyright Fringe81Co.,Ltd. % vagrant ssh $ cd ClientInstall $ ./as_java_install.sh $ cd ~/aerospike-client-java-3.1.2/examples $ ./run_examples all
  • 16.
  • 17.
    - -copyright Fringe81Co.,Ltd. ここまで 30分で出来た ※Vagrant自体のインストールは除く
  • 18.
    - -copyright Fringe81Co.,Ltd. GitHubで公開されている clientライブラリにも examplesが同梱 但しクライアントライブラリ(プログラミング言語) によってexamplesの充実度が異なる ※例えばLDTsはrubyやphpには2015/06時点で 無かったり一部だったり ※充実度ではJavaが一番良さそう
  • 19.
    - -copyright Fringe81Co.,Ltd. 基本の「保存」&「検索」
  • 20.
    - -copyright Fringe81Co.,Ltd. client.put( new WritePolicy(), new Key(“namespace”, “setname”, “key1”), new Bin(“num”, 1), new Bin(“bool”, true)); Bin部は可変長引数
  • 21.
    - -copyright Fringe81Co.,Ltd. getBooleanとgetObjectで挙動が異なる Record record = client.get( new Policy(), new Key(“namespace”, “setname”,“key1”), “num”); int n = record.getInt(“num”); // 1 boolean b = record.getBoolean(“bool”); // false Object o = record.getValue(“bool”); // null
  • 22.
    - -copyright Fringe81Co.,Ltd. Serializableを実装している 任意のクラスも保存可能 Record#getList Record#getMap はない Record#getObject を使用してダウンキャスト boolean int long float double String List Map Object byte[]
  • 23.
    - -copyright Fringe81Co.,Ltd. msgpackの 仕様に基づき シリアライズ されて保存
  • 24.
    - -copyright Fringe81Co.,Ltd. val list = List(“x”, “a”, “c”) list :+ “f” // 追加 list.dropWhile(_ == “a”) // 削除 list.find(_ == “c”) // 検索 list.sorted // ソート Aerospike上にListが保存されていても プログラミング言語のListのように 1要素だけ追加とか出来ない 取得→Listの操作→保存 Scala
  • 25.
    - -copyright Fringe81Co.,Ltd. でも ver.3から できる
  • 26.
    - -copyright Fringe81Co.,Ltd. ver.3から Aerospike DBとして List / Set / Map / Stackを サポート それが Large Data Types(LDTs)
  • 27.
    - -copyright Fringe81Co.,Ltd. LargeList llist = client.getLargeList( writePolicy, key, binName); llist.add(Value.get(“z”)) getLargeList時点では通信は発生しない。 “z”だけの追加が可能。
  • 28.
    - -copyright Fringe81Co.,Ltd. add / update scan / find / range / filter remove / destroy size LargeListはkeyのASCでソートされる O(logN)の探索となる LargeListのメソッド
  • 29.
    - -copyright Fringe81Co.,Ltd. llist.add(Value.get(“a,99”)); llist.add(Value.get(“b,1”)); これだと文字列順でa,bとソート
  • 30.
    - -copyright Fringe81Co.,Ltd. 上記だとkeyの数字順でb,aとソート ※“key”が特殊な意味を持つ Map<String,Value> m = new HashMap<>(); m.put(“key”,Value.get(99)); m.put(“value”, Value.get(“a,99”)); list.add(Value.get(m)); ※もう1つは省略
  • 31.
    - -copyright Fringe81Co.,Ltd. どうやって1要素だけの 差分追加等を実現しているのか? public void add(Value v) { client.execute(policy, key, PackageName, "add", binName, v); } private static final String PackageName = "llist"; LargeList.javaのaddメソッドのソースコード
  • 32.
    - -copyright Fringe81Co.,Ltd. サーバーに配置されたluaプログラムを実行 するためのメソッド。 LDT処理はサーバーのluaで実行される。 インストール時に/opt/aerospike/sys/udf/luaにluaスクリプトが配 置される。 function llist.add (topRec, ldtBinName, newValue, createSpec, src) local meth = "llist.add()"; local rc = aerospike:set_context( topRec, UDF_CONTEXT_LDT ); if (rc ~= 0) then error(ldte.ERR_NS_LDT_NOT_ENABLED); end if newValue == nil then ...略... end /opt/aerospike/sys/udf/lua/ldt/lib_llist.lua AerospikeClient#execute
  • 33.
    - -copyright Fringe81Co.,Ltd. Luaスクリプトは 自分で書くことも出来る UDF (User-Defined Functions) と呼ぶ
  • 34.
    - -copyright Fringe81Co.,Ltd. val l = List(1,2,3) val addr = (a:Int, b:Int) => a + b l.map(n => addr(1, n)) Scala (ちょっと苦しいが)UDFで実現してみる List(1,2,3) -> +1 -> List(2,3,4)
  • 35.
    - -copyright Fringe81Co.,Ltd. ・クライアント:  いくら足すのかを指定 ・サーバー:  udfにて、指定された値を全要素に足す  ※replaceできない(?)ので削除&追加で表現 シナリオ
  • 36.
    - -copyright Fringe81Co.,Ltd. LargeList llist = client.getLargeList( writePolicy, key, binName); llist.add( Value.get(1), Value.get(2), Value.get(3)); 1,2,3というLListを保存しておく
  • 37.
    - -copyright Fringe81Co.,Ltd. local llist_lib = require(‘ldt/lib_llist’); function addr(rec, binName, numVal) local l = list() elems = llist_lib.scan(rec, binName, nil, nil, nil, nil) for e in list.iterator(elems) do list.append(l, e + numVal) end llist_lib.destroy(rec, binName) llist_lib.add_all(rec, binName, l); return numVal end aql> register module ‘myfunc.lua’
  • 38.
    - -copyright Fringe81Co.,Ltd. client.execute( writePolicy, key, “myfunc”, “addr”, Value.get(“binName”), Value.get(1) ); クライアントで myfunc.addrを引数2つで呼び出し
  • 39.
    - -copyright Fringe81Co.,Ltd. System.out.println(llist.scan()); [2,3,4]と表示される。 もとのListに+1された事が確認できた。 ※List<?>が返る
  • 40.
    - -copyright Fringe81Co.,Ltd. ・ソート順は昇順のみ ・aerospike.confのwrite block size設定によっ て1要素の容量が制限される - 1Mbなら200kb - 128Kbなら30kb - なお要素数の制限は無い ・add_all()/update_all()での実行で挿入できる データ容量は1GBまで(luaの限界) ・BinaryDataTypeおよびmin()/max()はunder construction http://www.aerospike.com/docs/guide/llist.html Limitation:
  • 41.
    - -copyright Fringe81Co.,Ltd. 他にも制限がある ・XDR(※1)ではLDTは対象外 ・aql(※2)で内容を確認できない ※1 Cross Datacenter Replication ※2 SQLライクな対話型ツール
  • 42.
    - -copyright Fringe81Co.,Ltd. 制限とはちょっと違うが ・LDTのデータは1つのサーバーノードで保存され クラスタ内に分散するわけではない ・TTLはRecord単位で、LDTのデータ(要素)単位 ではない ・LDT処理はlua使う分CPU消費する ・LDT x Luaはサンプル少なくちょっと苦労
  • 43.
    - -copyright Fringe81Co.,Ltd. aqlの話を少ししてみる
  • 44.
    - -copyright Fringe81Co.,Ltd. aql> select * from test.hoge where pk='addkey' +------+ | bool | +------+ | 1 | +------+ aql> select * from test.hoge where pk='addkey2' +--------+ | addbin | +--------+ | 45 | +--------+ aql> select * from test.hoge +--------+------+ | addbin | bool | +--------+------+ | 45 | | | | 1 | +--------+------+ limit句欲しい、が難しいらしい
  • 45.
    - -copyright Fringe81Co.,Ltd. aql> select * from test.hoge where pk='addkey' +------+ | bool | +------+ | 1 | +------+ aql> select * from test.hoge where pk='addkey2' +--------+ | addbin | +--------+ | 45 | +--------+ aql> select * from test.hoge +--------+------+ | addbin | bool | +--------+------+ | 45 | | | | 1 | +--------+------+ Keyが表示されない。が...
  • 46.
    - -copyright Fringe81Co.,Ltd. WritePolicy wp = new WritePolicy(); wp.sendKey = true; client.put(wp, ...
  • 47.
    - -copyright Fringe81Co.,Ltd. aql> select * from test.hoge where pk='addkey' +------+ | bool | +------+ | 1 | +------+ aql> select * from test.hoge where pk='addkey2' +--------+ | addbin | +--------+ | 45 | +--------+ aql> select * from test.hoge +-----------+--------+------+ | key | addbin | bool | +-----------+--------+------+ | "addkey2" | 45 | | | "addkey" | | 1 | +-----------+--------+------+ Keyが表示される なおaqlでの表示以外にも...
  • 48.
    - -copyright Fringe81Co.,Ltd. client.scanAll( new ScanPolicy(), “namespace”, “setname”, new ScanCallback { public void scanCallback(Key k, Record r) { k.userKey(); // これでkeyの値が取得可能 } }); scanAllはSetのレコードを全走査する際に使用。 この時Keyの値が必要になることが多い。
  • 49.
    - -copyright Fringe81Co.,Ltd. OSS化 2014.6.24
  • 50.
    - -copyright Fringe81Co.,Ltd. Community Edition? Enterprise Edition?
  • 51.
    - -copyright Fringe81Co.,Ltd. あまり使われていない機能 (主に新機能)や 環境を使う場合は Enterprise Editionを 推奨
  • 52.
    - -copyright Fringe81Co.,Ltd. Aerospike自身のバグの可能性も 米国チームや インドチームに 調査依頼出来る ※日本語でOK ※英語チャットもOK 日本に来てくれることも
  • 53.
    - -copyright Fringe81Co.,Ltd. でも Community Edition利用も 広がって欲しい
  • 54.
  • 55.
  • 56.
  • 57.
    - -copyright Fringe81Co.,Ltd. 自分で薄いScalaラッパー作ってしまった。 みんなはどうしているんだろう? 調査発表とかソースコードリーディング勉強会?
  • 58.
    - -copyright Fringe81Co.,Ltd. 最後に...
  • 59.
    - -copyright Fringe81Co.,Ltd. We’re hiring!
  • 60.
    - -copyright Fringe81Co.,Ltd. 参考資料 GitHub上のClientライブラリ以外の サンプルコード https://github.com/aerospike/ldt-examples https://github.com/aerospike/url-tracker