はじめに
Mac のローカルで MySQL のレプリケーションを構築する機会があったので手順をまとめてみます。
レプリーションやリカバリなどを一度経験しておくと Amazon RDS などのクラウドサービスにおいても役に立つ場面があるかもしれません。
環境準備
Docker で mysql:8.0.39-debian を使用してレプリケーションを構築します。
ディレクトリ構成
├── .docker
│ ├── replica
│ │ ├── Dockerfile
│ │ └── my.cnf
│ └── source
│ ├── Dockerfile
│ ├── init.sql
│ ├── insert.sh
│ └── my.cnf
|
|── compose.yaml
ソースのリソース
Dockerfile
FROM mysql:8.0.39-debian
# 設定ファイルを配置
COPY ./my.cnf /etc/mysql/conf.d/my.cnf
# コンテナ初回起動時に実行する sql を配置
COPY ./init.sql /docker-entrypoint-initdb.d/init.sql
# レプリケーション確認用スクリプトを配置
COPY ./insert.sh /root/insert.sh
RUN chmod u+x /root/insert.sh
my.cnf
レプリケーションを構築するソースとレプリカのサーバシステム変数 server_id は異なる値を設定する必要があります。 またレプリケーションはバイナリログを使用します。MySQL 8系 からデフォルトでバイナリログは有効です。
設定ファイル( my.cnf )を使用して server_id を明示的に指定します。
[mysqld]
server_id=1000
init.sql
コンテナ初回起動時に説明で使用するデータベース( sample_db )とテーブル( sample )の作成およびデータを挿入する SQL を発行します( MySQL はデータベースをスキーマと呼びますが本記事ではデータベースと記載します)。
docker-entrypoint-initdb.d に配置した sql ファイルはコンテナ初回起動時に自動実行されます。
CREATE DATABASE IF NOT EXISTS `sample_db`;
USE `sample_db`;
CREATE TABLE IF NOT EXISTS sample (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT IGNORE INTO sample (name) VALUES ('Alice');
insert.sh
レプリケーション構築後はソースに加えた変更がレプリカに同期されます。
同期を確認するためにソースに 100 件 データを INSERT するスクリプトを作成しておきます。
#!/bin/bash
set -eu
MYSQL_PWD=password
export MYSQL_PWD
for i in {1..100}
do
mysql -u root -A sample_db -e "INSERT INTO sample (name) VALUES ('Bob{i}');"
done
レプリカのリソース
Dockerfile
FROM mysql:8.0.39-debian
COPY ./my.cnf /etc/mysql/conf.d/my.cnf
RUN apt-get update \
&& apt-get install -y less
my.cnf
[mysqld]
server_id=1001
compose.yaml
services:
db-source:
build:
context: .docker/source
dockerfile: Dockerfile
hostname: source
restart: always
volumes:
- db-source:/var/lib/mysql
networks:
- db-network
environment:
MYSQL_ROOT_PASSWORD: password
platform: linux/amd64
db-replica:
build:
context: .docker/replica
dockerfile: Dockerfile
hostname: replica
restart: always
volumes:
- db-replica:/var/lib/mysql
networks:
- db-network
environment:
MYSQL_ROOT_PASSWORD: password
platform: linux/amd64
networks:
db-network:
name: netowrk.local
driver: bridge
volumes:
db-source:
driver: local
db-replica:
driver: local
Docker はサービスディスカバリを使用してサービス名でコンテナ間通信ができますが分かり易さのために hostname(ホスト)を明示的に指定しています。
レプリケーションを構築
上記 Docker 環境でポジションレプリケーションを構築します。
レプリケーション構築方法を大まかに記載することが本記事の目的なので、各コマンドの詳細は説明しません。
また本記事は MySQL キーワードと予約語を小文字で記載します。
前提
source, replica の両ホストのデータベースにホスト %
ユーザー root
でアカウントを作成している前提で進めます。
環境準備の compose.yaml を使用すればアカウント root
@%
が作成されています。
1. ソースのフルバックアップを取得
ソースのフルバックアップを取得します。
host:$ docker compose exec db-replica /bin/bash
root@replica:$ mysqldump -h source -u root -p --single-transaction --default-character-set=utf8mb4 --source-data=2 --routines --triggers --events --hex-blob --all-databases > dump.sql
2. フルバックアップからレプリケーション開始ポジションを取得
フルバックアップを dump.sql として進めます。
root@replica:$ less dump.sql | grep -A3 "Position to start replication or point-in-time recovery from"
-- Position to start replication or point-in-time recovery from
--
-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.000002', MASTER_LOG_POS=157;
上記例ではレプリケーション開始ポジションはバイナリログ binlog.000002 の 157 です。
3. フルバックアップをレプリカにリストア
フルバックアップをレプリカにリストアします。
root@replica:$ mysql -h replica -u root -p < dump.sql
ホスト( -h
)の指定は省略できますが、分かり易さのために明示しています。
4. レプリケーションを設定
レプリカで以下ステートメントを発行します。
source_log_file, source_log_pos は 2. フルバックアップからレプリケーション開始ポジションを取得
で取得した値です。
root@replica > change replication source to source_host='source', source_port=3306, source_user='root', source_password='password', source_log_file='binlog.000002', source_log_pos=157;
5. レプリケーションを開始
レプリカで以下ステートメントを発行します。
root@replica > start replica;
6. レプリケーション構築を確認
レプリカで以下ステートメントを発行します。
root@replica > show replica status\G
Rplica_IO_Running, Replica_SQL_Running が Yes なら正常にレプリケーションが構築・開始されています。
7. レプリカに同期されることを確認
ソースに 100 件データを追加します。
host:$ docker compose exec db-source /root/insert.sh
レプリカに同期されたことを確認します。
host:$ docker compose exec db-replica /bin/bash
root@replica:/# mysql -h replica -u root -p -D sample_db
mysql> select * from sample;
+-----+---------+
| id | name |
+-----+---------+
| 1 | Alice |
| 2 | Bob1 |
| 3 | Bob2 |
.................
.................
| 100 | Bob99 |
| 101 | Bob100 |
+-----+---------+
レプリカに同期されていることを確認できました。
まとめ
今回は簡単ですが MySQL のレプリケーション構築の流れについて記載しました。
何かの役にたてれば幸いです。