Linux Install Memo

サーバー管理者によるLinux関連ソフトのインストールメモ

Home » □MySQL8でInnoDBクラスターを試す

□MySQL8でInnoDBクラスターを試す

・まずは環境設定

CentOS8のインストールが終わった直後くらいの状態からの構築メモ。

dnf -y update
dnf -y install emacs-nox
dnf -y install epel-release
dnf -y install certbot # pythonも一緒に入ってくれるから手抜き

alternatives --config python

で、python3を指定する。

/usr/bin/env python

で動けばOK。

クラスタを構成するインスタンス(サーバー)のホスト名をhostsファイルに記述。

emacs /etc/hosts

192.168.79.210    cl000
192.168.79.211    cl001
192.168.79.212    cl002

さらに、コマンドプロンプトにもインスタンス名が出るようにする。

emacs /etc/hostname

cl000

さらに、SELinuxを無効にしておく。

emacs /etc/sysconfig/selinux

####SELINUX=enforcing
SELINUX=permissive

さらに、MySQLに対して外部からアクセスを許可させる。(3306番ポートの開放)

firewall-cmd --add-service=mysql --zone=public --permanent
firewall-cmd --reload

※本来であれば、これとは別にiptablesでクラスタを構成するインスタンスのみが3306番ポートにアクセスできるように制限すべき。

そしたらいったん再起動。

reboot

MySQL8のインストール

CentOS8が配っているディストリビューション版ではツールが足りないのと、そもそもセキュリティレベルが低すぎるので、きちんと(?)公式からコミュニティ版をインストールする。

dnf -y install https://dev.mysql.com/get/mysql80-community-release-el8-1.noarch.rpm

dnf --repo=mysql80-community search mysql-community

dnf --repo=mysql80-community info mysql-community-server

dnf -y install --repo=mysql80-community \
	mysql-community-server mysql-community-client mysql-community-common

dnf -y install mysql-shell mysql-router-community

※mysql-community-devel mysql-community-libsを入れようとすると、コンフリクトが発生するので注意。

でもって、MySQLサーバーの基本設定をする。

emacs /etc/my.cnf

    :
#default_authentication_plugin = mysql_native_password
default_authentication_plugin = mysql_native_password

slow_query_log = 1
slow_query_log_file = /var/lib/mysql/slow_query.log
long_query_time = 3

max_connections=200
innodb_file_per_table

loose-group_replication_ip_whitelist="192.168.79.0/24"
     :

※まだこの段階ではgroup_replication_ip_whitelistはエラーになるので接頭語「loose-」をつけてスルーさせる
 https://dev.mysql.com/doc/refman/8.0/en/group-replication-ip-address-whitelisting.html

そしたらMySQLを起動して、root用の一時パスワードを確認する。

systemctl enable mysqld
systemctl restart mysqld
systemctl status mysqld

grep --color=auto 'temporary password' /var/log/mysqld.log

rootの一時パスワードでいったんMySQLにログインして、パスワードを変更する。

mysql -u root -p

SET GLOBAL validate_password.length=0;
SET GLOBAL validate_password.mixed_case_count=0;
SET GLOBAL validate_password.number_count=0;
SET GLOBAL validate_password.special_char_count=0;
SET GLOBAL validate_password.policy=LOW;

ALTER USER 'root'@'localhost' IDENTIFIED BY 'kantan7pwd';

SHOW VARIABLES LIKE '%validate_password%';

EXIT;

※簡単なパスワードを設定できるようにvalidate_password.~を変更している

・続いてクラスタの設定

MySQL ShellでMySQLにログインしてクラスタ用のアカウントを設定する。

mysqlsh
\c root@localhost
dba.configureLocalInstance()

とすると

Configuring local MySQL instance listening at port 3306 for use in an InnoDB cluster…

This instance reports its own address as localhost.localdomain:3306
Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed.

ERROR: User 'root' can only connect from 'localhost'. New account(s) with proper source address specification to allow remote connection from all instances must be created to manage the cluster.

1) Create remotely usable account for 'root' with same grants and password
2) Create a new admin account for InnoDB cluster with minimal required grants
3) Ignore and continue
4) Cancel
Please select an option [1]:

と聞かれる。

rootをそのままネットワーク接続OKなアカウントとして設定するのはちょっとアレなので、クラスタ専用のアカウント(clroot)にするため、2を選択する。

そしてアカウントとそのパスワードの設定をする。

Please provide an account name (e.g: icroot@%) to have it created with the necessary
privileges or leave empty and press Enter to cancel.
Account Name: clroot
Password for new account: *
Confirm password: * 

パスワードの確認ができると、設定を変更するか、MySQLを再起動するかと聞かれるので、それぞれyとする。

NOTE: Some configuration options need to be fixed:
+--------------------------+---------------+----------------+--------------------------------------------------+
| Variable                 | Current Value | Required Value | Note                                             |
+--------------------------+---------------+----------------+--------------------------------------------------+
| binlog_checksum          | CRC32         | NONE           | Update the server variable                       |
| enforce_gtid_consistency | OFF           | ON             | Update read-only variable and restart the server |
| gtid_mode                | OFF           | ON             | Update read-only variable and restart the server |
| server_id                | 1             |                | Update read-only variable and restart the server |
+--------------------------+---------------+----------------+--------------------------------------------------+

Some variables need to be changed, but cannot be done dynamically on the server.
Do you want to perform the required configuration changes? [y/n]: y
Do you want to restart the instance after configuring it? [y/n]: y

とすると、

Cluster admin user 'clroot'@'%' created.
Configuring instance…
The instance 'cl000:3306' was configured to be used in an InnoDB cluster.
Restarting MySQL…
NOTE: MySQL server at cl000:3306 was restarted.

となるので、設定状況を確認してみる。

dba.checkInstanceConfiguration('clroot@cl000')
Please provide the password for 'clroot@cl000': *
Save password for 'clroot@cl000'? [Y]es/[N]o/Ne[v]er (default No):
Validating local MySQL instance listening at port 3306 for use in an InnoDB cluster…

This instance reports its own address as cl000:3306
Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed.

Checking whether existing tables comply with Group Replication requirements…
No incompatible tables detected

Checking instance configuration…
Instance configuration is compatible with InnoDB cluster

The instance 'cl000:3306' is valid to be used in an InnoDB cluster.

{
     "status": "ok"
}

となればOK。

グループレプリケーション用の33061番ポートを「それぞれのインスタンス」で開ける。

emacs /etc/firewalld/services/mysql-cluster.xml

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>MySQL</short>
  <description>MySQL Database Server Group Replication</description>
  <port protocol="tcp" port="33061"/>
</service>


少し待ってfirewalldがこのxmlファイルを認識したら、

firewall-cmd --add-service=mysql-cluster --zone=public --permanent
firewall-cmd --list-services --zone=public  --permanent
firewall-cmd --reload

とすれば、インスタンス間でクラスタ用の通信が行えるようになる。

これを他のインスタンス(cl001, cl002)でも同様に行う。

・実際のクラスタの作成

ここまでの準備ができたら、あとは実際にクラスタを作成する。

まずはプライマリインスタンス(cl000)にて、

mysqlsh
\c clroot@cl000
dba.createCluster('Cluster000')

とすると、

A new InnoDB cluster will be created on instance 'cl000:3306'.

Disabling super_read_only mode on instance 'cl000:3306'.
Validating instance configuration at cl000:3306…

This instance reports its own address as cl000:3306

Instance configuration is suitable.
NOTE: Group Replication will communicate with other members using 'cl000:33061'. Use the localAddress option to override.

Creating InnoDB cluster 'Cluster000' on 'cl000:3306'…

Adding Seed Instance…
Cluster successfully created. Use Cluster.addInstance() to add MySQL instances.
At least 3 instances are needed for the cluster to be able to withstand up to
one server failure.

<Cluster:Cluster000>

としてプライマリインスタンスができる。

そしたら、インスタンス(cl001とcl002)を追加する。

cluster = dba.getCluster()

とすることで、clusterに「Cluster000」が関連付けされるので

cluster.status()

とすると、

{
    "clusterName": "Cluster000",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "cl000:3306",
        "ssl": "REQUIRED",
        "status": "OK_NO_TOLERANCE",
        "statusText": "Cluster is NOT tolerant to any failures.",
        "topology": {
            "cl000:3306": {
                "address": "cl000:3306",
                "mode": "R/W",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "cl000:3306"
} 

のようにして、クラスタに対しての操作ができるようになるので、さっそくインスタンスを追加してみる。

cluster.addInstance('clroot@cl001')

とすると、どのようなリカバリ(複製)モードにするか聞かれる。

NOTE: The target instance 'cl001:3306' has not been pre-provisioned (GTID set is empty). The Shell is unable to decide whether incremental state recovery can correctly provision it.
The safest and most convenient way to provision a new instance is through automatic clone provisioning, which will completely overwrite the state of 'cl001:3306' with a physical snapshot from an existing cluster member. To use this method by default, set the 'recoveryMethod' option to 'clone'.

The incremental state recovery may be safely used if you are sure all updates ever executed in the cluster were done with GTIDs enabled, there are no purged transactions and the new instance contains the same GTID set as the cluster or a subset of it. To use this method by default, set the 'recoveryMethod' option to 'incremental'.

Please select a recovery method [C]lone/[I]ncremental recovery/[A]bort (default Clone): 

今回は初めてのクラスタ構築なので、C(複製)でもI(増分リカバリ)でもどちらでもOK。

https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-working-with-clone.html

とすると、

NOTE: Group Replication will communicate with other members using 'cl001:33061'. Use the localAddress option to override.

Validating instance configuration at cl001:3306…

This instance reports its own address as cl001:3306

Instance configuration is suitable.
A new instance will be added to the InnoDB cluster. Depending on the amount of 
data on the cluster this might take from a few seconds to several hours.

Adding instance to the cluster…

Monitoring recovery process of the new cluster member. Press ^C to stop monitoring and let it continue in background.
Clone based state recovery is now in progress.

NOTE: A server restart is expected to happen as part of the clone process. If the
server does not support the RESTART command or does not come back after a
while, you may need to manually start it back.

* Waiting for clone to finish…
NOTE: cl001:3306 is being cloned from cl000:3306
** Stage DROP DATA: Completed
** Clone Transfer
   FILE COPY  ############################################################  100%  Completed
   PAGE COPY  ############################################################  100%  Completed
   REDO COPY  ############################################################  100%  Completed
** Stage RECOVERY: |
NOTE: cl001:3306 is shutting down…

* Waiting for server restart… ready
* cl001:3306 has restarted, waiting for clone to finish…
* Clone process has finished: 61.72 MB transferred in about 1 second (~1.00 B/s)   

State recovery already finished for 'cl001:3306'

The instance 'cl001' was successfully added to the cluster. 

として、インスタンスの追加ができたら、もう一つ(cl002)も追加。

cluster.addInstance('clroot@cl002')

こちらも

    :
The instance 'cl002' was successfully added to the cluster. 

となれば、追加完了。

cluster.status()
{
    "clusterName": "Cluster000",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "cl000:3306",
        "ssl": "REQUIRED",
        "status": "OK",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
        "topology": {
            "cl000:3306": {
                "address": "cl000:3306",
                "mode": "R/W",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            },
            "cl001:3306": {
                "address": "cl001:3306",
                "mode": "R/O",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            },
            "cl002:3306": {
                "address": "cl002:3306",
                "mode": "R/O",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "cl000:3306"
} 

これでcl000(プライマリ)、cl001(リードオンリー)、cl002(リードオンリー)のクラスタ構築ができた。

※/var/lib/mysql/mysqld-auto.cnfというファイルができる。

・MySQL Routerの設定

クラスタを構成したら、プライマリインスタンスに対して直接接続してあれこれしてもいいが、MySQL Routerというバランサーツールがあるので、これを素直に使うほうがよい。

https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-using-router.html

公式ドキュメントには、MySQL Routerはアプリケーションと同じホストでの動作を推奨しているが、とりあえず今回はプライマリインスタンス上でMySQL Routerも動かしてしまう。

まずはcl000(プライマリ)を指定して、初期設定をする。

mysqlrouter --bootstrap clroot@cl000 --user=mysqlrouter

としてパスワードを入力(mysqlshellのような*のエコーバックは無い)すると、

Please enter MySQL password for clroot:
# Bootstrapping system MySQL Router instance…

- Creating account(s) (only those that are needed, if any)
- 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   

Existing configuration backed up to '/etc/mysqlrouter/mysqlrouter.conf.bak'

# MySQL Router configured for the InnoDB Cluster 'Cluster000'

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

the cluster 'Cluster000' 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:64460
- Read/Only Connections:  localhost:64470    

というメッセージが出て、設定が完了する。

※/etc/mysqlrouter/mysqlrouter.confに設定が出力される。

MySQL Routerをサービスとして常に動かす場合には、メッセージにあるように

systemctl ebanle mysqlrouter
systemctl start mysqlrouter
systemctl status mysqlrouter

とすればよい。

・シングルプライマリモードのテスト

プライマリインスタンス(cl000)で

mysql -u root -p

としてMySQLにログインをしてテスト用のデータベースとユーザーを作る。


use mysql;

DROP DATABASE IF EXISTS `test001_db`;
DROP USER IF EXISTS 'test001'@'localhost';
DROP USER IF EXISTS 'test001'@'%';
FLUSH PRIVILEGES;

CREATE DATABASE `test001_db`;

CREATE USER 'test001'@'localhost' IDENTIFIED BY 'test001pwd';
CREATE USER 'test001'@'%' IDENTIFIED BY 'test001pwd';

SELECT user, host, plugin, authentication_string FROM user;

GRANT ALL ON `test001_db`.* TO 'test001'@'localhost';
GRANT ALL ON `test001_db`.* TO 'test001'@'%';
FLUSH PRIVILEGES;

EXIT;


すると、自動的にリードオンリーインスタンス(cl001, cl002)にもデータベースができるので、プライマリインスタンス(cl000)で、テスト用のデータベースを操作してみる。

普通にmysql(クライアント)コマンドでプライマリインスタンスに接続してもいいが、せっかくMySQL Routerを動かしたので、こちらに接続してみる。

mysql --host=cl000 --port=6446 --user=test001 -p
use test001_db;

DROP TABLE IF EXISTS `test001`;

CREATE TABLE test001
(
  column01      int,
  column02      text,
  column03      text,
  PRIMARY KEY(column01)
);

INSERT INTO test001 VALUES (1, 'bbb', 'ccc');

※テーブルにプライマリキーがないとダメ

※リードオンリーポートで上記SQLを試してみると、ちゃんとエラーになる。
 mysql –host=cl000 –port=6447 –user=test001 -p

・やっとMySQL8のクラスタ構築ができたので…

あとは公式ドキュメントを読みながら、インスタンスを止めたりして高可用性を試したり、マルチプライマリモードも試してみたい。

Name of author

Name: admin

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です