MySQL 5.6のInnoDB memcached pluginを使ってみる

MySQL 5.6の RC 版が出ましたね。魅力的な機能が満載で皆さんwktkしていることと思います。早速、個人的に気になっていた memcached plugin を試してみました。

最初に結論から言いますが、現時点 (5.6.7rc) では HandlerSocket の代わりに使えるようなものではなさそうです。

  • memcached protocol でアクセスできるのは全体で 1 テーブルのみ 訂正: namespace という仕組みで複数テーブルにmapが可能です
  • テーブルの文字コードは latin1 である必要がある

【2012-11-22 追記】5.6.8RCでは、文字コードが latin1 であるという制限は撤廃されました

「MySQL のテーブルに memcached protocol でアクセスできる」というよりは、「memcached のストレージを InnoDB にできる」ようなものと考えていただければよいのではないかと。

使ってみる

では使ってみます。といってもソースに含まれる plugin/innodb_memcached/README-innodb_memcached のままですが…

設定のための SQL を流し込んで、

$ mysql < scripts/innodb_memcached_config.sql

plugin を読み込みます。

mysql> install plugin daemon_memcached soname "libmemcached.so";
mysql> show plugins;
+----------------------------+----------+--------------------+-----------------+---------+
| Name                       | Status   | Type               | Library         | License |
+----------------------------+----------+--------------------+-----------------+---------+
(ç•¥)
| daemon_memcached           | ACTIVE   | DAEMON             | libmemcached.so | GPL     |
+----------------------------+----------+--------------------+-----------------+---------+

これで mysqld が TCP/UDP 11211 を listen します。設定は innodb_memcache というデータベースに保存されます。

mysql [localhost] (innodb_memcache) > show tables;
+---------------------------+
| Tables_in_innodb_memcache |
+---------------------------+
| cache_policies            |
| config_options            |
| containers                |
+---------------------------+
3 rows in set (0.00 sec)

mysql [localhost] (innodb_memcache) > desc containers;
+------------------------+--------------+------+-----+---------+-------+
| Field                  | Type         | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+-------+
| name                   | varchar(50)  | NO   | PRI | NULL    |       |
| db_schema              | varchar(250) | NO   |     | NULL    |       |
| db_table               | varchar(250) | NO   |     | NULL    |       |
| key_columns            | varchar(250) | NO   |     | NULL    |       |
| value_columns          | varchar(250) | YES  |     | NULL    |       |
| flags                  | varchar(250) | NO   |     | 0       |       |
| cas_column             | varchar(250) | YES  |     | NULL    |       |
| expire_time_column     | varchar(250) | YES  |     | NULL    |       |
| unique_idx_name_on_key | varchar(250) | NO   |     | NULL    |       |
+------------------------+--------------+------+-----+---------+-------+
9 rows in set (0.00 sec)

mysql [localhost] (innodb_memcache) > select * from containers\G
*************************** 1. row ***************************
                  name: aaa
             db_schema: test
              db_table: demo_test
           key_columns: c1
         value_columns: c2
                 flags: c3
            cas_column: c4
    expire_time_column: c5
unique_idx_name_on_key: PRIMARY
1 row in set (0.00 sec)

containers というテーブルに、memcached plugin 経由で実際にアクセスするテーブルの情報を保存します。

この例だと、test.demo_test というテーブルで key が c1, value が c2 に保存される、ということになります。

mysql [localhost] (test) > select * from demo_test;
+----+--------------+------+------+------+
| c1 | c2           | c3   | c4   | c5   |
+----+--------------+------+------+------+
| AA | HELLO, HELLO |    8 |    0 |    0 |
+----+--------------+------+------+------+
1 row in set (0.00 sec)

telnet で port 11211 に接続して get してみます。

$ telnet localhost 11211
Connected to localhost.

get AA
VALUE AA 8 12
HELLO, HELLO
END

取れましたね! telnet で set してみます。

$ telnet localhost 11211
Connected to localhost.

set BB 0 0 3
BBB
STORED
mysql [localhost] (test) > select * from demo_test;
+----+--------------+------+------+------+
| c1 | c2           | c3   | c4   | c5   |
+----+--------------+------+------+------+
| AA | HELLO, HELLO |    8 |    0 |    0 |
| BB | BBB          |    0 |    2 |    0 |
+----+--------------+------+------+------+
2 rows in set (0.00 sec)

保存されています。

注意点
  • flags, cas_column, expire_time_column のカラムは NULL ではいけない (memcached protocolで取得できない)
  • データを保存するテーブルの文字コードは latin1
    • 他の文字コードにすると、mysqld 起動時に "Failed to initialize instance. Error code: 13" というエラーが出力されて、memcached plugin が有効にならない
    • ↑ 5.6.7RCまで。5.6.8RCでは UTF-8 などで問題ありません

軽くベンチマーク

memslap を使ってみました。

InnoDB memcached plugin

$ memslap --servers=127.0.0.1:11211 --test set
	Took 14.781 seconds to load data

$ memslap --servers=127.0.0.1:11211 --test get
	Took 1.232 seconds to read data

本物の memcached

$ memslap --servers=127.0.0.1:11222 --test set
	Took 0.533 seconds to load data
$ memslap --servers=127.0.0.1:11222 --test get
	Took 0.655 seconds to read data

daemon_memcached_w_batch_size というパラメータで書き込みをまとめて性能を上げることができます。

# my.cnf
[mysqld]
daemon_memcached_w_batch_size = 100
$ memslap --servers=127.0.0.1:11211 --test set
	Took 4.512 seconds to load data

memstat の出力

curr_items, total_items, bytes あたりの数値は取れないようです。

$ memstat --servers=127.0.0.1:11211

Server: 127.0.0.1 (11211)
	 pid: 11353
	 uptime: 286
	 time: 1349335741
	 version: 5.6.7-rc
	 pointer_size: 64
	 rusage_user: 8.724673
	 rusage_system: 10.740367
	 curr_items: 0
	 total_items: 0
	 bytes: 0
	 curr_connections: 3
	 total_connections: 12
	 connection_structures: 3
	 cmd_get: 30000
	 cmd_set: 60000
	 get_hits: 30000
	 get_misses: 0
	 evictions: 0
	 bytes_read: 0
	 bytes_written: 0
	 limit_maxbytes: 67108864
	 threads: 4

まとめ

普通に動きます が、全体で1テーブルしか使えないとちょっと使いどころが難しいですね。

一応、 innodb_memcache.containers テーブルには name カラムがあって、そのカラムによって読み込む設定を分けるようなことは想定されているようです。が、現状は最初の1行を決めうちで読み込んでいるので、複数行入れても最初の行の設定しか有効になりません。 (訂正): containers の name に入れた値を使って、別テーブルにアクセス可能でした。namespaceを使わずにデフォルトでアクセスするのが最初の1行で定義されているテーブルです。

+------+-----------+------------+-------------+---------------+-------+------------+--------------------+------------------------+
| name | db_schema | db_table   | key_columns | value_columns | flags | cas_column | expire_time_column | unique_idx_name_on_key |
+------+-----------+------------+-------------+---------------+-------+------------+--------------------+------------------------+
| aaa  | test      | demo_test  | c1          | c2            | c3    | c4         | c5                 | PRIMARY                |
| bbb  | test      | demo_test2 | c1          | c2            | c3    | c4         | c5                 | PRIMARY                |
+------+-----------+------------+-------------+---------------+-------+------------+--------------------+------------------------+

この状態で、memcached protocol でアクセスする key を @@aaa.foo とすると demo_test.c1='foo' に、@@bbb.foo とすると demo_test2.c1='foo' にアクセスすることができます。