CLOVER🍀

That was when it all began.

MySQL 8.4でGTIDレプリケーションを構成する

これは、なにをしたくて書いたもの?

MySQL 8.4になってからレプリケーションを行う環境を作ったことがなかったので、設定しておこうということで。

MySQLレプリケーション

MySQL 8.4のレプリケーションに関するドキュメントはこちら。

MySQL :: MySQL 8.4 Reference Manual :: 19 Replication

MySQLレプリケーションには、バイナリーログのポジションにもとづくものと、
Global Transaction Identifiers(GTID)を使ったものの2種類があります。

今回はGTIDを使ったレプリケーションで構成します。

レプリケーションの設定方法はこちら。

MySQL :: MySQL 8.4 Reference Manual :: 19.1.3.4 Setting Up Replication Using GTIDs

レプリケーションに関するSQLはこちら。

MySQL :: MySQL 8.4 Reference Manual :: 15.4 Replication Statements

このあたりは実際にレプリケーションを構成する時に出てきますが、ここではGTIDを使ったレプリケーションでの
制限事項を見ておきます。

MySQL :: MySQL 8.4 Reference Manual :: 19.1.3.7 Restrictions on Replication with GTIDs

GTIDを使ったレプリケーションでは、以下の制限があるとされています。

  • 非トランザクショナルなストレージエンジンのテーブルの更新と、トランザクショナルなストレージエンジンのテーブルの更新を同じステートメントまたはトランザクションで行えない
  • アトミックDDLをサポートするストレージエンジン(InnoDB)の場合、CREATE TABLE ... SELECTはひとつのトランザクションとしてバイナリーログに記録される
  • binlog_formatSTATEMENTに設定されていて、サーバー上でGTIDを使用している場合、トランザクション内でCREATE TEMPORARY TABLEおよびDROP TEMPORARY TABLEの使用不可
  • サポートされていないSQLの実行をエラーで失敗させる
  • sql_replica_skip_counterを使用したイベント数を指定したスキップの不可
  • IGNORE_SERVER_IDSの使用不可

アトミックDDLとは?という気になりましたが、データディクショナリーの更新、ストレージエンジンの操作、
バイナリーログの操作を単一のアトミック操作とするDDLのことらしいです。

MySQL :: MySQL 8.4 Reference Manual :: 15.1.1 Atomic Data Definition Statement Support

また、アトミックDDLトランザクションDDLではないため、使用するとその時点でアクティブなトランザクション
あると暗黙的にコミットします。

見てみると、よく使うようなDDLはアトミックDDLのようですね…。

第93回 MySQL8.0のデータディクショナリー | gihyo.jp

DDLの実行途中で中断したりした場合に、中途半端な状態にならないようにする仕組みのようです。

それではドキュメントを見るのはこれくらいにして、実際にGTIDを使ったレプリケーションを構築してみましょう。

環境

今回の環境はこちら。2つのUbuntu Linux 24.04 LTSのサーバーを用意します。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.2 LTS
Release:        24.04
Codename:       noble


$ uname -srvmpio
Linux 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

IPアドレスはそれぞれ192.168.33.10、192.168.33.11とします。

192.168.33.10はSource、192.168.33.11はReplicaにすることにします。

MySQLをインストールする

ひとまずMySQLをインストールしましょう。

$ curl -LO https://dev.mysql.com/get/mysql-apt-config_0.8.33-1_all.deb
$ sudo dpkg -i mysql-apt-config_0.8.33-1_all.deb
$ sudo apt update
$ sudo apt install mysql-server

操作はMySQL Shellから行うことにします。

$ sudo apt install mysql-shell

今回はMySQL 8.4.4がインストールされました。

$ mysqlsh --version
mysqlsh   Ver 8.4.4 for Linux on x86_64 - for MySQL 8.4.4 (MySQL Community Server (GPL))


$ mysqlsh root@localhost

 MySQL  localhost:33060+ ssl  SQL > select version();
+-----------+
| version() |
+-----------+
| 8.4.4     |
+-----------+
1 row in set (0.0008 sec)

GTIDレプリケーションを構成する

では、レプリケーションを構成していきましょう。

最初にMySQLサーバーは、2つとも停止しておきます。

$ sudo systemctl stop mysql

MySQLの設定を変更します。デフォルトの設定はこんな感じです。

$ grep -v '#' /etc/mysql/mysql.conf.d/mysqld.cnf


[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
log-error       = /var/log/mysql/error.log
Sourceのセットアップ

Sourceの設定はこのようにしました。

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
log-error       = /var/log/mysql/error.log

character_set_server  = utf8mb4
collation_server      = utf8mb4_0900_bin
transaction_isolation = READ-COMMITTED

gtid_mode = on
enforce_gtid_consistency = on

log_bin = binlog
sync_binlog = 1
binlog_expire_logs_seconds = 864000

server_id = 1

ちなみに、この部分はレプリケーションに関係ありません。

character_set_server  = utf8mb4
collation_server      = utf8mb4_0900_bin
transaction_isolation = READ-COMMITTED

またbinlog_expire_logs_secondsを設定したのはなんとなくです。

MySQLを起動。

$ sudo systemctl start mysql

レプリケーション用のユーザーを作成。

$ mysqlsh root@localhost
 MySQL  localhost:33060+ ssl  SQL > create user repl_user@'%' identified by 'password';
Query OK, 0 rows affected (0.0633 sec)


 MySQL  localhost:33060+ ssl  SQL > grant replication slave on *.* to 'repl_user'@'%';
Query OK, 0 rows affected (0.0179 sec)

権限については、未だに"slave"のようです。

バイナリーログの確認。

 MySQL  localhost:33060+ ssl  SQL > show binary log status\G
*************************** 1. row ***************************
             File: binlog.000003
         Position: 700
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: c6a5cdba-17a7-11f0-aaeb-525400d48b63:1-2
1 row in set (0.0014 sec)

これでSourceのセットアップは完了です。

Replicaのセットアップ

続いてはReplicaのセットアップです。

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
log-error       = /var/log/mysql/error.log

character_set_server  = utf8mb4
collation_server      = utf8mb4_0900_bin
transaction_isolation = READ-COMMITTED

gtid_mode = on
enforce_gtid_consistency = on

log_bin = binlog
sync_binlog = 1
binlog_expire_logs_seconds = 864000

server_id = 2
read_only = on
relay_log = relay-binlog

Sourceとの違いはserver_idの値と、read_onlyですね。

MySQLを起動。

$ sudo systemctl start mysql

MySQLに接続します。

$ mysqlsh root@localhost

レプリケーションの設定。

 MySQL  localhost:33060+ ssl  SQL > change replication source to source_host = '192.168.33.10', source_port = 3306, source_auto_position = 1, source_ssl = 1;
Query OK, 0 rows affected (0.0593 sec)

MySQL :: MySQL 8.4 Reference Manual :: 15.4.2.2 CHANGE REPLICATION SOURCE TO Statement

この時点ではレプリケーションは動作していません。

 MySQL  localhost:33060+ ssl  SQL > show replica status\G
*************************** 1. row ***************************
             Replica_IO_State:
                  Source_Host: 192.168.33.10
                  Source_User:
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File:
          Read_Source_Log_Pos: 4
               Relay_Log_File: relay-binlog.000001
                Relay_Log_Pos: 4
        Relay_Source_Log_File:
           Replica_IO_Running: No
          Replica_SQL_Running: No
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 0
              Relay_Log_Space: 158
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Source_SSL_Allowed: Yes
           Source_SSL_CA_File:
           Source_SSL_CA_Path:
              Source_SSL_Cert:
            Source_SSL_Cipher:
               Source_SSL_Key:
        Seconds_Behind_Source: NULL
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Source_Server_Id: 0
                  Source_UUID:
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State:
           Source_Retry_Count: 10
                  Source_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Source_SSL_Crl:
           Source_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Source_TLS_Version:
       Source_public_key_path:
        Get_Source_public_key: 0
            Network_Namespace:
1 row in set (0.0020 sec)

Replicaの開始。

 MySQL  localhost:33060+ ssl  SQL > start replica user = 'repl_user' password = 'password';
Query OK, 0 rows affected, 1 warning (0.1097 sec)
Note (code 1759): Sending passwords in plain text without SSL/TLS is extremely insecure.

MySQL :: MySQL 8.4 Reference Manual :: 15.4.2.4 START REPLICA Statement

ドキュメントのようにchange replication source to 〜にユーザー名とパスワードを含めると、以下のように
start replicaに含めるように警告されるのですが。

Note (code 1760): Storing MySQL user name or password information in the connection metadata repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START REPLICA; see the 'START REPLICA Syntax' in the MySQL Manual for more information.

start replicaに入れたら入れたで、やっぱり警告されるのですが…。

Note (code 1759): Sending passwords in plain text without SSL/TLS is extremely insecure.

レプリケーションステータスの確認。

 MySQL  localhost:33060+ ssl  SQL > show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 192.168.33.10
                  Source_User: repl_user
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000003
          Read_Source_Log_Pos: 700
               Relay_Log_File: relay-binlog.000002
                Relay_Log_Pos: 911
        Relay_Source_Log_File: binlog.000003
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 700
              Relay_Log_Space: 1119
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Source_SSL_Allowed: Yes
           Source_SSL_CA_File:
           Source_SSL_CA_Path:
              Source_SSL_Cert:
            Source_SSL_Cipher:
               Source_SSL_Key:
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Source_Server_Id: 1
                  Source_UUID: c6a5cdba-17a7-11f0-aaeb-525400d48b63
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 10
                  Source_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Source_SSL_Crl:
           Source_SSL_Crlpath:
           Retrieved_Gtid_Set: c6a5cdba-17a7-11f0-aaeb-525400d48b63:1-2
            Executed_Gtid_Set: c6a5cdba-17a7-11f0-aaeb-525400d48b63:1-2
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Source_TLS_Version:
       Source_public_key_path:
        Get_Source_public_key: 0
            Network_Namespace:
1 row in set (0.0017 sec)

レプリケーションが開始されたようです。

確認

最後に動作確認。

Sourceに接続して、データベース、ユーザーを作成。

$ mysqlsh root@localhost


 MySQL  localhost:33060+ ssl  SQL > create database example;
Query OK, 1 row affected (0.0318 sec)


 MySQL  localhost:33060+ ssl  SQL > create user kazuhira@'%' identified by 'password';
Query OK, 0 rows affected (0.0490 sec)


 MySQL  localhost:33060+ ssl  SQL > grant all privileges on example.* to 'kazuhira'@'%';
Query OK, 0 rows affected (0.0252 sec)


 MySQL  localhost:33060+ ssl  SQL > flush privileges;
Query OK, 0 rows affected (0.0149 sec)

作成したユーザーで接続しなおし。

$ mysqlsh kazuhira@localhost/example

テーブルとデータの作成。

 MySQL  localhost:33060+ ssl  example  SQL > create table t1(c1 varchar(20));
Query OK, 0 rows affected (0.1023 sec)


 MySQL  localhost:33060+ ssl  example  SQL > insert into t1(c1) values('foo');
Query OK, 1 row affected (0.0328 sec)


 MySQL  localhost:33060+ ssl  example  SQL > insert into t1(c1) values('bar');
Query OK, 1 row affected (0.0218 sec)


 MySQL  localhost:33060+ ssl  example  SQL > select * from t1;
+-----+
| c1  |
+-----+
| foo |
| bar |
+-----+
2 rows in set (0.0015 sec)

Replicaに接続。

$ mysqlsh kazuhira@localhost/example

データがレプリケーションされていることが確認できます。

 MySQL  localhost:33060+ ssl  example  SQL > select * from t1;
+-----+
| c1  |
+-----+
| foo |
| bar |
+-----+
2 rows in set (0.0019 sec)

なお、ReplicaはRead Onlyです。

 MySQL  localhost:33060+ ssl  example  SQL > create table t2(c2 varchar(20));
ERROR: 1290: The MySQL server is running with the --read-only option so it cannot execute this statement

これで確認できました。

おわりに

MySQL 8.4でGTIDレプリケーションの設定をしてみました。

8.0の時と変わっていませんでしたが、時々こういうのを確認しないとな、と思います。