-
Notifications
You must be signed in to change notification settings - Fork 14
Benchmark
CannyLSのベンチマーク結果。
CannyLSが主眼に置いている「大容量HDD上でのランダムアクセスワークロード」での性能を確認することが目的。
- 約1TB分のデータに対して各種操作を逐次的に実行し、その所要時間(レイテンシ)を計測する
- ※ 理想的には、もう一桁以上は大きなサイズの方が望ましいが、今回は時間の都合上1TBとした
- キーは16バイトのランダムバイト列
- 値は以下のそれぞれのサイズのランダムバイト列:
- 100KB
- 1MB
- 10MB
- 測定対象操作:
- PUT(新規)
- PUT(更新)
- GET
- DELETE
- LOAD ※ 1TB分のデータを有するKVSの起動時間
- ※ なお時間の関係上、
PUT(新規)
とLOAD
以外は、格納済みエントリ全体の中から、無作為に選択した1%、に対して操作を実行している
- 各測定の前には、OSのキャッシュ(ページキャッシュ及びslabキャッシュ)はクリアしておく
- 具体的には
sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
を実行する
- 具体的には
- 比較のためにCannyLS以外の組み込みKVS(後述)に対しても、同様の測定を行う
- データの保存先には、KSV毎および値のサイズ毎、に別々のHDDを使用する
- 測定ツールとしてはekvsb(v0.0.8)を使用
- CPU: Intel(R) Xeon(R) CPU E5-2630L v3 @ 1.80GHz
- RAM: 64GB
- HDD:
- 容量: 3TB
- 回転数: 15,000rpm
- ファイルシステム: XFS
- OS: Scientific Linux 7.2
以下の四つの組み込みKSV(ではないものもあるが)に対して、測定を実施する:
- cannyls:
- CannyLSのデフォルトパラメータを使用したもの (https://crates.io/crates/cannyls/0.9.0)
- 測定コマンド:
ekvsb run cannyls --capacity 2048GiB /path/to/lusf-file
- cannyls(sync):
- CannyLSのジャーナルメモリバッファを無効にしたもの
- プロセスクラッシュ時の整合性保証は最大化されるが、その分性能は劣化する
- 測定コマンド:
ekvsb run cannyls --capacity 2048GiB --journal-sync-interval 0 /path/to/lusf-file
- xfs:
- xfsフォーマットのファイルシステムをKVS的に利用したもの
- 具体的には、以下のように利用している:
- 一エントリが一ファイル
- 単一ディレクトリ内の大量のファイルが作成されることを避けるために、キーのハッシュの上位三バイトを用いて、以下のようなパスを生成している
{ハッシュの一バイト目}/{ハッシュの二バイト目}/{ハッシュの三バイト目}/{キー名}
- xfsがフォーマットとして選択された強い理由はない(たまたま測定環境がxfsだったため)
- 測定コマンド:
ekvsb run builtin::fs /path/to/root-dir/
- rocksdb:
- LevelDBから派生したFacebookが開発している組み込みKVS (https://crates.io/crates/rocksdb/0.10.1 )
- Rustバインディングのデフォルトパラメータを使用して計測
- 測定コマンド:
ekvsb run rocksdb /path/to/root-dir/
- XFSおよびRocksDBの結果は、あくまでも参考として載せられているものであり、これら自体の最大性能を示すものではない
- 両者ともに特にチューニング等は行っていない
- 特にRocksDBに関しては「A Persistent Key-Value Store for Flash and RAM Storage」とREADMEで銘打たれており、そもそもHDD向けでは無いことは留意しておく必要がある
- Rustから利用可能なより適切な、HDDを対象として組み込みKVSが存在する場合には、比較対象をそちらに変更する可能性がある
各操作の性能測定結果:
- レイテンシの単位は秒
- PUTおよびGETに関しては「秒間に処理されたデータ量(MB/秒)」を示すスループットカラムが存在
- DELETEに関しては「秒間に処理された操作数」を示す秒間処理数カラムが存在
- 図の掲載順は左から
cannyls, cannyls(sync), xfs, rocksdb
- 図のY軸(レイテンシ)の上限は五秒で固定
測定および結果生成コマンド(データサイズが100KBの場合):
$ ekvsb workload PUT --count 10000000 --key-size 16 --value-size 100KiB --seed foo > workload.put.100kb.json
$ ${対象KVS用の測定コマンド} < workload.put.100kb.json > result.put.100kb.json
$ ekvsb summary < result.put.100kb.json
$ ekvsb plot png put.100kb.png --title "PUT(new): kvs=${KVS名}, datasize=100KB" --y-max 5 < result.put.100kb.json
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 249.235 | 0.000358 | 0.001475 | 1.261304 |
cannyls(sync) | 137.087 | 0.000519 | 0.005121 | 1.189983 |
xfs | 9.367 | 0.000125 | 0.210620 | 9.309418 |
rocksdb | 2.295 | 0.029796 | 0.259761 | 703.077684 |
レイテンシの中央値に関してはxfsが一番小さいが、それ以外ではcannylsが良好な結果を示していた。 rocksdbはDBのサイズが増加するにつれて性能が劣化し、またレイテンシのバラつきもかなり大きなものとなっていた。
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 217.070 | 0.004342 | 0.012747 | 1.591087 |
cannyls(sync) | 142.533 | 0.006241 | 0.022470 | 1.369462 |
xfs | 54.699 | 0.000699 | 0.473626 | 2.605536 |
rocksdb | 2.954 | 0.235579 | 1.956971 | 960.785539 |
全体的な傾向はデータサイズが100KBの時と同様だが、xfsのスループットに関しては今回の方が格段に向上している。
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 224.392 | 0.043889 | 0.075065 | 0.498525 |
cannyls(sync) | 224.540 | 0.043010 | 0.084834 | 1.663457 |
xfs | 134.809 | 0.006345 | 1.256966 | 2.484090 |
rocksdb | 4.037 | 1.733949 | 11.826268 | 790.836380 |
全体的な傾向はデータサイズが1MBの時と似ているが、xfsのスループットが今回も向上しているのと、cannylsのジャーナルバッファ有無での性能差がほぼなくなっているのが特徴。
測定および結果生成コマンド(データサイズが100KBの場合):
$ ekvsb workload PUT --count 100000 --population-size 10000000 --shuffle qux --key-size 16 --seed foo --value-size 100KiB > workload.update.100kb.json
$ ${対象KVS用の測定コマンド} < workload.update.100kb.json > result.update.100kb.json
$ ekvsb summary < result.update.100kb.json
$ ekvsb plot png update.100kb.png --title "PUT(update): kvs=${KVS名}, datasize=100KB" --y-max 5 < result.update.100kb.json
※ 事前にPUT(新規)
の測定が実施されていることが前提
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 57.696 | 0.001473 | 0.010359 | 0.037559 |
cannyls(sync) | 34.065 | 0.001955 | 0.016928 | 1.185657 |
xfs | 2.692 | 0.031768 | 0.075660 | 3.659143 |
rocksdb | 9.662 | 0.010346 | 0.037739 | 0.182336 |
新規PUTに比べるとスループットは大幅に下がっているが、それでもcannylsが一番レイテンシも小さく安定している。 またrocksdbの性能が良くなっているのも特徴(件数を新規PUTと同様にすれば後半で傾向が変ってくる可能性もあるが未確認)。
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 222.293 | 0.004191 | 0.014692 | 0.035776 |
cannyls(sync) | 163.345 | 0.006310 | 0.019325 | 0.522372 |
xfs | 21.004 | 0.043746 | 0.097234 | 2.283350 |
rocksdb | 4.751 | 0.194194 | 0.468607 | 0.470332 |
データサイズが100KBの場合に比べて、全体的にスループットが向上する形となっている。ただしrocksdbだけは逆にスループットが下がっている。 一回のPUTのレイテンシに関しては、データサイズが増えた分だけ長くなっている。
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 362.061 | 0.010537 | 0.072840 | 0.081998 |
cannyls(sync) | 334.785 | 0.022547 | 0.077606 | 0.109275 |
xfs | 87.121 | 0.114569 | 0.327141 | 0.558513 |
rocksdb | 3.513 | 2.065413 | 14.258073 | 27.805194 |
一つ前の結果と同様に、データサイズが大きくなったことで全体的にスループットは向上しているが、rocksdbだけは大幅に性能が落ちている。
測定および結果生成コマンド(データサイズが100KBの場合):
$ ekvsb workload GET --count 100000 --population-size 10000000 --shuffle bar --key-size 16 --seed foo > workload.get.100kb.json
$ ${対象KVS用の測定コマンド} < workload.get.100kb.json > result.get.100kb.json
$ ekvsb summary < result.get.100kb.json
$ ekvsb plot png get.100kb.png --title "GET: kvs=${KVS名}, datasize=100KB" --y-max 5 < result.get.100kb.json
※ 事前にPUT(新規)
の測定が実施されていることが前提
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 9.916 | 0.009848 | 0.015516 | 0.072573 |
cannyls(sync) | 10.170 | 0.009563 | 0.015115 | 0.192162 |
xfs | 3.125 | 0.025806 | 0.060545 | 4.122876 |
rocksdb | 2.372 | 0.018690 | 0.849928 | 3.852956 |
cannylsのジャーナルメモリバッファはGET操作には影響を与えないので、今回は有り無しどちらの場合でも似たような結果となっている。 各KVSの結果はそれぞれ特徴的で「cannylsは全体的に安定」、「xfsは全体的にバラついている」、「rocksdbは最初はバラつきが激しいがしばらくしたら低いレイテンシで安定(ページキャッシュの影響?)」といった傾向となっている。
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 63.331 | 0.015778 | 0.021745 | 0.040909 |
cannyls(sync) | 63.949 | 0.015586 | 0.021668 | 0.095330 |
xfs | 19.033 | 0.048192 | 0.082145 | 2.594533 |
rocksdb | 3.142 | 0.056083 | 2.198023 | 4.455123 |
大まかな傾向はデータサイズが100KBの時と同様だが、サイズ増加の影響でスループットは全体的に向上している。また、rocksdbのレイテンシが安定するまでに要する操作回数も多くなっている。
KVS | スループット | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 137.349 | 0.072592 | 0.083659 | 0.098612 |
cannyls(sync) | 142.484 | 0.069988 | 0.081944 | 0.094999 |
xfs | 57.596 | 0.167162 | 0.269709 | 1.045060 |
rocksdb | 11.070 | 0.858279 | 2.338944 | 2.997740 |
これも傾向としては、データサイズが100KBから1MBに変わった場合と同様(スループットは向上し、レイテンシは長くなり、rocksdbの性能劣化が目立つ)。
測定および結果生成コマンド(データサイズが100KBの場合):
$ ekvsb workload DELETE --count 100000 --population-size 10000000 --shuffle baz --key-size 16 --seed foo > workload.delete.100kb.json
$ ${対象KVS用の測定コマンド} < workload.delete.100kb.json > result.delete.100kb.json
$ ekvsb summary < result.delete.100kb.json
※ 事前にPUT(新規)
の測定が実施されていることが前提
なおDELETEに関しては、表を見れば十分に傾向が把握可能なため、図の掲載は省略している。
KVS | 秒間処理数 | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 5,838.170 | 0.000169 | 0.000181 | 0.030402 |
cannyls(sync) | 4,810.811 | 0.000169 | 0.000355 | 0.136506 |
xfs | 38.753 | 0.018704 | 0.061354 | 3.680779 |
rocksdb | 118,899.689 | 0.000008 | 0.000015 | 0.001429 |
rocksdbが圧倒的に速く、逆にxfsは大幅に遅くなっている。
cannylsはその中間で、ジャーナルバッファが有効になっている方が性能は良いが、無効な場合でもそこまで極端に劣化している訳ではない。 なお現状のekvsbの実装では、cannylsが非同期インタフェースを提供している関係上、DELETE操作を発行した後に100us間隔でその結果をポーリングしているので、その間隔をもう少し短くすれば、測定上のレイテンシがもっと向上する可能性はある。
KVS | 秒間処理数 | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 5,854.403 | 0.000169 | 0.000181 | 0.000651 |
cannyls(sync) | 4,847.301 | 0.000167 | 0.000340 | 0.029850 |
xfs | 34.177 | 0.026111 | 0.061702 | 2.431488 |
rocksdb | 308,862.363 | 0.000003 | 0.000005 | 0.000527 |
データサイズが100KBの場合と同様。
KVS | 秒間処理数 | レイテンシ(中央) | レイテンシ(99%点) | レイテンシ(最大) |
---|---|---|---|---|
cannyls | 5,824.257 | 0.000168 | 0.000186 | 0.000887 |
cannyls(sync) | 4,971.541 | 0.000168 | 0.000487 | 0.000502 |
xfs | 44.313 | 0.020823 | 0.063784 | 0.098553 |
rocksdb | 95,195.420 | 0.000006 | 0.000015 | 0.001647 |
データサイズが100KBの場合と同様。
以下の方法で、各KVSの起動に要する時間を計測:
$ time echo '[]' | ${対象KVS用の測定コマンド}
KVS | データサイズ | 要素数 | 起動時間 |
---|---|---|---|
cannyls | 100 KB | 10,000,000 | 18.840 |
cannyls | 1 MB | 1,000,000 | 1.900 |
cannyls | 10 MB | 100,000 | 0.181 |
cannyls(sync) | 100 KB | 10,000,000 | 19.347 |
cannyls(sync) | 1 MB | 1,000,000 | 1.918 |
cannyls(sync) | 10 MB | 100,000 | 0.173 |
xfs | 100 KB | 10,000,000 | 0.018 |
xfs | 1 MB | 1,000,000 | 0.033 |
xfs | 10 MB | 100,000 | 0.029 |
rocksdb | 100 KB | 10,000,000 | 170.773 |
rocksdb | 1 MB | 1,000,000 | 178.919 |
rocksdb | 10 MB | 100,000 | 112.335 |
rocksdb(ページキャッシュ未クリア) | 100 KB | 10,000,000 | 2.411 |
rocksdb(ページキャッシュ未クリア) | 1 MB | 1,000,000 | 1.825 |
rocksdb(ページキャッシュ未クリア) | 10 MB | 100,000 | 1.953 |
ファイルシステムに関しては特別な起動処理は不要なので、当然xfsが一番短い結果となっている(実質上、コマンドの起動・停止時間そのもの)。
rocksdbは事前にページキャッシュに載っているかどうかで、大幅に起動時間に差が出ていた。ページキャッシュに必要なデータが事前に載っている場合には、かなり良好な結果となっているが、逆にページキャッシュがクリアされている場合の起動時間はこの中では一番長いものとなっている。また、起動時間はDBのサイズにのみ影響を受けているように見える。
cannylsは、起動時間が要素数に比例して長くなっている。おそらく要素数がもう一桁増えれば、rocksdb(ページキャッシュ無)よりも起動時に時間が掛かるようになるのではないかと思われる。
個々の測定結果を見てみると必ずしもCannyLSが全てにおいて一番優れていた訳ではないが、CannyLSが目指している「安定した低レイテンシの提供」という点においては、現時点でもそれなりに達成できていることは示せたのではないかと思う。