[Oracle Cloud] MySQL Database Service で Inbound Replication をしてみた 

# はじめに

MySQL Database Service (略 MDS) には、ちょっと前に、Inbound Replication 機能が追加されました。これは、オンプレミスなどで稼働している MySQL を レプリケーションの Source(Master) にして、MDS へ非同期レプリケーションが出来る機能です。今回の記事では、Inbound Replication の設定手順を紹介します。

次の Document を参考にしています
https://docs.oracle.com/en-us/iaas/mysql-database/doc/replication.html



# 用語について

MySQL のレプリケーションで、データ同期元を Source と呼びます。データ同期先を Replica と呼びます。ちょっと前まで、Master, Slave と呼ばれていましたが、用語変更されました。今回の記事では、新しい定義で書いていきます。

https://mysqlhighavailability.com/mysql-terminology-updates/



# 制限事項

Document に書かれている通り、Inbound Replication は次の制限事項があるのでご注意ください

- 行ベースレプリケーションのみサポート
- GTIDベースのレプリケーションのみサポート
- マルチソースレプリケーションは非サポート
- レプリケーションフィルターは非サポート
- Source(Master) の `mysql` スキーマはレプリケーション対象外。また、`mysql` スキーマで変更をしてしまうと、レプリケーションが停止してしまう



# Source : MySQL のインストール

データ同期元の Source を CentOS 7 上で適当に作ります。この辺を参考に。
https://qiita.com/sugimount/items/bf44904db8201d377536



8.0.23 をインストール

```
========================================================================================================================
 Package                                   Arch              Version                 Repository                    Size
========================================================================================================================
Installing:
 mysql-community-libs                      x86_64            8.0.23-1.el7            mysql80-community            4.6 M
     replacing  mariadb-libs.x86_64 1:5.5.68-1.el7
 mysql-community-libs-compat               x86_64            8.0.23-1.el7            mysql80-community            1.2 M
     replacing  mariadb-libs.x86_64 1:5.5.68-1.el7
 mysql-community-server                    x86_64            8.0.23-1.el7            mysql80-community            518 M
Installing for dependencies:
 mysql-community-client                    x86_64            8.0.23-1.el7            mysql80-community             48 M
 mysql-community-client-plugins            x86_64            8.0.23-1.el7            mysql80-community            237 k
 mysql-community-common                    x86_64            8.0.23-1.el7            mysql80-community            621 k

Transaction Summary
========================================================================================================================
```



# Source : テストデータ作成

作った Source の MySQL にテストデータを作成します
`sugitest` スキーマ作成

```
mysql> create database sugitest;
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sugitest           |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql>
```



`sample` テーブルの作成

```
use sugitest;

CREATE TABLE sample(
 id INT(11) NOT NULL AUTO_INCREMENT,
 value INT(5) NOT NULL DEFAULT 0,
 PRIMARY KEY (id)
);

INSERT INTO sample(value) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
```





# Source : GTID Mode を有効

8.0.23 の Default では、gtid_mode が OFF になっている。Replication のために、ON へ変更

```
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery      | ON        |
| enforce_gtid_consistency         | OFF       |
| gtid_executed                    |           |
| gtid_executed_compression_period | 0         |
| gtid_mode                        | OFF       |
| gtid_next                        | AUTOMATIC |
| gtid_owned                       |           |
| gtid_purged                      |           |
| session_track_gtids              | OFF       |
+----------------------------------+-----------+
9 rows in set (0.01 sec)

mysql>
```



編集

```
sudo vim /etc/my.cnf
```



追記

```
[mysqld]
...
省略
...
log-bin
server-id=100
log-slave-updates
gtid-mode=ON
enforce-gtid-consistency=true
```



再起動

```
sudo systemctl restart mysqld
```



有効化されている

```
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery      | ON        |
| enforce_gtid_consistency         | ON        |
| gtid_executed                    |           |
| gtid_executed_compression_period | 0         |
| gtid_mode                        | ON        |
| gtid_next                        | AUTOMATIC |
| gtid_owned                       |           |
| gtid_purged                      |           |
| session_track_gtids              | OFF       |
+----------------------------------+-----------+
9 rows in set (0.00 sec)

mysql>
```



# Source  : レプリケーションユーザーの設定

ユーザー作成

```
CREATE USER rpluser001@'%' IDENTIFIED BY 'Rpl001#!' REQUIRE SSL;
```



REPLICATION SLAVE の権限付与

```
GRANT REPLICATION SLAVE on *.* to rpluser001@'%';
```



# Source : Dump ファイルを Export

MySQL Shell を使って、Dump ファイルを作成します。
https://docs.oracle.com/en-us/iaas/mysql-database/doc/importing-and-exporting-databases.html#GUID-63396585-3ECA-4202-86D7-94C6DE08CCCD

このあたりを参考に、MySQL Shell を Insall
https://qiita.com/sugimount/items/bf44904db8201d377536#mysql-shell-install



Export用ユーザー作成

```
CREATE USER sugi01@'%' IDENTIFIED BY 'mIfoO8_fai12#-gai897fao';
grant all on *.* to sugi01@'%';
```



MySQL Shell で接続

```
mysqlsh sugi01@10.0.0.63
```



接続例

```
[opc@mysql-client01 ~]$ mysqlsh sugi01@10.0.0.63
Please provide the password for 'sugi01@10.0.0.63': ***********************
Save password for 'sugi01@10.0.0.63'? [Y]es/[N]o/Ne[v]er (default No):
MySQL Shell 8.0.23

Copyright (c) 2016, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
Creating a session to 'sugi01@10.0.0.63'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 25 (X protocol)
Server version: 8.0.23 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.
 MySQL  10.0.0.63:33060+ ssl  JS >
```



ここのバケットにDumpする

![1611370271623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/6d4b292e-9243-94e1-c2db-a19353d1d35b.png)



`util.dumpInstance` で、Source MySQL の全体の Dump を取得

```
util.dumpInstance("SourceInstanceDump", {osBucketName: "mysqldump", osNamespace: "orasejapan", threads: 4, ocimds: true, compatibility: ["strip_restricted_grants"]})
```



ちなみに、自分の環境ではハマりポイントがありました。次のエラーが発生ました。

```
 JS > util.dumpInstance("SourceInstanceDump", {osBucketName: "mysqldump", osNamespace: "orasejapan", threads: 4, ocimds: true, compatibility: ["strip_restricted_grants"]})
Util.dumpInstance: Cannot load "~/.oci/oci_api_key.pem" private key associated with OCI configuration profile named "DEFAULT". (RuntimeError)
```



原因は `/home/opc/.oci/config` ファイルの中の書き方でした。`key_file` の書き方がチルダ(~) が含まれているとエラーでした。

```
[opc@mysql-client01 .oci]$ cat config
[DEFAULT]
key_file=~/.oci/oci_api_key.pem
region=ap-tokyo-1
```



絶対パスで指定すると正常に動作しました。もし同じエラーの場合は注意してください。

```
[opc@mysql-client01 .oci]$ cat config
[DEFAULT]
key_file=/home/opc/.oci/oci_api_key.pem
region=ap-tokyo-1
```



実行例

```
 MySQL  10.0.0.63:33060+ ssl  JS > util.dumpInstance("SourceInstanceDump", {osBucketName: "mysqldump", osNamespace: "orasejapan", threads: 4, ocimds: true, compatibility: ["strip_restricted_grants"]})
Acquiring global read lock
Global read lock acquired
Gathering information - done
All transactions have been started
Locking instance for backup
Global read lock has been released
Checking for compatibility with MySQL Database Service 8.0.23
NOTE: User 'root'@'localhost' had restricted privileges (AUDIT_ADMIN, BACKUP_ADMIN, BINLOG_ADMIN, BINLOG_ENCRYPTION_ADMIN, CLONE_ADMIN, CREATE TABLESPACE, ENCRYPTION_KEY_ADMIN, FILE, FLUSH_OPTIMIZER_COSTS, FLUSH_STATUS, FLUSH_TABLES, FLUSH_USER_RESOURCES, GROUP_REPLICATION_ADMIN, INNODB_REDO_LOG_ARCHIVE, INNODB_REDO_LOG_ENABLE, PERSIST_RO_VARIABLES_ADMIN, PROXY, RELOAD, REPLICATION_SLAVE_ADMIN, ROLE_ADMIN, SERVICE_CONNECTION_ADMIN, SESSION_VARIABLES_ADMIN, SET_USER_ID, SHOW_ROUTINE, SHUTDOWN, SUPER, SYSTEM_USER, SYSTEM_VARIABLES_ADMIN, TABLE_ENCRYPTION_ADMIN) removed
NOTE: User 'sugi01'@'%' had restricted privileges (AUDIT_ADMIN, BACKUP_ADMIN, BINLOG_ADMIN, BINLOG_ENCRYPTION_ADMIN, CLONE_ADMIN, CREATE TABLESPACE, ENCRYPTION_KEY_ADMIN, FILE, FLUSH_OPTIMIZER_COSTS, FLUSH_STATUS, FLUSH_TABLES, FLUSH_USER_RESOURCES, GROUP_REPLICATION_ADMIN, INNODB_REDO_LOG_ARCHIVE, INNODB_REDO_LOG_ENABLE, PERSIST_RO_VARIABLES_ADMIN, RELOAD, REPLICATION_SLAVE_ADMIN, ROLE_ADMIN, SERVICE_CONNECTION_ADMIN, SESSION_VARIABLES_ADMIN, SET_USER_ID, SHOW_ROUTINE, SHUTDOWN, SUPER, SYSTEM_USER, SYSTEM_VARIABLES_ADMIN, TABLE_ENCRYPTION_ADMIN) removed
NOTE: Database sugitest had unsupported ENCRYPTION option commented out
Compatibility issues with MySQL Database Service 8.0.23 were found and repaired. Please review the changes made before loading them.
Writing global DDL files
Writing users DDL
Preparing data dump for table `sugitest`.`sample`
Writing DDL for schema `sugitest`
Data dump for table `sugitest`.`sample` will be chunked using column `id`
Running data dump using 4 threads.
NOTE: Progress information uses estimated values and may not be accurate.
Writing DDL for table `sugitest`.`sample`
Data dump for table `sugitest`.`sample` will be written to 1 file
1 thds dumping - 100% (10 rows / ~10 rows), 7.00 rows/s, 32.00 B/s uncompressed, 0.00 B/s compressed
Duration: 00:00:01s
Schemas dumped: 1
Tables dumped: 1
Uncompressed data size: 42 bytes
Compressed data size: 0 bytes
Compression ratio: 42.0
Rows written: 10
Bytes written: 0 bytes
Average uncompressed throughput: 32.59 B/s
Average compressed throughput: 0.00 B/s
 MySQL  10.0.0.63:33060+ ssl  JS >
```



こんな具合に Bucket に DumpFile が出力されている

![1611386021375.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/42bdd499-2e26-d73d-9d19-8a8fe895b9db.png)



# Replica : Dumpfile を Import

Replica である MDS に Dumpfile を Import します

MySQL Shell で接続

```
mysqlsh admin@replica01.mysqlsubnet01.vcn.oraclevcn.com
```



実行例

```
[opc@mysql-client01 ~]$ mysqlsh admin@replica01.mysqlsubnet01.vcn.oraclevcn.com
Please provide the password for 'admin@replica01.mysqlsubnet01.vcn.oraclevcn.com': ***********************
Save password for 'admin@replica01.mysqlsubnet01.vcn.oraclevcn.com'? [Y]es/[N]o/Ne[v]er (default No):
MySQL Shell 8.0.23

Copyright (c) 2016, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
Creating a session to 'admin@replica01.mysqlsubnet01.vcn.oraclevcn.com'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 275
Server version: 8.0.23-cloud MySQL Enterprise - Cloud
No default schema selected; type \use <schema> to set one.
 MySQL  replica01.mysqlsubnet01.vcn.oraclevcn.com:3306 ssl  JS >
```



Dumpfile を Import

```
util.loadDump("SourceInstanceDump", {osBucketName: "mysqldump", osNamespace: "orasejapan", threads: 4})
```



実行例

```
 MySQL  replica01.mysqlsubnet01.vcn.oraclevcn.com:3306 ssl  JS > util.loadDump("SourceInstanceDump", {osBucketName: "mysqldump", osNamespace: "orasejapan", threads: 4})
Loading DDL and Data from OCI ObjectStorage bucket=mysqldump, prefix='SourceInstanceDump' using 4 threads.
Opening dump...
Target is MySQL 8.0.23-cloud (MySQL Database Service). Dump was produced from MySQL 8.0.23
Fetching dump data from remote location...
Fetching 1 table metadata files for schema `sugitest`...
Checking for pre-existing objects...
Executing common preamble SQL
Executing DDL script for schema `sugitest`
[Worker000] Executing DDL script for `sugitest`.`sample`
[Worker001] sugitest@sample@@0.tsv.zst: Records: 10  Deleted: 0  Skipped: 0  Warnings: 0
Executing common postamble SQL

1 chunks (10 rows, 42 bytes) for 1 tables in 1 schemas were loaded in 1 sec (avg throughput 42.00 B/s)
0 warnings were reported during the load.
 MySQL  replica01.mysqlsubnet01.vcn.oraclevcn.com:3306 ssl  JS >
```



GTID ベースのレプリケーションでは、どこまでトランザクションをレプリケーションしたかを、GTID で管理しています。MySQL Shell のユーティリティでは、Replica 側で、GTID 関連の設定が必要です。
Object Storage 内の json メタデータから、`gtidExecuted`を取得してメモします。

Object Storage の`@.json` ファイルをダウンロードします。

![1611387373790.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/eb852580-3a9c-a2b2-d27a-61c1cdbfe537.png)



この `@.json` ファイルの中身は以下。この中の `gtidExecuted` をメモっておく

```
{
    "dumper": "mysqlsh Ver 8.0.23 for Linux on x86_64 - for MySQL 8.0.23 (MySQL Community Server (GPL))",
    "version": "1.0.2",
    "origin": "dumpInstance",
    "schemas": [
        "sugitest"
    ],
    "basenames": {
        "sugitest": "sugitest"
    },
    "users": [
        "'root'@'localhost'",
        "'rpluser001'@'%'",
        "'rpluser002'@'%'",
        "'sugi01'@'%'",
        "'test2'@'%'"
    ],
    "defaultCharacterSet": "utf8mb4",
    "tzUtc": true,
    "bytesPerChunk": 64000000,
    "user": "sugi01",
    "hostname": "mysql-client01",
    "server": "mysql-source01",
    "serverVersion": "8.0.23",
    "gtidExecuted": "0e1a6a53-5cac-11eb-8d54-02001701e97e:1-3",
    "gtidExecutedInconsistent": false,
    "consistent": true,
    "mdsCompatibility": true,
    "begin": "2021-01-23 07:10:44"
}
```



メモった値を使って、gtid_purged を行います。Replica に　MySQL Client (MySQL Shell じゃないよ) を使って接続します。次にメモった値を使ってコマンドを発行します

```
mysql> call sys.set_gtid_purged("0e1a6a53-5cac-11eb-8d54-02001701e97e:1-3");
Query OK, 0 rows affected (0.00 sec)

mysql>
```



確認

```
mysql> select @@gtid_purged;
+------------------------------------------+
| @@gtid_purged                            |
+------------------------------------------+
| 0e1a6a53-5cac-11eb-8d54-02001701e97e:1-3 |
+------------------------------------------+
1 row in set (0.00 sec)

mysql>
```



memo : エラーになったとき

```
mysql> call sys.set_gtid_purged("0e1a6a53-5cac-11eb-8d54-02001701e97e:1-10");
ERROR 3546 (HY000): @@GLOBAL.GTID_PURGED cannot be changed: the added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED
```



memo : 次の gtid_purged が空白じゃないとエラーになる

```
mysql> show global variables like 'GTID%';
+----------------------------------+------------------------------------------------------------------------------------+
| Variable_name                    | Value                                                                              |
+----------------------------------+------------------------------------------------------------------------------------+
| gtid_executed                    | 0e1a6a53-5cac-11eb-8d54-02001701e97e:1-5,
cbcefcc6-5cb0-11eb-8761-020017004a1e:1-7 |
| gtid_executed_compression_period | 0                                                                                  |
| gtid_mode                        | ON                                                                                 |
| gtid_owned                       |                                                                                    |
| gtid_purged                      | 0e1a6a53-5cac-11eb-8d54-02001701e97e:1-3                                           |
+----------------------------------+------------------------------------------------------------------------------------+
5 rows in set (0.01 sec)

mysql>
```





# Replica : Channel の作成

OCI Console 上で、Create Channel を行います

![1611327494852.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/6c0fecf6-a90c-656a-f03d-b4071bed69c3.png)



各種パラメータを入れます。Source で作成したレプリケーション用のユーザー名とパスワードを指定します

```
rpluser001
Rpl001#!
```

![1611327913895.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/5ae6a5c2-d161-49a2-3e5f-f4d43f53850a.png)



Create

![1611327953254.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/f8e7d1f4-af9c-016c-a84e-f4edab64bd7b.png)



Creating

![1611327971359.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/e0831c47-099e-63d3-a5c3-bf42830339ed.png)



ステータスが NEEDS ATTENTION になった場合、レプリケーションに何らかの問題が発生しています
次の URL で「NEEDS ATTENTION」で検索すると、詳細情報が見えます
https://docs.oracle.com/en-us/iaas/mysql-database/doc/replication.html#GUID-CB1AC60B-AA87-4D7C-9D75-191449F89663

![1611328818226.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/9ab8a7bf-3ecb-4f25-c606-e699006622b0.png)



一個上の画面に戻ると、エラーメッセージが確認出来ます。自分の環境の場合は、Source のセキュリティーグループで 3306 を開けていなかったため、次のエラーが出ていました。

![1611328850292.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/9735f844-3e74-6e67-3098-78c99da77a65.png)



エラー原因を改善したあとに、Resume を押すと再開できます。

![1611329277254.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/9a8d6ecd-cf7c-c30a-0717-32a4632a66a1.png)



ACTIVE になります。これで Inbound Replication を使った非同期レプリケーションが完成です。

![1611330497665.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/8233f1c4-d73f-d8c9-6731-96bb84a610bb.png)



# レプリケーション確認

レプリケーションされているか確認するために、Source にテストデータを入れてみます

```
mysql -h 10.0.0.63 -u sugi01 -p
```



現在のデータ

```
mysql> select * from sugitest.sample;
+----+-------+
| id | value |
+----+-------+
|  1 |     1 |
|  2 |     2 |
|  3 |     3 |
|  4 |     4 |
|  5 |     5 |
|  6 |     6 |
|  7 |     7 |
|  8 |     8 |
|  9 |     9 |
| 10 |    10 |
+----+-------+
10 rows in set (0.00 sec)

mysql>
```



Source にデータを Insert します

```
INSERT INTO sugitest.sample(value) VALUES (11);
```



replica 先

```
mysql -h replica01.mysqlsubnet01.vcn.oraclevcn.com -u admin -p
```



レプリケートされている

```
mysql> select * from sugitest.sample;
+----+-------+
| id | value |
+----+-------+
|  1 |     1 |
|  2 |     2 |
|  3 |     3 |
|  4 |     4 |
|  5 |     5 |
|  6 |     6 |
|  7 |     7 |
|  8 |     8 |
|  9 |     9 |
| 10 |    10 |
| 11 |    11 |
+----+-------+
11 rows in set (0.00 sec)

mysql>
```





# memo : わかったこと

- MDS1個につき、Channel は1個まで (マルチソースレプリケーションが現状出来ないので、問題なし)
- - `mysql` スキーマ内で CREATE TABLE しても、レプリケーションされない。また、これが影響してレプリケーションが中断されるので注意 (Document で書かれているので、mysql スキーマ内で作業するのは止めよう)



# 参考URL

Inbound Replication
https://docs.oracle.com/en-us/iaas/mysql-database/doc/replication.html

https://dev.mysql.com/doc/refman/8.0/en/replication.html

MySQL Database Serviceへ移行してみよう
https://www.s-style.co.jp/blog/2021/01/7076/