【MySQL】AWS Aurora上でもgh-ostオンラインマイグレーション

[【MySQL】gh-ostでオンラインマイグレーション](http://qiita.com/suzuki_sh/items/3e1fc979a0713fbf577c)の応用編です。

gh-ostはMySQLのバイナリログを使ってテーブルを同期します。
一方で、AWSの[Amazon Aurora](https://aws.amazon.com/jp/rds/aurora/)は、バイナリログを使わない方法でリードレプリカを作成します。

※Auroraのリードレプリカが一体どういう仕組みなのかここでは省きますが、過去のAWS SummitのDeep DiveとかでAmazonの超技術を垣間見ることができます。
[\[レポート\] Amazon Aurora deep dive ～性能向上の仕組みと最新アップデート～ \#AWSSummit ｜ Developers\.IO](http://dev.classmethod.jp/cloud/aws/awssummit-2016-amazon-aurora-deep-dive/)

さてバイナリログを使っていないとなると、gh-ostの利用はどうなるのでしょうか。
gh-ostにもドキュメントがありますが

https://github.com/github/gh-ost/blob/master/doc/rds.md

>gh-ost has been updated to work with Amazon RDS however due to GitHub not relying using AWS for databases, this documentation is community driven so if you find a bug please open an issue!

(gh-ostはAmazon RDSでも動くようになったが、我々GitHubはDBにAWSは使ってないので、このドキュメントはコミュニティに懸かっている。だからバグを見つけたら是非issueを上げて欲しい)

とあり、gh-ostの特徴のひとつである「GitHub社での実績」が欠けます。
実際に使ってみました。

## 準備

下記条件でAWS RDS Auroraインスタンスを作ります。
t2.smallインスタンスが解禁されたので、検証用途でもAuroraを作りやすくなりました。

- Aurora 5.6.10a
- db.t2.small
- writer×1、reader×1

また、接続元のIPアドレスを調べてセキュリティグループでポートを開けておきます。

gh-ostを使うにはバイナリログが必要です。
先述のとおりAuroraのリードレプリカ作成にはバイナリログは使われませんが、Auroraと他のMySQL等とのレプリケーションのためにバイナリログの出力機能は存在しています。

[Aurora と MySQL との間、または Aurora と別の Aurora DB クラスターとの間のレプリケーション \- Amazon Relational Database Service](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Aurora.Overview.Replication.MySQLReplication.html#Aurora.Replication.MySQLReplication.CreateSnapshot)

gh-ostを利用するには、DB Cluster Parameter Groupにて「binlog_format=ROW」に設定しておく必要があります。

クラスターエンドポイントに接続し、`show binary logs`でバイナリログファイルが確認できればOKです。

```sql
mysql> SHOW VARIABLES LIKE "binlog_format";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.01 sec)

mysql> show binary logs;
+----------------------------+-----------+
| Log_name                   | File_size |
+----------------------------+-----------+
| mysql-bin-changelog.000001 |       120 |
| mysql-bin-changelog.000002 |     16062 |
+----------------------------+-----------+
2 rows in set (0.01 sec)
```

今回の検証には下記のデータベース/テーブルを使います。

```sql
USE sushiya;

CREATE TABLE sushi(
  id   INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(20),
  INDEX(id)
);
```

## gh-ostの実行

まず入手します。

```sh
$ wget https://github.com/github/gh-ost/releases/download/v1.0.36/gh-ost-binary-linux-20170403125842.tar.gz
$ tar xzvf ./gh-ost-binary-linux-20170403125842.tar.gz
```

gh-ostには3つのモードがありますが、Aurora上では[b. Connect to master](https://github.com/github/gh-ost/blob/master/doc/cheatsheet.md#b-connect-to-master)にて実行します。

```sh
$ ./gh-ost \
  --user="(ユーザー)" \
  --password="(パスワード)" \
  --host="(クラスターエンドポイント)" \
  --port=3306 \
  --database="sushiya" \
  --table="sushi" \
  --alter="ADD COLUMN price INT DEFAULT 100, ADD COLUMN created_at DATETIME" \
  --allow-on-master \
  --execute
```

確認します。

```sql
mysql> show create table sushi\G
*************************** 1. row ***************************
       Table: sushi
Create Table: CREATE TABLE `sushi` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `price` int(11) DEFAULT '100',
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.01 sec)
```

カラムが増えていることを確認できました。

gh-ostの特徴として[a. Connect to replica, migrate on master](https://github.com/github/gh-ost/blob/master/doc/cheatsheet.md#a-connect-to-replica-migrate-on-master)モードや[c. Migrate/test on replica](https://github.com/github/gh-ost/blob/master/doc/cheatsheet.md#c-migratetest-on-replica)モードがありますが、これらを使うためにリードレプリカに接続して実行しようとしても「バイナリログが無効」というエラーで失敗してしまいます。

```sh
$ ./gh-ost \
>   --user="(ユーザー)" \
>   --password="(パスワード)" \
>   --host="(リーダーエンドポイント)" \
>   --port=3306 \
>   --database="sushiya" \
>   --table="sushi" \
>   --alter="ADD COLUMN price INT DEFAULT 100, ADD COLUMN created_at DATETIME" \
>   --test-on-replica
2017-05-02 01:11:40 FATAL (リーダーエンドポイント):3306 must have binary logs enabled
```

もしAuroraからバイナリログを受け取って同期しているSlaveデータベースがあれば、[c\. Migrate/test on replica](https://github.com/github/gh-ost/blob/master/doc/cheatsheet.md#c-migratetest-on-replica)モードでの実行も可能なのではないかと思います。

### Interactive commandsの使用

通常のgh-ost利用時と同様に、UNIXドメインソケットを使った制御もAurora経由で可能です。

[gh\-ost/interactive\-commands\.md at master · github/gh\-ost](https://github.com/github/gh-ost/blob/master/doc/interactive-commands.md)

テーブル切り替えを保留にするフラグファイルを作成します。

```sh
$ touch /tmp/ghost.postpone.flag
```

実行します。

```sh
$ ./gh-ost \
  --user="(ユーザー)" \
  --password="(パスワード)" \
  --host="(クラスターエンドポイント)" \
  --port=3306 \
  --database="sushiya" \
  --table="sushi" \
  --alter="ADD COLUMN price INT DEFAULT 100, ADD COLUMN created_at DATETIME" \
  --allow-on-master \
  --postpone-cut-over-flag-file=/tmp/ghost.postpone.flag \
  --execute
```

`--postpone-cut-over-flag-file`オプションで、先程作成したフラグファイルを指定するとテーブルの同期だけが進み、切り替えが保留状態になります。

ここからステータスの確認など、gh-ost実行途中での操作ができます。

```sh
$ echo status | nc -U /tmp/gh-ost.sushiya.sushi.sock
```

`unposepone`でテーブルの切り替えが実行されます。

```sh
$ echo unpostpone | nc -U /tmp/gh-ost.sushiya.sushi.sock
```

確認します。

```sql
mysql> SHOW CREATE TABLE sushi\G
*************************** 1. row ***************************
       Table: sushi
Create Table: CREATE TABLE `sushi` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `price` int(11) DEFAULT '100',
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.01 sec)
```

カラムが追加されました。

Auroraでgh-ostの必要性がどれくらいあるかはさておき、Auroraでも一部条件下にてgh-ostを利用できることがわかりました。

## 参考文献

- [Amazon Auroraのbinlogを有効にしAmazon MySQLにレプリケートしてみる ｜ Developers\.IO](http://dev.classmethod.jp/cloud/aws/enable-aurora-binary-logs/)
- [Amazon Aurora のレプリケーション機能を使うときに知っておきたいこと \- Qiita](http://qiita.com/inayuta/items/195d13617527e0645e3a)
- [製品の詳細 - Amazon Aurora | AWS](https://aws.amazon.com/jp/rds/aurora/details/)