2025年7月5日土曜日

MySQL8.4.5でInnoDBClusterにMySQLRouterを適用し自動でPRIMARYにアクセスできるようにしてみた

MySQL8.4.5でInnoDBClusterにMySQLRouterを適用し自動でPRIMARYにアクセスできるようにしてみた

概要

前回 MySQL8.4.5 で InnoDBCluster を構築し FailOver 可能な MySQL 環境を構築してみました
今回は FailOver 後に PRIMARY が変わってしまうのに自動で対応するために MySQL Router を導入しバランシングしてみました

なお MySQL Router は Arm 環境には対応していないので注意しましょう

環境

  • macOS 15.5
    M1 mac 上の docker では動きません

環境

  • Ubuntu 24.04
  • docker 28.2.2
  • MySQL 8.4.5

compose.yaml

過去のやつに mysqlrouter のサービスを追加しています
次回起動時に bootstrap の設定を使うようにボリュームを使っています

services:
  mysqlrouter:
    image: container-registry.oracle.com/mysql/community-router:8.4
    depends_on:
      - mysql1
      - mysql2
      - mysql3
    environment:
      - MYSQL_HOST=mysql1
      - MYSQL_PORT=3306
      - MYSQL_USER=root
      - MYSQL_PASSWORD=rootpass
      - MYSQL_INNODB_CLUSTER_MEMBERS=3
      - MYSQL_ROUTER_BOOTSTRAP_EXTRA_OPTIONS=--conf-use-sockets --conf-use-gr-notifications
    ports:
      - "6446:6446"  # Read-write port (Primary)
      - "6447:6447"  # Read-only port (all members)
    networks:
      - mysqlnet
    restart: always

  mysql1:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33061:3306"
    command: >
      --mysql-native-password=ON
      --server-id=1
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql1_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysql2:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33062:3306"
    command: >
      --mysql-native-password=ON
      --server-id=2
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql2_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysql3:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33063:3306"
    command: >
      --mysql-native-password=ON
      --server-id=3
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql3_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysqlshell:
    image: mysql:8.4.5
    depends_on:
      - mysql1
      - mysql2
      - mysql3
    networks:
      - mysqlnet
    volumes:
      - ./scripts:/scripts
    command: >
      bash -c "
      echo 'Waiting for MySQL to be ready...' &&
      sleep 15 &&
      mysqlsh --host=mysql1 --port=3306 --user=root --password=rootpass --py < /scripts/setup_cluster.py
      "

networks:
  mysqlnet:

volumes:
  mysql1_data:
  mysql2_data:
  mysql3_data:

MYSQL_ROUTER_BOOTSTRAP_EXTRA_OPTIONS--conf-use-sockets は最後に s が付くのが正しいようです (参考)

--conf-use-gr-notifications も同様に s が付くのが正しいです

動作確認

まずは起動します

  • docker compose up -d

そして router に対して mysql コマンドが使えるか確認します

書き込みができるポートと読み込みのみのポートがあるのでそれぞれで挙動を確認しましょう
今回であれば 6446 が書き込み可能なポートで 6447 が読み込み専用ポートです

  • mysql -u root -h 192.168.1.100 --port 6446 -p

ちなみに InnoDBCluster では PRIMARY_KEY がないテーブルに対する書き込みはエラーになるので必ず PRIMARY_KEY を各テーブルに設定するようにしましょう

mysql> create database test;
Query OK, 1 row affected (0.01 sec)

mysql> use test;
Database changed
mysql> create table test (`id` int, `name` varchar(50));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test values (1, "hoge");
ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.
mysql> drop table test;
Query OK, 0 rows affected (0.01 sec)

mysql> create table test (`id` int primary key, `name` varchar(50));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test values (1, "hoge");
Query OK, 1 row affected (0.00 sec)

読み込み専用では上記のテーブルに書き込みできないことが確認できます

  • mysql -u root -h 192.168.1.100 --port 6447 -p
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | hoge |
+----+------+
1 row in set (0.00 sec)

mysql> insert into test values (2, "fuga");
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement

耐障害テスト

PRIMARY なノードを停止し他に移動した上で書き込みが継続できるか試してみます

  • docker compose stop mysql1
  • docker compose start mysql1
  • docker compose exec -it mysql1 mysqlsh --py
dba.get_cluster().status()

クラスタの状態を確認し PRIMARY なノードが移動していることを確認します
このあとで 6446 ポートに接続し問題なくデータが登録できることを確認しましょう

mysql -u root -h 10.104.37.79 --port 6446 -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 0
Server version: 8.4.5-router MySQL Community Server - GPL

Copyright (c) 2000, 2025, 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 '\h' for help. Type '\c' to clear the current input statement.

mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | hoge |
+----+------+
1 row in set (0.00 sec)

mysql> insert into test values (2,"fuga");
Query OK, 1 row affected (0.01 sec)

最後に

MySQL8.4.5 で InnoDB Cluster に MySQL Router を設定し自動的に PRIMARY にバランシングしてくれる仕組みを試しました
確かに便利ですが PRIMARY_KEY の制約などは注意が必要かもしれません

参考サイト

0 件のコメント:

コメントを投稿