MySQL道普請便り

第138回 オンラインスキーママイグレーションツール gh-ostを使ってみよう[その1]

この記事を読むのに必要な時間:およそ 4 分

制限事項

下記条件のうちいずれかに当てはまると実行エラーとなります。ご留意ください。

  • 対象テーブルにプライマリキーまたはNOT NULL制約がついたユニークキーがない。
  • 対象テーブルに外部キー制約がある。⁠子テーブル,親テーブルまたは両方)
  • 対象テーブルにトリガーがある。
  • 対象テーブルのプライマリーキーがJSONカラムの一部から生成されたキーである。

使ってみる

さて,前置きが長くなりましたが,ここからはgh-ostを使ってみましょう。

マスターと必須要件を満たしたレプリカのMySQLを用意します。

インストール

今回は,gh-ost実行するためのCentOS 7のサーバを用意して,そこにインストールします。gh-ostのバージョンは1.1.0です。Releasesから最新リリースの確認とダウンロードができます。

# wget https://github.com/github/gh-ost/releases/download/v1.1.0/gh-ost-1.1.0-1.x86_64.rpm
# rpm -i gh-ost-1.1.0-1.x86_64.rpm

実行

まずは,sbtest1テーブルにcol1カラムを追加するgh-ostを最小限のオプションで実行したいと思います。sbtest1テーブルは現在以下のような構成です。

CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `pad` char(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
gh-ost \
--host=192.168.0.2 \
--port=3306 \
--user="ghost_user" \
--password="xx" \
--database="sysbenchdb" \
--alter="ALTER TABLE sbtest1 ADD col1 int;" \
--execute
  • --hostレプリカのホスト名。マスターの情報はgh-ostが内部で検索します(default: "127.0.0.1")
  • --portレプリカのポート番号(default: 3306)
  • --user …接続するユーザ名
  • --password …パスワード
  • --database …データベース名
  • --alter …実行したいAlterステートメント。
  • --execute …テーブルの変更と移行を実際に実行。指定なしはテストをして終了

標準出力にログが出力されます。

[2020/12/28 10:51:56] [info] binlogsyncer.go:354 begin to sync binlog from position (binary_log.000012, 732101540)
[2020/12/28 10:51:56] [info] binlogsyncer.go:723 rotate to (binary_log.000012, 732101540)
# Migrating `sysbenchdb`.`sbtest1`; Ghost table is `sysbenchdb`.`_sbtest1_gho`
# Migrating 192.168.0.1:3306; inspecting 192.168.0.2:3306; executing on 192.168.0.3
# Migration started at Mon Dec 28 10:51:56 +0900 2020
# chunk-size: 1000; max-lag-millis: 1500ms; dml-batch-size: 10; max-load: ; critical-load: ; nice-ratio: 0.000000
# throttle-additional-flag-file: /tmp/gh-ost.throttle
# Serving on unix socket: /tmp/gh-ost.sysbenchdb.sbtest1.sock
Copy: 0/9936 0.0%; Applied: 0; Backlog: 0/1000; Time: 1s(total), 0s(copy); streamer: binary_log.000012:732104613; Lag: 0.02s, State: migrating; ETA: N/A
Copy: 0/9936 0.0%; Applied: 0; Backlog: 0/1000; Time: 2s(total), 1s(copy); streamer: binary_log.000012:732112272; Lag: 0.01s, State: migrating; ETA: N/A
Copy: 10000/10000 100.0%; Applied: 0; Backlog: 0/1000; Time: 2s(total), 1s(copy); streamer: binary_log.000012:733837596; Lag: 0.01s, State: migrating; ETA: due
Copy: 10000/10000 100.0%; Applied: 0; Backlog: 1/1000; Time: 3s(total), 1s(copy); streamer: binary_log.000012:734037044; Lag: 0.01s, State: migrating; ETA: due
Copy: 10000/10000 100.0%; Applied: 0; Backlog: 0/1000; Time: 3s(total), 1s(copy); streamer: binary_log.000012:734039306; Lag: 0.01s, State: migrating; ETA: due
[2020/12/28 10:51:59] [info] binlogsyncer.go:164 syncer is closing...
[2020/12/28 10:51:59] [error] binlogstreamer.go:77 close sync with err: sync is been closing...
[2020/12/28 10:51:59] [info] binlogsyncer.go:179 syncer is closed
2020-12-28 10:51:59 ERROR Error 1146: Table 'sysbenchdb._sbtest1_ghc' doesn't exist
# Done

このように,簡単に実行することができます。ログ内容は次回説明しますが,# Doneが出力されていれば正常終了となります。

sbtest1テーブルを確認してみます。

 CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `pad` char(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `col1` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

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

また,以下のようなテーブルも一緒に残っているのがわかります。

mysql> show tables like '_sbtest1_del';
+-------------------------------------+
| Tables_in_sysbenchdb (_sbtest1_del) |
+-------------------------------------+
| _sbtest1_del                        |
+-------------------------------------+

_sbtest1_delは基テーブルです。基本的に_TABLENAME_delという形で残されています。DROPはコストの高い処理のため,デフォルトでは基テーブルはDROPされずにリネームされます。--ok-to-drop-tableオプションをつけると実行終了時にDROPされます。

gh-ostを実行する手順として,以下の流れが良いと思います。

  1. --executeオプションなしで実行して,エラーがないか確認
  2. --executeオプションをつけて,実際に実行する

まとめ

gh-ostの概要と,簡単に実行した内容を紹介しました。外部キーやトリガーが対象テーブルにあると実行できないのは少し残念ですが,そういう場合はオンラインDDLを使うなど,状況に合わせて使い分ければ良いでしょう。今回は触れていませんが,速度に関してはMySQLのオンラインDDLが速いです。

次回は,もう少し詳しくオプション,ステータスや提供されている機能について紹介したいと思います。

著者プロフィール

北川健太郎(きたがわけんたろう)

LINE株式会社所属のデータベースエンジニア。担当はMySQLとOracle Database。好きなMySQLの機能はレプリケーションで,好きなOracleDatabaseの機能はログオントリガー。

Twitter:@keny_lala