MySQLのベンチマークツール
MySQLのベンチーマークツールで一般的によく使われるのは以下のようなものがあります。
- sysbench
CPUやファイルIOなどデータベースサーバーのパフォーマンスを測定するツール。データベースはMySQLとPostgreSQLに対応。シナリオは比較的シンプルです。
GitHub – akopytov/sysbench: Scriptable database and system performance benchmark - tpcc-mysql
TPCは非営利団体によるデータベースのベンチマーク定義の中の「TPC-C」に基づいてMySQL向けに作成されたベンチマークツールです。複数の販売区域と倉庫を持つ卸売り業者を模した現実に近いシナリオです。
GitHub – Percona-Lab/tpcc-mysql - LinkBench
Facebookが開発しているベンチマークツール。そのため、シナリオもFacebookのワークロードに近いものになっています。
GitHub – facebookarchive/linkbench: Facebook Graph Benchmark
今回はこの中の sysbench の最新バージョンの 1.0 系で Lua スクリプトを使ったオリジナルのベンチマークシナリオの作成方法について解説します。
カスタムシナリオ
sysbench 1.0 ではLuaスクリプトでオリジナルのベンチマークシナリオを作成することが可能になりましたが、ドキュメントやAPIの仕様など、まとまった情報はまだありません。
現状では、sysbench 作者によるスライド資料から読み解くか、デフォルトで使えるOLTPのシナリオもLuaスクリプトで書かれているので、詳細はそこから読み解く必要がありそうです。
参考
- sysbench 1.0: teaching an old dog new tricks (PDF)
- sysbench/src/lua at master · akopytov/sysbench · GitHub
前提条件
sysbench 1.0 がインストールされている必要があります。
インストール方法は以下のページを参考に行って下さい。
GitHub – akopytov/sysbench: Installing from Binary Packages
sysbench からコールされるメソッド
sysbenchのデータベースのシナリオでは prepare / run / cleanup と3つのコマンドがあります。
Luaスクリプトでは下記の例のように、これらに対応したメソッドがコールされることになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/usr/bin/env sysbench -- コマンドラインオプションの定義 sysbench.cmdline.options = { table_size = {"Number of rows", 1000} } function prepare() -- prepare コマンドが実行されると呼び出されます end function cleanup() -- cleanup コマンドが実行されると呼び出されます end function thread_init() -- スレッド起動時の初期化処理 end function event(thread_id) -- イベント単位で呼び出される end |
イベントとは?
run コマンドを実行した際に、eventメソッドが繰り返しコールされます。
sysbenchではeventメソッドが実行された回数をトランザクションと定義しています。
そのため、例えばベンチマークの実行時間を10秒と設定すると、このeventメソッドが10秒間連続して実行され、その実行回数がトランザクション数としてカウントされることになります。
スレッドとは?
sysbenchではデータベースへの同時接続数は複数のスレッドを同時実行することで実現しています。そのため、スレッドはスレッド単位でシナリオファイルを実行することになるため、連続する一意な値を作成する場合は他のスレッドと値が衝突しないように、thread_idと組み合わせて使うような注意が必要です。
sequence.lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#!/usr/bin/env sysbench function get_con() drv = sysbench.sql.driver() return drv:connect() end function prepare() con = get_con() -- シーケンス番号とスレッドIDを格納するテーブルを定義 con:query("CREATE TABLE seq (seq int(11), thread_id int(11))") end function thread_init() con = get_con() end function event(thread_id) -- イベント単位で数値を増やす num = num + 1 -- シーケンス番号とスレッドIDを挿入 con:query("INSERT INTO seq (id) VALUES (" .. num .. "," .. thread_id .. ")") end |
実行
テーブル作成
1 |
$ ./sequence.lua --db-driver=mysql --mysql-host=127.0.0.1 --mysql-user=root --mysql-password=password --mysql-db=test prepare |
thread数を4で実行
1 |
$ ./sequence.lua --db-driver=mysql --mysql-host=127.0.0.1 --mysql-user=root --mysql-password=password --mysql-db=test --threads=4 run |
シナリオのLuaファイルにオプション定義を記載しなくても、--mysql-*
のグローバルオプションはそのまま使えます。
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
mysql> select * from seq limit 10; +------+-----------+ | id | thread_id | +------+-----------+ | 1 | 1 | | 1 | 2 | | 1 | 3 | | 1 | 4 | | 2 | 1 | | 2 | 2 | | 2 | 3 | | 2 | 4 | | 3 | 1 | | 3 | 2 | +------+-----------+ 10 rows in set (0.01 sec) |
スレッド単位で独立して採番しているのがわかるかと思います。
カスタムレポート
sysbench 1.0 では --report-interval=
オプションで出力されるレポートをカスタマイズすることが出来るようになりました。
メソッド定義
下記のようにフックメソッドを定義すると--report-interval
オプションで指定した秒数毎にコールされます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function sysbench.hooks.report_intermediate(stat) -- report-intervalで指定した秒数単位でこのメソッドが呼ばれる -- 引数のstatsの中身 stat.time_interval -- オプションで指定した秒数 stat.time_total -- runの実行時間(秒) stat.threads_running -- スレッド数 stat.events -- インターバルの間で実行されたevent数(=トランザクション数) stat.reads -- インターバルの間で実行された読み込みクエリー数 stat.writes -- インターバルの間で実行された書き込みクエリー数 stat.other -- インターバルの間で実行されたその他のクエリー数 stat.latency_pct -- インターバルの間のレイテンシパーセンタイル??(詳細不明) stat.errors -- インターバルの間のエラー数 stat.reconnects -- インターバルの間の再接続数 end |
オリジナルベンチマークの実装サンプル
以下は、eventメソッドで挿入処理を繰り返し、カスタムレポートでデータベースサイズを取得してLTSV形式でレポートを出力するオリジナルベンチマークの実装サンプルになります。
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#!/usr/bin/env sysbench total_events = 0 -- カスタムレポートの定義 function sysbench.hooks.report_intermediate(stat) -- DB接続されていない時は接続する if con == nil then con = assert(sysbench.sql.driver():connect()) end -- イベント実行数を累積する -- runコマンドで複数スレッドで実行しても問題ありません(thread safe) total_events = total_events + stat.events size = con:query_row(string.format([[ SELECT ROUND(((SUM(data_length + index_length)) / 1024 / 1024), 2) as 'Size' FROM information_schema.TABLES WHERE table_schema = '%s' ]], sysbench.opt.mysql_db)) -- LTSV形式で出力 print(string.format( "time_total:%.0f\ttotal_events:%.0f\terrors:%.0f\tsize:%.2f", stat.time_total, total_events, stat.errors, size)) end function get_con() drv = sysbench.sql.driver() return drv:connect() end -- テーブル作成の実行 function prepare() con = get_con() con:query("CREATE TABLE seq (id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY)") end -- テーブル削除の実行 function cleanup() con = get_con() con:query("DROP TABLE seq") end -- スレッド起動時にMySQLへの接続処理を行う function thread_init() con = get_con() end -- レコード挿入処理を行う function event() con:query("INSERT INTO seq VALUES(NULL)") end |
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ ./report_databasesize.lua --time=30 --report-interval=1 --mysql-host=127.0.0.1 --mysql-user=root --mysql-password=password --mysql-db=d1 --threads=2 run sysbench 1.0.8 (using bundled LuaJIT 2.1.0-beta2) Running the test with following options: Number of threads: 2 Report intermediate results every 1 second(s) Initializing random number generator from current time Initializing worker threads... Threads started! time_total:1s total_events:846 errors:0 size:0.02mb time_total:2s total_events:1672 errors:0 size:0.02mb time_total:3s total_events:2434 errors:0 size:0.02mb time_total:4s total_events:3229 errors:0 size:0.02mb time_total:5s total_events:4187 errors:0 size:0.02mb time_total:6s total_events:5135 errors:0 size:0.02mb time_total:7s total_events:6087 errors:0 size:0.02mb time_total:8s total_events:7115 errors:0 size:0.02mb time_total:9s total_events:8129 errors:0 size:0.02mb ...(省略)... |
まとめ
ドキュメントやマニュアルがあまり無いのですが、sysbenchがインストールされていれば、Luaスクリプトを書くだけで独自のベンチマークシナリオを簡単に作ることができました。
- 特殊なワークロードのため、一般的なベンチマークの結果が使えない
- 自身のシステムの処理を再現して、できるだけ正確な性能限界を知りたい
- MySQLやPostgreSQLの新機能や特定の処理のベンチマークを取りたい
上記の場合などで、sysbenchによるオリジナルベンチマークを作るのを検討してはいかがでしょうか?