MySQL では 「InnoDB Memcached」プラグインを使うことで、Memcached プロトコルを使ってテーブルデータに直接アクセスすることができるようになります。
参考:MySQL :: MySQL 5.7 Reference Manual :: 14.20 InnoDB memcached Plugin
今回はPHPとMySQLの組み合わせでMemcachedプロトコルを使ったデータアクセスと、PHPからSQLを使ったデータアクセスでどれくらい速度差が出るのかを調べて見ました。
環境
AWS の m4.2xlarge インスタンスを使用しました。
スペック
vCPU: 8 core
MEM: 32GB
DISK: gp2 – 16GB
バージョン
MySQL: 5.7.20
PHP : 7.1.11
ベンチマーク方法
ベンチマーク方法は、PHPのベンチマークスクリプトから、同一マシンのMySQLに対して、Memcachedプロトコル経由で追加、読み込み、更新、削除をそれぞれ10万回実行するのにかかった時間と、同じくPHPのベンチマークスクリプトからSQLを通じて同様の追加、読み込み、更新、削除を10万回実行するのにかかった時間を比較します。
ベンチマークスクリプト
ベンチマークスクリプトは以下になります。
接続処理は一回のみ、SQLについてはプリペアドステートメントを利用しています。
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<?php define("REQUESTS", 100000); define("VALUE_LENGTH", 30); // memcached test case $memcached = new Memcached; $memcached->addServer('localhost', 11211); // memcached set benchmark $time_start = microtime(true); for ($i = 1; $i <= REQUESTS; $i++) { $value = str_repeat("x", VALUE_LENGTH); $memcached->set($i, $value); } $time_end = microtime(true); printf("memcached set %d回 %.2f秒\n", REQUESTS, $time_end - $time_start); // memcached get benchmark $time_start = microtime(true); for ($i = 1; $i <= REQUESTS; $i++) { $memcached->get($i); } $time_end = microtime(true); printf("memcached get %d回 %.2f秒\n", REQUESTS, $time_end - $time_start); // memcached delete benchmark $time_start = microtime(true); for ($i = 1; $i <= REQUESTS; $i++) { $memcached->delete($i); } $time_end = microtime(true); printf("memcached del %d回 %.2f秒\n", REQUESTS, $time_end - $time_start); $memcached->quit(); // mysql query test case $mysqli = new mysqli("127.0.0.1", "root", "Password1!", "test"); // sql insert benchmark $stmt = $mysqli->prepare("INSERT INTO demo_test (c1, c2) VALUES (?, ?)"); $stmt->bind_param('ss', $i, $value); $value = str_repeat("x", VALUE_LENGTH); $time_start = microtime(true); for ($i = 1; $i <= REQUESTS; $i++) { $stmt->execute(); } $stmt->close(); $time_end = microtime(true); printf("SQL set %d回 %.2f秒\n", REQUESTS, $time_end - $time_start); // sql select benchmark $stmt = $mysqli->prepare("SELECT c2 FROM demo_test WHERE c1 = ?"); $stmt->bind_param("s", $i); $time_start = microtime(true); for ($i = 1; $i <= REQUESTS; $i++) { $stmt->execute(); $stmt->bind_result($v); while ($stmt->fetch()) { // nothing to do } } $stmt->close(); $time_end = microtime(true); printf("SQL get %d回 %.2f秒\n", REQUESTS, $time_end - $time_start); // sql delete benchmark $stmt = $mysqli->prepare("DELETE FROM demo_test WHERE c1 = ?"); $stmt->bind_param("s", $i); $time_start = microtime(true); for ($i = 1; $i <= REQUESTS; $i++) { $stmt->execute(); } $stmt->close(); $time_end = microtime(true); printf("SQL del %d回 %.2f秒\n", REQUESTS, $time_end - $time_start); $mysqli->close(); |
ベンチマーク結果
プロトコル | 処理 | 結果 |
---|---|---|
Memcached | 追加 | 124.84秒 |
Memcached | 取得 | 3.66秒 |
Memcached | 削除 | 125.40秒 |
SQL | 追加 | 129.55秒 |
SQL | 取得 | 8.01秒 |
SQL | 削除 | 132.09秒 |
追加と削除については、プロトコルの違いで大きな速度差はありませんでした。
これは更新処理にかかる時間の大半はディスクへの書き出しなど重い処理が占めているため、Memcachedプラグインを使うことで得られる高速化の影響がそれほど現れなかったと考えられます。
取得についてはMemcachedプロトコルを使うことで実行にかかる時間が半分程度になったことから大きく高速化されたと言えると思います。
まとめ
計三回にわたってMySQLのInnoDB Memcachedプラグインについて取り上げてきました。
下記の用途以外にも、MySQLのInnoDBとして格納されることから工夫次第では色々な使い方ができると思います。
- Memcachedプロトコルを使いながらデータの高可用性を実現したい
- MySQLに格納されている比較的単純なデータの読み込み処理を高速化したい
- Key/Value なデータをリアルタイムにMySQLの他のテーブルとJOINして使いたい