前回の検証の振り返り
前回のブログで、Cassandraへの大量データのロードと全件検索の性能をPostgreSQLと比較して検証しました。
1ノード構成ではありますが、この時のCassandra側の性能が、PostgreSQLに比べると圧倒的に遅いことがわかりました。
以下は前回のブログで検証した結果です。
CassandraもPostgreSQLもパラメータチューニングなしです。
100万件のロードの所要時間
- PostgreSQL:約3秒
- Cassandra:タイムアウト頻発、約5分30秒
100万件の全件カウント検索の所要時間
- PostgreSQL:1秒未満
- Cassandra:タイムアウト発生で検索できず。タイムアウトしないように設定して約30秒
今回は、大量データロード時のCassandraのタイムアウトを抑止して、処理時間を短縮した方法と検証結果を紹介します。
検索の方は、次回のブログで書きます。
100万件のロードのタイムアウトを解決し、ロード時間を短縮した方法
何度かロードを繰り返していると、そのうちに、5分30秒どころか、タイムアウト頻発で終わらなくなりました。
cqlsh:ks2> COPY emp(empno,ename,deptno) FROM 'sampledata1000000.csv' ;
Using 1 child processes
Starting copy of ks2.emp with columns [empno, ename, deptno].
Failed to import 10 rows: WriteTimeout - Error from server: code=1100 [Coordinator node timed out waiting for replica nodes' responses] message="Operation timed out - received only 0 responses." info={'received_responses': 0, 'required_responses': 1, 'consistency': 'ONE'}, will retry later, attempt 1 of 5
Failed to import 20 rows: WriteTimeout - Error from server: code=1100 [Coordinator node timed out waiting for replica nodes' responses] message="Operation timed out - received only 0 responses." info={'received_responses': 0, 'required_responses': 1, 'consistency': 'ONE'}, will retry later, attempt 1 of 5
Failed to import 20 rows: WriteTimeout - Error from server: code=1100 [Coordinator node timed out waiting f
vmstatを見ていると、スワップが頻発していることに気づきます。
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
1 1 225792 68404 0 173504 19320 9652 22108 9652 2546 6992 29 13 0 59 0
3 3 223328 71264 0 172104 25288 11640 28716 11880 4443 11220 32 16 0 52 0
1 1 225648 67032 0 173492 22780 11068 25432 11068 2804 3002 5 8 0 87 0
1 1 225144 71016 0 172040 11200 1776 13332 1776 1744 1632 1 4 0 95 0
JVMの起動オプション「-Xms」を確認すると、ヒープサイズが496Mと設定されていることがわかりました。
スワップが発生していた原因は、jvmのヒープサイズのデフォルト値496Mに対して、OSのメモリ1GBが少なすぎたことでした。
CassandraのJVMヒープサイズデフォルト値の計算ロジック
そこで、OSのメモリを1GB→2GBに増やして再度ロードしてみました。
cqlsh:ks2> COPY emp(empno,ename,deptno) FROM 'sampledata1000000.csv' ;
Using 1 child processes
Starting copy of ks2.emp with columns [empno, ename, deptno].
Processed: 1000000 rows; Rate: 4398 rows/s; Avg. rate: 6141 rows/s
1000000 rows imported from 1 files in 2 minutes and 42.846 seconds (0 skipped).
2分42秒で終わりました。
スワップは発生しなくなり、タイムアウトも抑止できました。
Cassandra側のパラメータは何も変更していません。
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
15 0 0 85936 164 417256 0 0 0 0 1313 667 97 3 0 0 0
20 0 0 82372 164 421364 0 0 0 0 1256 632 97 3 0 0 0
2 0 0 77576 164 425492 0 0 0 0 1302 717 98 2 0 0 0
PostgreSQLで同じことをすると約3秒で終わりました。
もっと早くできないでしょか?
Cassandraの書き込みアーキテクチャHow is data written?を参照し、書き込み処理を早くする方法として思いつくものを洗い出してみました。
- 書き込みのプロセス数を増やす
- メモリ領域(memtable)を増やして、ディスク(sstable)へのフラッシュ頻度を減らす
- ロード中にcommitlogへの書き込みを中止する
- GCの回数を減らす
vmstatではrunqueの数も多かったので、1.の方法を試すこととし、CPUを増やして複数プロセスで処理することでロード時間を短縮できないかを検証してみました。
2~4の方法は、次回以降で調査してみて、いい方法があれば検証してみます。
さて、copyコマンドを複数プロセスで実行する方法を調べたところ、
というオプションがありました。
これは使えそうです。
CPUを10個に増やして2プロセスで実行すると、処理速度はほぼ倍の1分25秒になりました。
cqlsh:ks2> COPY emp(empno,ename,deptno) FROM 'sampledata1000000.csv' with numprocesses=2;
Reading options from the command line: {'numprocesses': '2'}
Using 2 child processes
Starting copy of ks2.emp with columns [empno, ename, deptno].
Processed: 1000000 rows; Rate: 13562 rows/s; Avg. rate: 11650 rows/s
1000000 rows imported from 1 files in 1 minute and 25.840 seconds (0 skipped).
numprocessesの値を増やしてcopyコマンドを実行した結果です。
CPU10個に対してプロセス数は7で処理性能が頭打ちとなりましたが、処理時間を20秒まで短縮できました。
PostgreSQLだと3秒で終わったので、かなり不満ですが。。。
それは置いといて、1ノードでもCPUを増やすと速度を向上させることができたことがわかりました。
ノードを増やすとどうなるのだろうか。。