はじめに
YCSBを使用してインメモリデータベースVoltDBの性能を計測しています。
YCSBはYahoo! Cloud Serving Benchmarkの略で、 Yahoo! Research が開発したNoSQL用のベンチマークツールです。
YCSBはデフォルトでCassandraやRedis等の多くのNoSQLに対応しているのですがVoltDBには対応していません。VoltDB側でクライアントが用意されているのでそちらを利用します。
環境設定
YCSBを以下からダウンロードします。
YCSBを展開し、環境変数YCSB_HOMEを設定します。
tar xzvf ycsb-0.15.0.tar.gz -C /opt
export YCSB_HOME="/opt/ycsb-0.15.0"
VoltDBのYCSBクライアントは以下にあります。
これを/opt以下に格納します。
以下のコマンドでVoltDB用のYCSBクライアントをコンパイルします。
# cd /opt/ycsb
# chmod 755 run.sh
# ./run.sh jars
ベンチマークに必要なSTOREテーブルとプロシージャを作成します。
# ./run.sh init
作成されたテーブルのDDLは以下のようになっています。
(ycsb_ddl.sqlファイルから抜粋)
CREATE TABLE Store
(
keyspace VARBINARY(128) NOT NULL
, key VARCHAR(128) NOT NULL
, value VARBINARY(2056) NOT NULL
, PRIMARY KEY (keyspace, key)
);
PARTITION TABLE Store ON COLUMN key;
次にさきほど作成したSTOREテーブルにベンチマーク用のデータをロードします。
# ./run.sh load
使用される設定ファイルは「base.properties」と「load.properties」の2ファイルです。以下のように修正して実行しました。
voltdb.servers=localhost
threadcount=150
fieldcount=5 # 100から変更
fieldlength=10 # 100から変更
# load で挿入するレコード数
recordcount=2000000 # 10000000から変更
# run で実行されるクエリの回数
operationcount=2000000 # 10000000から変更
# workload を実行するクラス
workload=com.yahoo.ycsb.workloads.CoreWorkload
ベンチマーク用のデータの準備なのですが、これ自体もベンチマーク結果が以下のように出力されました。
秒間スループットが24,184件となっています。
[OVERALL], RunTime(ms), 82696
[OVERALL], Throughput(ops/sec), 24184.96662474606
[TOTAL_GCS_Copy], Count, 127
[TOTAL_GC_TIME_Copy], Time(ms), 223
[TOTAL_GC_TIME_%_Copy], Time(%), 0.2696623778659185
[TOTAL_GCS_MarkSweepCompact], Count, 3
[TOTAL_GC_TIME_MarkSweepCompact], Time(ms), 28
[TOTAL_GC_TIME_%_MarkSweepCompact], Time(%), 0.03385895327464448
[TOTAL_GCs], Count, 130
[TOTAL_GC_TIME], Time(ms), 251
[TOTAL_GC_TIME_%], Time(%), 0.303521331140563
[CLEANUP], Operations, 150
[CLEANUP], AverageLatency(us), 801.54
[CLEANUP], MinLatency(us), 2
[CLEANUP], MaxLatency(us), 114431
[CLEANUP], 95thPercentileLatency(us), 18
[CLEANUP], 99thPercentileLatency(us), 3325
[INSERT], Operations, 2000000
[INSERT], AverageLatency(us), 6024.355673
[INSERT], MinLatency(us), 69
[INSERT], MaxLatency(us), 294911
[INSERT], 95thPercentileLatency(us), 16143
[INSERT], 99thPercentileLatency(us), 25855
[INSERT], Return=OK, 2000000
ベンチマークを実行する
ベンチマークを実行します。「workloada」はベンチマークのシナリオで、50%の読み込みと50%の書き込みのシナリオになります。
./run.sh workload workloada
使用される設定ファイルは「base.properties」と「workload.properties」の2ファイルです。「workload.properties」は以下のように修正して実行しました。
maxexecutiontime=600
# load で挿入するレコード数
recordcount=2000000 # 10000000から変更
# run で実行されるクエリの回数
operationcount=2000000 # 1000000000から変更
また、ベンチマークの種類は以下のページが参考になりました。
YCSBの概要とCassandraへのベンチマーク
実行するとベンチマーク完了後に以下のような結果が表示されます。
秒間スループットが全体で23,723件になっています。
[OVERALL], RunTime(ms), 84306
[OVERALL], Throughput(ops/sec), 23723.10393091832
[TOTAL_GCS_Copy], Count, 100
[TOTAL_GC_TIME_Copy], Time(ms), 201
[TOTAL_GC_TIME_%_Copy], Time(%), 0.23841719450572912
[TOTAL_GCS_MarkSweepCompact], Count, 3
[TOTAL_GC_TIME_MarkSweepCompact], Time(ms), 27
[TOTAL_GC_TIME_%_MarkSweepCompact], Time(%), 0.032026190306739734
[TOTAL_GCs], Count, 103
[TOTAL_GC_TIME], Time(ms), 228
[TOTAL_GC_TIME_%], Time(%), 0.2704433848124689
[READ], Operations, 999883
[READ], AverageLatency(us), 6112.663878673805
[READ], MinLatency(us), 58
[READ], MaxLatency(us), 391679
[READ], 95thPercentileLatency(us), 18431
[READ], 99thPercentileLatency(us), 30815
[READ], Return=OK, 999883
[CLEANUP], Operations, 150
[CLEANUP], AverageLatency(us), 1108.56
[CLEANUP], MinLatency(us), 1
[CLEANUP], MaxLatency(us), 162943
[CLEANUP], 95thPercentileLatency(us), 21
[CLEANUP], 99thPercentileLatency(us), 1658
[UPDATE], Operations, 1000117
[UPDATE], AverageLatency(us), 6134.580398093423
[UPDATE], MinLatency(us), 68
[UPDATE], MaxLatency(us), 346623
[UPDATE], 95thPercentileLatency(us), 18495
[UPDATE], 99thPercentileLatency(us), 31071
[UPDATE], Return=OK, 1000117
VoltDBだと、CPU負荷等の情報もWeb画面で確認できて便利です。
参考
YCSBについては以下の情報が参考になりました。
VoltClient4.javaの修正
VoltDB用のクライアント(VoltClient4.java)はコンパイルが通らなかったので、以下のように修正しています。
# diff VoltClient4.java VoltClient4.java.kaizou
34a35
> import java.util.Map;
109c110
< public Status insert(String keyspace, String key, HashMap<String, ByteIterator> columns)
---
> public Status insert(String keyspace, String key, Map<String, ByteIterator> columns)
115c116
< public Status read(String keyspace, String key, Set<String> columns, HashMap<String, ByteIterator> result)
---
> public Status read(String keyspace, String key, Set<String> columns, Map<String, ByteIterator> result)
174c175
< result.add(unpackRowData(table, columns));
---
> result.add((HashMap)unpackRowData(table, columns));
193c194
< public Status update(String keyspace, String key, HashMap<String, ByteIterator> columns)
---
> public Status update(String keyspace, String key, Map<String, ByteIterator> columns)
251c252
< private byte[] packRowData(HashMap<String, ByteIterator> columns)
---
> private byte[] packRowData(Map<String, ByteIterator> columns)
273c274
< private HashMap<String, ByteIterator> unpackRowData(VoltTable data, Set<String> fields)
---
> private Map<String, ByteIterator> unpackRowData(VoltTable data, Set<String> fields)
279c280
< HashMap<String, ByteIterator> res = new HashMap<String, ByteIterator>(size, (float) 1.25);
---
> Map<String, ByteIterator> res = new HashMap<String, ByteIterator>(size, (float) 1.25);
283c284
< private HashMap<String, ByteIterator> unpackRowData(VoltTable data, Set<String> fields, HashMap<String, ByteIterator> result)
---
> private Map<String, ByteIterator> unpackRowData(VoltTable data, Set<String> fields, Map<String, ByteIterator> result)
291c292
< private HashMap<String, ByteIterator> unpackRowData(byte[] rowData, ByteBuffer buf, int nFields, Set<String> fields, HashMap<String, ByteIterator> result)
---
> private Map<String, ByteIterator> unpackRowData(byte[] rowData, ByteBuffer buf, int nFields, Set<String> fields, Map<String, ByteIterator> result)