MySQLといえばレプリケーションと言っても過言では無いかと思います。
しかしながら、MySQL Shell 8.0.19 よりMySQL Shell APIとして追加された MySQL InnoDB ReplicaSet 構成をご利用でないユーザはまだまだいらっしゃるのではと思います。
これまでも弊社ブログで何回か取り上げておりますが、MySQL InnoDB ReplicaSet とは、従来のレプリケーション構成に、Load BalancerとなるMySQL Routerを加え、それらをMySQL Shellで構成・管理する複合的なソリューションです。
MySQL Shellを使用してレプリケーションクラスタ全体を管理でき、ヘルスチェック、新規レプリカの追加、プライマリの切り替え等を簡単に行えます。
また、MySQL Routerにより負荷分散や、インスタンス単位でサービスアウトさせるといった操作もやりやすくなります。
今回は、非ReplicaSetであるレプリケーション環境を、 ReplicaSetとして構成する方法について検証したいと思います。
検証環境
ホスト名 | MySQLバージョン | 用途 |
---|---|---|
mysql-test-1 | 8.0.34 | DB#1(primary) |
mysql-test-2 | 8.0.34 | DB#2(replica1) |
mysql-test-3 | 8.0.34 | DB#3(replica2) |
mysql-test-4 | 8.0.34 | proxy(mysqlrouter) + admin(mysql-shell) |
※ すべてOSは Oracle Linux 9です
MySQL InnoDB ReplicaSet化の準備
以下に記載されている制限に該当しない必要があります。
https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-innodb-replicaset.html
詳細はドキュメントをご確認いただければと思いますが、製品上の主な制限事項は以下になります。
- プライマリは1ノードのみ(双方向レプリケーションや循環レプリケーション、マルチソースレプリケーションは不可)
- すべてのノードはMySQL 8.0以降であること
- GTIDが有効であり、GTIDを使用してレプリケーションを行っていること
binlog_format = ROW
(RBR) であること- レプリケーションフィルタが設定されていないこと
- InnoDB ReplicaSet構成時に設定されたレプリケーションチャネル以外にレプリケーションチャネル設定が無いこと
- SQL ステートメントを直接使用してプライマリを変更する事等はサポートされず、レプリケーショントポロジの変更はMySQL Shellで行うこと
前述のドキュメントでは具体的に説明していないのですが、8.0.34
のデフォルトでよいものを除き、MySQL ReplicaSetの設定上で必要なものについて例示します。
すべて [mysqld]
セクションに記載します。
変数名 | 説明 |
---|---|
server_id | レプリケーションに参加するインスタンス毎に異なる値を設定します |
report_host | MySQL Shell, MySQL Router, 各MySQL Serverから到達可能なIP/FQDNを設定します |
log_bin | --initialize-insecure を指定してdatadirを初期化した場合のみ指定します |
gtid_mode | ONにする必要があります |
enforce_gtid_consistency | gtid_mode = ONに伴い、ONにする必要があります |
binlog_transaction_dependency_tracking | WRITESETに設定する必要があります |
ほとんどのパラメータは、動的(set global)変更可能ですが、既存の環境のReplicaSet化を行う際にreport_hostが設定されていないとレプリカを検出することができず作成に失敗します。
厄介なことにreport_hostの設定には、mysqldの再起動が必要になりますので、これが一番のハードルになりそうです。
レプリケーション環境の MySQL InnoDB ReplicaSet 化
MySQL Shellからクラスタを構成・管理するためには、各ノードにクラスタ管理用のユーザが必要になります。
本来、dba.configureReplicaSetInstance()
を実行すると管理用のユーザが作成されますが、すでにレプリケーショントポロジに含まれるインスタンスでは以下のエラーで実行できません。
1 |
Dba.configureReplicaSetInstance: This function is not available through a session to an instance belonging to an unmanaged asynchronous replication topology (RuntimeError) |
そのため手動で作成する必要があります。
dba.configureReplicaSetInstance()
で作成するユーザは以下の権限を持ちます(ユーザ名を’rsadmin’@’%’とした場合)
※ ブログの表示の都合上、下記結果の`(バッククォート) を'(シングルコーテーション)に変えています
1 2 3 4 5 6 7 8 9 10 11 |
mysql> show grants for rsadmin; +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Grants for rsadmin@% | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | GRANT SELECT, RELOAD, SHUTDOWN, PROCESS, FILE, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE USER ON *.* TO 'rsadmin'@'%' WITH GRANT OPTION | | GRANT CLONE_ADMIN,CONNECTION_ADMIN,GROUP_REPLICATION_ADMIN,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_APPLIER,REPLICATION_SLAVE_ADMIN,ROLE_ADMIN,SYSTEM_VARIABLES_ADMIN ON *.* TO 'rsadmin'@'%' WITH GRANT OPTION | | GRANT INSERT, UPDATE, DELETE ON 'mysql'.* TO 'rsadmin'@'%' WITH GRANT OPTION | | GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON 'mysql_innodb_cluster_metadata'.* TO 'rsadmin'@'%' WITH GRANT OPTION | | GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON 'mysql_innodb_cluster_metadata_bkp'.* TO 'rsadmin'@'%' WITH GRANT OPTION | | GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON 'mysql_innodb_cluster_metadata_previous'.* TO 'rsadmin'@'%' WITH GRANT OPTION | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
ReplicaSet化については、以下のドキュメントに従い、プライマリノードに接続した後、 dba.createReplicaSet()
に 'adoptFromAR':1
を指定して実行します。
https://dev.mysql.com/doc/mysql-shell/8.0/en/replicaset-adopting.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
MySQL JS > \c rsadmin@mysql-test-1 MySQL mysql-test-1:33060+ ssl JS > rs = dba.createReplicaSet('rs-1', {'adoptFromAR':1}) A new replicaset with the topology visible from 'mysql-test-1:3306' will be created. * Scanning replication topology... ** Scanning state of instance mysql-test-1:3306 ** Scanning state of instance mysql-test-2:3306 ** Scanning state of instance mysql-test-3:3306 * Discovering async replication topology starting with mysql-test-1:3306 Discovered topology: - mysql-test-1:3306: uuid=8c4b0331-7324-11ee-98f6-525400758124 read_only=no - mysql-test-2:3306: uuid=8d5bb8e2-7324-11ee-912d-525400385495 read_only=no - replicates from mysql-test-1:3306 source="mysql-test-1:3306" channel= status=ON receiver=ON coordinator=ON applier0=ON applier1=ON applier2=ON applier3=ON - mysql-test-3:3306: uuid=8ec759a5-7324-11ee-98c7-525400de7cf1 read_only=no - replicates from mysql-test-1:3306 source="mysql-test-1:3306" channel= status=ON receiver=ON coordinator=ON applier0=ON applier1=ON applier2=ON applier3=ON * Checking configuration of discovered instances... This instance reports its own address as mysql-test-1:3306 mysql-test-1:3306: Instance configuration is suitable. This instance reports its own address as mysql-test-2:3306 mysql-test-2:3306: Instance configuration is suitable. This instance reports its own address as mysql-test-3:3306 mysql-test-3:3306: Instance configuration is suitable. * Checking discovered replication topology... mysql-test-1:3306 detected as the PRIMARY. Replication state of mysql-test-2:3306 is OK. Replication state of mysql-test-3:3306 is OK. Validations completed successfully. * Updating metadata... ReplicaSet object successfully created for mysql-test-1:3306. Use rs.addInstance() to add more asynchronously replicated instances to this replicaset and rs.status() to check its status. <ReplicaSet:rs-1> |
全てのノードが正常に動作しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
MySQL mysql-test-1:33060+ ssl JS > rs.status() { "replicaSet": { "name": "rs-1", "primary": "mysql-test-1:3306", "status": "AVAILABLE", "statusText": "All instances available.", "topology": { "mysql-test-1:3306": { "address": "mysql-test-1:3306", "instanceRole": "PRIMARY", "mode": "R/W", "status": "ONLINE" }, "mysql-test-2:3306": { "address": "mysql-test-2:3306", "instanceRole": "SECONDARY", "mode": "R/O", "replication": { "applierStatus": "APPLIED_ALL", "applierThreadState": "Waiting for an event from Coordinator", "applierWorkerThreads": 4, "receiverStatus": "ON", "receiverThreadState": "Waiting for source to send event", "replicationLag": null, "replicationSsl": null }, "status": "ONLINE" }, "mysql-test-3:3306": { "address": "mysql-test-3:3306", "instanceRole": "SECONDARY", "mode": "R/O", "replication": { "applierStatus": "APPLIED_ALL", "applierThreadState": "Waiting for an event from Coordinator", "applierWorkerThreads": 4, "receiverStatus": "ON", "receiverThreadState": "Waiting for source to send event", "replicationLag": null, "replicationSsl": null }, "status": "ONLINE" } }, "type": "ASYNC" } } |
スイッチオーバも正常に動作しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
MySQL mysql-test-1:33060+ ssl JS > rs.setPrimaryInstance("rsadmin@mysql-test-2") mysql-test-2:3306 will be promoted to PRIMARY of 'rs-1'. The current PRIMARY is mysql-test-1:3306. * Connecting to replicaset instances ** Connecting to mysql-test-1:3306 ** Connecting to mysql-test-2:3306 ** Connecting to mysql-test-3:3306 ** Connecting to mysql-test-1:3306 ** Connecting to mysql-test-2:3306 ** Connecting to mysql-test-3:3306 * Performing validation checks ** Checking async replication topology... ** Checking transaction state of the instance... * Synchronizing transaction backlog at mysql-test-2:3306 ** Transactions replicated ############################################################ 100% * Updating metadata * Acquiring locks in replicaset instances ** Pre-synchronizing SECONDARIES ** Acquiring global lock at PRIMARY ** Acquiring global lock at SECONDARIES * Updating replication topology ** Changing replication source of mysql-test-1:3306 to mysql-test-2:3306 ** Changing replication source of mysql-test-3:3306 to mysql-test-2:3306 mysql-test-2:3306 was promoted to PRIMARY. |
MySQL Router用ユーザをを追加します。
1 2 3 4 5 6 7 8 |
MySQL mysql-test-1:33060+ ssl JS > rs.setupRouterAccount('router@mysql-test-4') Missing the password for new account router@mysql-test-4. Please provide one. Password for new account: *********** Confirm password: *********** Creating user router@mysql-test-4. Account router@mysql-test-4 was successfully created |
MySQL Routerを設定し起動します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
$ mysqlrouter --bootstrap rsadmin@mysql-test-1:3306 --account=router --user=mysqlrouter Please enter MySQL password for rsadmin: # Reconfiguring system MySQL Router 8.0.35 (MySQL Community - GPL) instance... Please enter MySQL password for router: - Creating account(s) (only those that are needed, if any) - Using existing certificates from the '/var/lib/mysqlrouter' directory - Verifying account (using it to run SQL queries that would be run by Router) - Storing account in keyring - Adjusting permissions of generated files - Creating configuration /etc/mysqlrouter/mysqlrouter.conf # MySQL Router configured for the InnoDB ReplicaSet 'rs-1' After this MySQL Router has been started with the generated configuration $ /etc/init.d/mysqlrouter restart or $ systemctl start mysqlrouter or $ mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf InnoDB ReplicaSet 'rs-1' can be reached by connecting to: ## MySQL Classic protocol - Read/Write Connections: localhost:6446 - Read/Only Connections: localhost:6447 ## MySQL X protocol - Read/Write Connections: localhost:6448 - Read/Only Connections: localhost:6449 $ systemctl start mysqlrouter |
正常にロードバランスできました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ mysql_config_editor set --login-path=primary -uu -p -P6446 -h127.0.0.1 $ mysql_config_editor set --login-path=replica -uu -p -P6447 -h127.0.0.1 # for i in {1..5};do mysql --login-path=primary -NB -e "select @@hostname";done mysql-test-1 mysql-test-1 mysql-test-1 mysql-test-1 mysql-test-1 # for i in {1..5};do mysql --login-path=replica -NB -e "select @@hostname";done mysql-test-2 mysql-test-3 mysql-test-2 mysql-test-3 mysql-test-2 |
まとめ
MySQL InnoDB ReplicaSet とすることで、リモートからの死活監視もやりやすくなり、ノード追加やメンテナンスもしやすくなるかと思います。
ぜひ MySQL InnoDB ReplicaSet をお試しください!