InnoDB Cluster与MySQL Cluster是完全不同的:InnoDB Cluster用于InnoDB,而MySQL Cluster用于NDB。
InnoDB Cluster并没有单独的应用,它是由3个应用共同协作构成的:
进入官方下载页面:
https://dev.mysql.com/downloads/shell/
MySQL当前最新版为8.0.21。本次以该版本为例。
文中会多次用到cmd。打开cmd后,需cd到 mysql/bin/ 目录下。也可以直接将该目录配置到系统环境变量中,这样打开cmd无需cd即可调用mysql命令。下文将不再强调这一点。
安装MySQL Community Server,需要创建my.ini配置文件并添加配置。一个示例配置如下:
[client]
# 设置mysql客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8mb4
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8mb4
[mysqld]
# 日志时间
log_timestamps=SYSTEM
# 设置3306端口
port=3306
# 设置mysql的安装目录
basedir=D:\Program Files\mysql
# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
# datadir=D:\\sqldata
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10
# 服务端使用的字符集默认为utf8mb4
character-set-server=utf8mb4
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用“mysql_native_password”插件认证
#mysql_native_password
default_authentication_plugin=mysql_native_password
# 不使用严格模式
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
任何对my.ini配置文件的修改,都必须重启MySQL服务才能生效。
不需要也不推荐在其中添加任何集群相关的配置。
若需要MySQL恢复初始状态,又不想卸载重新安装,可执行如下步骤来重置MySQL:
net stop mysql
来停止服务。mysqld --initialize --console
,等待初始化完成,记下密码。net start mysql
来启动服务。这样,MySQL就重置完成了。
需要为MySQL创建'root'@'%'
用户并为其赋权。
打开cmd,首先登陆MySQL:
mysql -u root -p
输入密码后,若是第一次运行MySQL,则需要修改密码,下面将密码改为123456。否则跳过这一步:
alter user 'root'@'localhost' identified by '123456';
然后依次输入:
create user 'root'@'%' identified by '123456';
grant all privileges on *.* to 'root'@'%' with grant option;
flush privileges;
3台服务器,1台安装系统windows 10,2台安装windows 7。都已安装MySQL 8.0.21,使用相同的my.ini配置文件,并按上述步骤创建'root'@'%'
用户并赋权。
查看我的电脑属性,可以看到这三台机器的计算机名,其ip与计算机名分别为:
接下来要以192.168.15.98作为主服务器。
为了防止防火墙影响,关闭三台服务器的防火墙。生产环境防火墙不能关闭,则需要开放3306和33061两个端口。
对三台机器都执行如下操作:
打开 C:\Windows\System32\drivers\etc\
,将hosts文件复制到桌面上。打开桌面上的hosts文件,在最后添加:
192.168.15.98 YJPC-20200402
192.168.15.38 BF-20191127EQLK
192.168.15.115 PC-20180424RHNT
将hosts文件复制回 C:\Windows\System32\drivers\etc\
,替换。
日志文件位于*/mysql/data/计算机名.err*,记录的是MySQL生成的日志。无论何种方式影响到MySQL,都会将日志写入该文件。
当使用MySQL Shell操作时,MySQL Shell本身控制台的输出信息是有限的,更多详细信息会被写入到*.err日志文件中。因此遇到问题时,应多分析.err日志文件。
对于集群添加/删除实例等,不仅会影响到主实例的.err日志文件,还会影响到被添加/删除实例的.err*日志文件。
打开\mysql-shell\bin\mysqlsh.exe
,默认以JS方式操作。
运行指令:
dba.checkInstanceConfiguration('[email protected]:3306')
其中括号内的参数需要使用''
号包裹,@
号之前为用户名,@
号之后为数据库访问地址。
然后会提示输入密码,以及是否记住密码。
接着会列出检查结果:
打印出的表格已经给出了有问题到的变量、变量的当前值、变量的所需值、修改建议。并提示可使用dba.configureInstance()
命令来修正这些问题。按照建议对有问题的变量进行修改:
dba.configureInstance('[email protected]:3306')
在执行过程中会2次询问用户是否修改,输入y
,然后即可修改成功。
MySQL会自动重启,重新输入dba.checkInstanceConfiguration('[email protected]:3306')
来检测:
此时状态已变为OK。
对其他两台服务器也使用相同方式修正配置。
创建集群之前,MySQL Shell需要连接到一个主实例,也称为集群的种子实例。该实例会作为模板,用于该集群其他实例的同步。
输入\connect [email protected]:3306
来连接到主服务器,准备将其作为种子实例。第一次连接会提示输入密码并是否记住。连接成功,会显示connection id的值,且JS命令行会带有前缀192.168.15.98:3306 ssl。
输入var cluster = dba.createCluster('clusterTest')
来创建一个名为clusterTest的集群,等待创建完成。创建完成后,会提示集群至少需要3个实例才能支撑1个实例的故障。
创建完成,可调用命令查看其状态:
cluster.status()
集群创建后,MySQLperformance_schema.global_variables
表会添加许多集群相关的变量,例如group_replication_ip_whitelist
、group_replication_local_address
等。只有集群创建后才会添加这些变量;当解散集群时,这些变量仅仅不会再使用,并不会被删除。
可以使用cmd登录MySQL查询这些变量,不过使用Navicat等数据库工具更方便。
MySQL Shell只是一个控制台,InnoDB Cluster本质上还是MySQL提供的功能。因此即使关闭MySQL Shell,InnoDB Cluster依然是运行的。关闭MySQL Shell后再次打开,可输入\connect root@ip:3306
来连接到任意实例并操作InnoDB Cluster。
添加实例之前,要将各个实例的地址加入到白名单中。
白名单相关的全局变量为performance_schema.global_variables
表中的group_replication_ip_whitelist
,默认值为AUTOMATIC
。
打开cmd,登陆MySQL:
mysql -u root -p123456
然后进行永久化设置:
stop group_replication;
set persist group_replication_ip_whitelist="192.168.15.98,192.168.15.38,192.168.15.115";
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;
persist
是MySQL8.0的新特性。
第一次执行很可能会遇到3092错误,详细见下文错误处理。将错误日志中的ip调用如上命令进行永久化设置即可。
网上的文章大多通过修改my.ini来永久化设置白名单。
在不使用persist
的情况下,有时无论怎样修改my.ini中的白名单并重启MySQL服务,甚至重启计算机,group_replication_ip_whitelist
始终都是AUTOMATIC
,或者之前某一次配置的值。不仅仅是白名单,此时my.ini中的非集群设置都生效了,就是集群设置不生效。
实际上,这是mysqld-auto.cnf导致的。
使用persist
永久化配置,或者调用dba.rebootClusterFromCompleteOutage()
来重启集群,都会创建自动配置文件mysqld-auto.cnf。该文件位于 /mysql/data/ 文件夹下。
该文件内容是一个json,会保存集群相关的一些配置项。若该文件的配置项与my.ini中的配置项冲突,则优先使用该文件的配置项。这也是为什么my.ini可能会失效的原因,故而不推荐在my.ini中添加集群相关配置。
可以调用set persist 变量名=变量值
来更改某个要永久化的变量,或者直接修改mysqld-auto.cnf。
网上对白名单进行动态设置的方法通常为:打开cmd,登陆MySQL,然后依次输入:
stop group_replication;
set global group_replication_ip_whitelist="192.168.15.98,192.168.15.38,192.168.15.115";
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;
但实际上,动态设置的group_replication_ip_whitelist
值,会在MySQL服务重启后失效。
每次重启MySQL服务,根据mysqld-auto.cnf中是否配置了group_replication_ip_whitelist
变量的值:
AUTOMATIC
。不推荐该方式,建议直接使用永久化设置。
loose-
前缀如前文所说,不推荐使用my.ini来进行任何集群相关的设置。该处仅仅是一个说明,不需要了解的可跳过。
网上各种资料配置my.ini白名单使用的设置都是loose-group_replication_ip_whitelist
。
loose-
前缀的作用是:当启动MySQL服务时若使用本配置的插件尚未加载,则不报错,令MySQL服务继续加载。若没有该前缀,则若MySQL没有启用组复制插件,那么MySQL将无法启动。
因此,当数据库刚初始化时,由于这时没有使用组复制相关的插件,若不带loose-
前缀,必然会报错。但若带上loose-
前缀,就可以继续加载了。
同理,若数据库中尚未创建集群,那么若此时my.ini中使用了不带loose-
前缀的配置项,一旦重启MySQL服务,会发现MySQL服务无法启动。
总之就是:推荐带上loose-
前缀,这样无论是否使用了组复制插件都不会报错。
打开MySQL Shell:
输入\connect [email protected]:3306
来连接到主实例。
定义变量来保存集群对象:
var cluster = dba.getCluster()
获取到cluster
变量后,可调用命令查看其状态:
cluster.status()
只要连接到InnoDB Cluster上的任意实例,都可获取cluster。
将另一个实例添加到该集群中来:
cluster.addInstance('[email protected]:3306')
提示选择一种恢复策略,用于决定实例如何恢复与集群同步所需的事务。提供了2种策略:
并提示 (default Clone),即默认为克隆。可根据需求选择。这里选择第一项克隆,输入C
。
若从实例只参与集群,不做其他用途,则可以选克隆;若从实例除了集群还有其他作用,则需要选择增量。
等待执行完成,提示添加成功:
其他实例按相同方式添加。
这样,集群就构成了。对主实例进行任何操作,都会同步到从实例中。
其中:
REQUIRED
/DISABLED
,默认为REQUIRED
。可在createCluster()
或addInstance()
时设置memberSslMode
从而更改该值。此参数返回的值对应于实例上的group_replication_ssl_mode服务器变量的值。R/W
为读写,R/O
为只读。H/A
。ONLINE
:实例在线并参与集群。OFFLINE
:实例离线。RECOVERING
:实例正在与集群同步,同步完成后将变为ONLINE
。UNREACHABLE
:实例不可达,与集群无法通信。ERROR
:实例在回复阶段或应用事务时遇到错误。ERROR
状态的实例其super_read_only
将被设置为ON
。MISSING
:已在元数据中注册但在实时集群中找不到的实例。cluster.status({'extended':value})
传入额外的参数值来显示不同的信息,value的取值为:
MySQL Router单独配置时,通常是手动在根目录下添加一个mysqlrouter.ini文件。
但结合InnoDB Cluster使用时,则是使用--bootstrap
命令来自动生成配置文件。
首先打开cmd,cd到 /mysql-router/bin/ 目录下。然后调用--bootstrap
命令来自动生成配置文件:
mysqlrouter --bootstrap [email protected]:3306
此时查看MySQL Router根目录,会发现自动生成了2个文件:mysqlrouter.conf和mysqlrouter.key。其中mysqlrouter.conf就是生成的配置文件。
查看mysqlrouter.conf,会发现创建了如下几个端口设置:
当客户端连接到一个端口并进行操作时,MySQL Router就会进行重定向。
策略可修改。
然后执行命令来启动MySQL Router:
mysqlrouter &
若出现提示
logging facility initialized, switching logging to loggers specified in configuration
且新的一行出现小横线且无法再输入,即运行成功。
最底层为多个MySQL实例,由InnoDB Cluster负责同步。这些实例需要分别访问。
向上一层为MySQL Router,对多个MySQL实例进行了统一入口,只需要访问单一端口,即可对整个集群进行操作。使得整个集群结构对用户透明。
最上层为用户,只需要访问MySQL Router提供的读写/只读端口。
也就是说,对于最上层用户而言,只需要区分哪个操作用读写端口,哪个操作用只读端口。地址是唯一的。
创建一个名为script.bat的文件,在其中添加脚本:
echo 访问6446端口:主实例,读写.
mysql -uroot -p123456 -P6446 --protocol=TCP -N -r -B -e"select @@hostname"
mysql -uroot -p123456 -P6446 --protocol=TCP -N -r -B -e"select @@hostname"
mysql -uroot -p123456 -P6446 --protocol=TCP -N -r -B -e"select @@hostname"
echo 访问6447端口:从实例,只读.
mysql -uroot -p123456 -P6447 --protocol=TCP -N -r -B -e"select @@hostname"
mysql -uroot -p123456 -P6447 --protocol=TCP -N -r -B -e"select @@hostname"
mysql -uroot -p123456 -P6447 --protocol=TCP -N -r -B -e"select @@hostname"
其中:
然后在同一目录下再创建一个名为test.bat的文件,在其中添加脚本:
script.bat >result.txt
双击运行test.bat,等待执行完成,会在同目录下生成result.txt文件,打开即可看到执行结果。
操作 | 方法示例 |
---|---|
连接实例 | \connect [email protected]:3306 |
检测实例状态 | dba.checkInstanceConfiguration('[email protected]:3306') |
自动修正实例设置 | dba.configureInstance('[email protected]:3306') |
删除集群元数据 | dba.dropMetadataSchema() |
创建集群 | var cluster = dba.createCluster('clusterTest') |
向集群中添加实例 | cluster.addInstance('[email protected]:3306') |
从集群中删除实例 | cluster.removeInstance('[email protected]:3306') |
从集群中删除实例(强制) | cluster.removeInstance('[email protected]:3306',{force:true}) |
查看集群状态 | cluster.status() |
查看集群描述 | cluster.describe() |
重启集群 | var cluster = dba.rebootClusterFromCompleteOutage() |
解散集群 | cluster.dissolve({force:true}) |
指定一个新的主节点 | cluster.setPrimaryInstance('[email protected]:3306') |
切换到多主模式 | cluster.switchToMultiPrimaryMode() |
切换到单主模式 | cluster.switchToSinglePrimaryMode('[email protected]:3306') |
更改集群设置 | cluster.setOption('clusterName','newCluster') |
更改集群实例设置 | cluster.setInstanceOption('[email protected]:3306', 'exitStateAction', 'READ_ONLY') |
说明:
MISSING
状态的实例,直接重启该实例的MySQL服务。调用cluster.status()
,会看到该实例的状态变更为RECOVERING
。等待其执行完成,状态会变为ONLINE
。若依然不能解决,将该实例从集群中删除,重新添加。dba.rebootClusterFromCompleteOutage()
来重启集群。\connect
连接到哪个实例,后续的操作就对哪个实例生效。例如dba.dropMetadataSchema()
会删除当前连接实例的集群元数据。当遇到错误时,要看错误是操作哪个实例出现的。若仅仅是操作一个实例导致,那么就查看该实例的日志;若是两个实例通信,则需要同时分析这两个实例的日志。
ERROR: Unable to start Group Replication for instance 'PC-20180424RHNT:3306'. Please check the MySQL server error log for more information.
Cluster.addInstance: Group Replication failed to start: MySQL Error 3096 (HY000): PC-20180424RHNT:3306: The START GROUP_REPLICATION command failed as there was an error when initializing the group communication layer. (RuntimeError)
以及日志提示:
2020-07-31T06:56:59.959400Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Timeout while waiting for the group communication engine to be ready!'
2020-07-31T06:56:59.959400Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] The group communication engine is not ready for the member to join. Local port: 33061'
2020-07-31T06:57:01.009400Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] The member was unable to join the group. Local port: 33061'
2020-07-31T06:57:07.229400Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Error connecting to all peers. Member join failed. Local port: 33061'
通常为hosts配置错误。检查通信的两个实例各自的hosts是否已正确设置。
若确认hosts配置无误,则可能是防火墙/路由器阻止,3306/33061端口不通。可以使用telnet
命令来测试目标实例的这两个端口确保畅通。
ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log.
日志位于\mysql\data\YJPC-20200402.err
。用记事本打开,可以看到提示:
2020-08-01T03:00:37.094436Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Error connecting to the local group communication engine instance.'
2020-08-01T03:00:37.159548Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] The member was unable to join the group. Local port: 33061'
2020-08-01T03:00:42.256356Z 0 [Warning] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Connection attempt from IP address ::ffff:192.168.147.1 refused. Address is not in the IP whitelist.'
有一个ip 192.168.147.1 被拒绝了,这个ip并非是三台服务器的ip。需要将此ip也加入到白名单中。
可以使用永久化方式添加,按前文方式操作即可。
ERROR 3097 (HY000): The START GROUP_REPLICATION command failed as there was an error when joining the communication group.
通常是在调用start group_replication;
时报此错误。start group_replication;
必须先设置group_replication_bootstrap_group
为on
:
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;
调用\connect
连接到主节点,然后var cluster = dba.getCluster()
时报:
Dba.getCluster: This function is not available through a session to a standalone instance (metadata exists, instance belongs to that metadata, but GR is not active) (RuntimeError)
此时可尝试重启集群:
dba.rebootClusterFromCompleteOutage()
若依然不能解决,则使用cmd方式登录MySQL,然后启动该节点的group replication:
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;
调用\connect
连接到某个从节点,然后var cluster = dba.getCluster()
时报:
Dba.getCluster: This function is not available through a session to a standalone instance (metadata exists, instance does not belong to that metadata, and GR is not active) (RuntimeError)
此时可删除从节点元数据,重新加入集群中:
dba.dropMetadataSchema();
执行过程中会报一个ERROR,提示是否禁用super_reade_only,输入y即可。
对于非当前节点报的此错误,首先要\connect
连接到错误节点。