MySQL5.6のテーブルをMariaDBでMyRocksに変換する


MySQL界隈を賑わせているMyRocks。
2017/5/23リリースの **MariaDB 10.2.6** に[MyRocks(RocksDB)エンジン(alpha)が追加されました](https://mariadb.com/kb/en/mariadb/mariadb-1026-release-notes/)ので、InnoDBのテーブルを変換して使ってみました。

# はじめに

注意事項と結論ですが、本番用途ならMyRocksもチューニングしないとダメそうです。それは本記事の範囲外です。

チューニングについては、[オフィシャル](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide)にもこのような記述があります。

> Unfortunately, configuring RocksDB optimally is not trivial. Even we as RocksDB developers don't fully understand the effect of each configuration change. If you want to fully optimize RocksDB for your workload, we recommend experiments and benchmarking, while keeping an eye on the three amplification factors.

要約すると、「まだ熟れてないから自分で試してね」ということですね。

また、そもそも本記事執筆時点で **RocksDBはAlphaリリース** です。

# MariaDBの準備
インストールと簡単な設定を記載しておきます。

## インストール

[最新のMariaDB](https://downloads.mariadb.org/mariadb/+releases/)を入れましょう。本記事執筆時点では`10.2.7`が最新ですが、検証環境を構築した時点では`10.2.6`が最新でした。

本記事の環境は`CentOS7`をOSとして、以下のパッケージを入れている環境です。

- MariaDB-client-10.2.6-1.el7.centos.x86_64
- MariaDB-shared-10.2.6-1.el7.centos.x86_64
- MariaDB-common-10.2.6-1.el7.centos.x86_64
- MariaDB-devel-10.2.6-1.el7.centos.x86_64
- MariaDB-compat-10.2.6-1.el7.centos.x86_64
- MariaDB-server-10.2.6-1.el7.centos.x86_64
- **MariaDB-rocksdb-engine-10.2.6-1.el7.centos.x86_64**

`10.2.6`の時点では **MyRocksは`MariaDB-rocksdb-engine`という別のプラグインパッケージになっています** ので、`MariaDB-server`と合わせて入れましょう。


### 簡単な設定

自動的に`rocksdb.cnf`というファイルが作成されていると思います。

```bash
$ cat /etc/my.cnf.d/rocksdb.cnf
[mariadb]
plugin-load-add=ha_rocksdb.so
```

この記述さえあればRocksDBエンジンが有効化されます。
MariaDBを起動したときに以下のようにRocksDBエンジンが有効になっていることが確認できるはずです。


```sql:エンジン一覧
MariaDB> SHOW ENGINES;
+--------------------+---------+----------------------------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                                          | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------------------------+--------------+------+------------+
| ROCKSDB            | YES     | RocksDB storage engine                                                           | YES          | YES  | YES        |　←これ
| MRG_MyISAM         | YES     | Collection of identical MyISAM tables                                            | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                                               | NO           | NO   | NO         |
| Aria               | YES     | Crash-safe tables with MyISAM heritage                                           | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                                            | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables                        | NO           | NO   | NO         |
| Mroonga            | YES     | CJK-ready fulltext search, column store                                          | NO           | NO   | NO         |
| SEQUENCE           | YES     | Generated tables filled with sequential values                                   | YES          | NO   | YES        |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                                               | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, foreign keys and encryption for tables | YES          | YES  | YES        |
+--------------------+---------+----------------------------------------------------------------------------------+--------------+------+------------+
10 rows in set (0.00 sec)
```

`ROCKSDB`が見えますよね。InnoDB同様の機能を有していることもわかります。

### 設定値補足

後継バージョンでは直っているかもしれませんので補足程度ですが・・・
`MariaDB 10.2.6`ではRocksDBのディレクトリがデータベースのように認識されて「`#mysql50#.rocksdb`」というデータベースが見えてしまいます。([既知の不具合](https://jira.mariadb.org/browse/MDEV-12451)です)

上記設定ファイルに以下のパラメータを追加しておけばその問題を回避できます。

```plain:rocksdb.cnf
ignore-db-dirs=.rocksdb
```



# データベースの移行
MariaDBの準備も整ったので、データを移行してみます。
Perconaの[XtraBackup](https://www.percona.com/software/mysql-database/percona-xtrabackup)が非常に高速で便利です。

## 環境情報

今回の検証では、以下の環境間/バージョン間でデータの移行に成功しています。
(XtraBackupについては、単に手間を惜しんだだけなので、最新バージョンを使う方が良いですね）

- 移行元: CentOS6 + MySQL 5.6.12 + XtraBackup 2.2.11
- 移行先: CentOS7 + MariaDB 10.2.6 + XtraBackup 2.3.6


## バックアップ〜リストア

本題ではないのでさくっと書きます。

### バックアップ

移行元のMySQLサーバーで以下のようにバックアップを取ります。
各種パスや、`parallel`の値、lz4の圧縮率などは任意に変更してください。

```bash:バックアップ
[MySQLサーバー]
$ mkdir /var/tmp/tmp.xtrabackup

### 認証情報が必要な場合はオプションを付ける
$ innobackupex --stream=xbstream --parallel=4 --socket=/var/lib/mysql/mysql.sock /var/tmp/tmp.xtrabackup | lz4 -4 > /var/tmp/dbbackup.xbstream.lz4
```

こうして作成された`/var/tmp/dbbackup.xbstream.lz4`を移行先に転送します。

### リストア

移行先のMariaDBサーバーで以下のコマンドでリストアします。
当然ながら、今あるデータは全て吹き飛びますのでご注意下さい。

```bash:リストア
[MariaDBサーバー]

### 作業ディレクトリに移動
$ mkdir /var/tmp/tmp.xtrabackup
$ cd /var/tmp/tmp.xtrabackup

### 展開とリストア可能状態への変換
$ lz4 -d /var/tmp/dbbackup.xbstream.lz4 | xbstream -x -v
$ innobackupex --apply-log ./

### リストア
$ mv /var/lib/mysql /var/tmp/.
$ innobackupex --move-back ./
$ chown -R mysql:mysql /var/lib/mysql
```

あとはMariaDBを起動すれば、リストア完了です。

もしログに「please run mysql_upgrade」の文字列が出力されているときは、`mysql_upgrade`を打っておくと良いでしょう。

```bash:mysql_upgrade
$ mysql_upgrade
```


## RocksDBへの変換

### 事前準備
Perconaの(pt-online-schema-change)[https://www.percona.com/software/database-tools/percona-toolkit](以下pt-osc)は優秀で、RocksDBに切り替えるときにも利用できます。

オフィシャルページの指示に従って入れておきましょう。
今回の検証バージョンは以下です。

- percona-toolkit-3.0.3-1.el7.x86_64

### 元のテーブルの情報

`hoge`というテーブルを対象にします。

```sql:元のhogeテーブル情報
mysql> SHOW CREATE TABLE hoge\G

中略
ENGINE=InnoDB AUTO_INCREMENT=19103259 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED
```

これはほぼ本番相当のデータが入っている、圧縮済みInnoDBのテーブルです。
なお、下記の行数(tbl_rows)は概算なので参考程度に捉えてください。

```sql:変換前のテーブルの情報
mysql> select
    -> table_name, engine, table_rows as tbl_rows, avg_row_length as rlen,
    -> floor((data_length+index_length)/1024/1024) as allMB,
    -> floor((data_length)/1024/1024) as dMB,
    -> floor((index_length)/1024/1024) as iMB
    -> from information_schema.tables
    -> where table_schema=database() and table_name='hoge';
+------------+--------+----------+------+-------+------+------+
| table_name | engine | tbl_rows | rlen | allMB | dMB  | iMB  |
+------------+--------+----------+------+-------+------+------+
| hoge       | InnoDB | 16005625 |  605 | 13065 | 9240 | 3825 |
+------------+--------+----------+------+-------+------+------+
1 row in set (0.03 sec)
```


### エンジンの変換
このコマンドを打つイメージで、pt-oscを実行します。

```sql
ALTER TABLE hoge ENGINE=ROCKSDB ROW_FORMAT=Dynamic;
```

非常に時間がかかるので、`nohup`で投げ込みましょう。

```bash:pt-online-schema-changeの実行
### Dryrun
$ nohup pt-online-schema-change --charset=utf8 --nocheck-replication-filters --alter "ENGINE=ROCKSDB ROW_FORMAT=Dynamic" h=localhost,D=DBNAME,t=hoge,u=root --socket=/var/lib/mysql/mysql.sock --dry-run 2>&1 > /tmp/pt-osc.log &

### Execute
$ nohup pt-online-schema-change --charset=utf8 --nocheck-replication-filters --alter "ENGINE=ROCKSDB ROW_FORMAT=Dynamic" h=localhost,D=DBNAME,t=hoge,u=root --socket=/var/lib/mysql/mysql.sock --execute 2>&1 > /tmp/pt-osc.log &
```

検証環境（OpenstackのVM)では6時間強掛かりました。

### 変換後の確認

もう一度`information_schema`から情報を取ってみましょう。


```sql:変換後のテーブル情報
MariaDB> select
    -> table_name, engine, table_rows as tbl_rows, avg_row_length as rlen,
    -> floor((data_length+index_length)/1024/1024) as allMB,
    -> floor((data_length)/1024/1024) as dMB,
    -> floor((index_length)/1024/1024) as iMB
    -> from information_schema.tables
    -> where table_schema=database() and table_name='hoge';
+------------+---------+----------+------+-------+------+------+
| table_name | engine  | tbl_rows | rlen | allMB | dMB  | iMB  |
+------------+---------+----------+------+-------+------+------+
| hoge       | ROCKSDB | 17774854 |  585 | 11937 | 9926 | 2010 |
+------------+---------+----------+------+-------+------+------+
1 row in set (0.00 sec)
```

RocksDBになっていることが確認できます。わずかに容量も減っていますね。


# 使ってみる

試しに全件COUNTのクエリを投げてみます。

- 注意1) Indexが使われるため実際のデータフルスキャンとは違いますが・・・参考に捉えていただければ。
- 注意2) 違う日に比較しているので結果(件数)が異なりますが、おおよそ同じデータ量なので差異は無視してください。

### MySQL 5.6 + InnoDB

この`hoge`テーブルはなかなか大きいので、暖気前だとDiskReadが激しいことになります。

```sql:mysql暖気前
mysql> SELECT SQL_NO_CACHE COUNT(*) FROM hoge;
+----------+
| COUNT(*) |
+----------+
| 17824275 |
+----------+
1 row in set (48.98 sec)
```

暖気後はバッファプールに乗るため、多少は速い結果となります。
(それでも4秒かかってますね・・・)

```sql:mysql暖気後
mysql> SELECT SQL_NO_CACHE COUNT(*) FROM hoge;
+----------+
| COUNT(*) |
+----------+
| 17824275 |
+----------+
1 row in set (4.03 sec)

```


### MariaDB + RocksDB

MySQLと同様に投げ込んでみます。

```sql:RocksDB暖気前
MariaDB> SELECT SQL_NO_CACHE COUNT(*) FROM hoge;
+----------+
| COUNT(*) |
+----------+
| 17774854 |
+----------+
1 row in set (48.76 sec)
```

ほぼ同じ時間となりました。ディスク上のデータサイズがほぼ一緒だったので、納得はできます。
暖気後はどうでしょう。

```sql:RocksDB暖気後
MariaDB> SELECT SQL_NO_CACHE COUNT(*) FROM hoge;
+----------+
| COUNT(*) |
+----------+
| 17774854 |
+----------+
1 row in set (11.81 sec)
```

11秒かかってます・・・
設定をすべてデフォルトにしているのでバッファが不十分なのか、それともこれがRocksDBの構造によるオーバーヘッドなのか。

いずれにしろ、本番用途ではチューニングが必要だということはわかりました。


# 最後に

本記事はMyRocksの知見と事例が増えることを期待して執筆しました。
MySQL5.6からの移行先をMariaDBにするかMySQL5.7にするか検討している企業も多いのではないでしょうか。そのような方々にも参考になれば幸いです。