MySQL Innodb ReplicaSet 是 MySQL 团队在 2020 年推出的一款产品,用来帮助用户快速部署和管理主从复制,在数据库层仍然使用的是主从复制技术。
ReplicaSet 主要包含三个组件:MySQL Router、MySQL Server 以及 MySQL Shell 高级客户端。
MySQL Shell 负责管理 ReplicaSet 包括部署、切换、节点加入等,都可以通过内置 AdminAPI 自动化完成。
MySQL Router 是一款轻量级中间件,可在应用程序和 ReplicaSet 之间提供透明路由和读写分离功能。
系统版本:CentOS Linux release 7.8.2003 (Core)
MySQL Server:8.0.32
IP | hostname | Role |
---|---|---|
172.16.104.55 | 172-16-104-55 | Master |
172.16.104.56 | 172-16-104-56 | Secondary |
vi /etc/hosts
172.16.104.55 172-16-104-55
172.16.104.56 172-16-104-56
安装 MySQL Shell 前需要保证已经部署好两台 MySQL 8.0 版本的实例。
官方下载地址:MySQL Shell download
mv mysql-shell-8.0.31-linux-glibc2.12-x86-64bit /usr/local/mysqlsh
export PATH=/usr/local/mysqlsh/bin/:$PATH
echo 'PATH=$PATH:/usr/local/mysqlsh/bin/' >> /etc/profile
进入 MySQL Shell 使用 \py & \js 可以切换命令模式,本篇文章使用 python 模式演示:
部署好 MySQL 实例后,需要创建一个用户,提供给 MySQL Shell 使用,这里演示创建的用户是:rw_shell
GRANT CLONE_ADMIN, CONNECTION_ADMIN, CREATE USER, EXECUTE, FILE, GROUP_REPLICATION_ADMIN, PERSIST_RO_VARIABLES_ADMIN, PROCESS, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, REPLICATION_APPLIER, REPLICATION_SLAVE_ADMIN, ROLE_ADMIN, SELECT, SHUTDOWN, SYSTEM_VARIABLES_ADMIN ON *.* TO 'rw_shell'@'%' WITH GRANT OPTION;
GRANT DELETE, INSERT, UPDATE ON mysql.* TO 'rw_shell'@'%' WITH GRANT OPTION;
GRANT ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, EXECUTE, INDEX, INSERT, LOCK TABLES, REFERENCES, SHOW VIEW, TRIGGER, UPDATE ON mysql_innodb_cluster_metadata.* TO 'rw_shell'@'%' WITH GRANT OPTION;
GRANT ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, EXECUTE, INDEX, INSERT, LOCK TABLES, REFERENCES, SHOW VIEW, TRIGGER, UPDATE ON mysql_innodb_cluster_metadata_bkp.* TO 'rw_shell'@'%' WITH GRANT OPTION;
GRANT ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, EXECUTE, INDEX, INSERT, LOCK TABLES, REFERENCES, SHOW VIEW, TRIGGER, UPDATE ON mysql_innodb_cluster_metadata_previous.* TO 'rw_shell'@'%' WITH GRANT OPTION;
配置 MySQL 实例,检查是否符合创建 ReplicaSet 的条件,如果发现需要修改的地方,就会提示确认修改。
执行次命令会让用户输入密码,保存后会进入检查阶段。
dba.configure_replica_set_instance('rw_shell@172-16-104-55:3306', {"clusterAdmin": "rw_shell@'%'"})
dba.configure_replica_set_instance('rw_shell@172-16-104-56:3306', {"clusterAdmin": "rw_shell@'%'"})
MySQL Shell 会检查数据库参数是否满足创建 ReplicaSet 条件,并提出修改建议:
此阶段执行完成后,表示实例都具备组成 ReplicaSet 条件,可进入下一步。
使用 MySQL Shell 连接到主实例,否则测试中会报 session 错误。
An open session is required to perform this operation.
\c rw_shell@172-16-104-55:3306
rs = dba.create_replica_set("prd_op_service")
可通过下方命令查看 ReplicaSet 状态:
rs.status()
此时只有主库实例在线:
{
"replicaSet": {
"name": "prd_op_service",
"primary": "172-16-104-55:3306",
"status": "AVAILABLE",
"statusText": "All instances available.",
"topology": {
"172-16-104-55:3306": {
"address": "172-16-104-55:3306",
"instanceRole": "PRIMARY",
"mode": "R/W",
"status": "ONLINE"
}
}
"type": "ASYNC"
}
}
添加新实例:
rs.add_instance("172-16-104-56:3306")
MySQL Shell 支持使用 Clone 模式,快速将一个新实例加入已有数据的 ReplicaSet。
查看某个对象有多少种方法,当然也可以直接使用 help() 方法,打印帮助文档:
>> dir(rs)
[
"add_instance", # 添加新实例到 ReplicaSet 中
"disconnect", # 断开当前会话
"force_primary_instance", # 切换主实例
"get_name", # 获取当前会话中,ReplicaSet 名称
"help", # 打印帮助文档
"list_routers", # 列出当前配置的 routers
"name",
"options", # 查看配置
"rejoin_instance",
"remove_instance", # 移除一个节点
"remove_router_metadata", # 删除 router 元数据
"set_instance_option",
"set_option",
"set_primary_instance", # 执行安全的主备切换
"setup_admin_account",
"setup_router_account",
"status" # 查看 ReplicaSet 状态
]
退出 MySQL Shell 后,再次进入如何管理之前创建 ReplicaSet 呢?
首先进入主库实例:
\c rw_shell@172-16-104-55:3306
通过使用下方命令,获取当前会话的 ReplicaSet 操作对象:
rs = dba.get_replica_set()
MySQL Router 是一款轻量级的中间件,可以为 inoodb ReplicaSet 提供应用程序的透明路由和读写分离。
官方下载地址:MySQL Router Donwload
xz -d mysql-router-8.0.30-linux-glibc2.12-x86_64.tar.xz
tar -xvf mysql-router-8.0.30-linux-glibc2.12-x86_64.tar
rs.setup_router_account('op_router')
./mysqlrouter \
--bootstrap rw_shell@172-16-104-55:3306 \
--directory /data/myrouter \
--conf-use-sockets \
--account op_router \
--user=root
bootstrap:引导实例的连接串 router 会通过该实例获取 ReplicaSet 元数据信息
directory:mysql-router 数据目录
conf-use-sockets:确认生成 socket 文件
account:router 连接 MySQL 的账号,上一步已使用 mysql shell 已创建
MySQL Router 会自动生成配置文件,启动命令也打印在终端中。
./mysqlrouter -c /data/myrouter/mysqlrouter.conf &
MySQL Router 为用户提供四个端口:
-- MySQL 经典协议
- Read/Write Connections: localhost:6446, /data/myrouter/mysql.sock
- Read/Only Connections: localhost:6447, /data/myrouter/mysqlro.sock
-- MySQL X 协议
- Read/Write Connections: localhost:6448, /data/myrouter/mysqlx.sock
- Read/Only Connections: localhost:6449, /data/myrouter/mysqlxro.sock
使用 MySQL Sehll 连接到 ReplicaSet 中,此时 55 为 Primary 实例:
rs.set_primary_instance('172-16-104-56:3306')
rs.status()
使用 6446 写端口连接数据库,查看 Server-id 是否为 56,验证 router 切换后是否路由正确:
mysql -h172.16.104.56 -P6446 -urw_shell -p -e'select @@server_id;'
-- result:563306
AdminAPI 提供了一系列的方法,用户管理 ReplicaSet,运维人员可以通过这些方法对 ReplicaSet 实现日常运维管理。
add_instance(instance, {options}) 方法用于给现有的 ReplicaSet 添加只读实例,可以通过 clone 模式完整数据 copy 到新实例。
disconnect() 方法用于断开当前使用 ReplicaSet 上下文环境,管理多个 ReplicaSet 时会用到。
force_primary_instance(instance, {options}) 在当前主节点不可用且无法恢复的创建中,该方法将执行主服务器的强制故障转移功能。目标实例将提升为主服务器,而其它服务器将切换到新的主服务器。
list_routers() 列出现 MySQL Router 实例。该方法列出为集群注册的所有 MySQL Router 实例信息。
rejoin_instance(instance, {options}) 将 MySQL 实例重新加入 ReplicaSet 主,当某实例因意外原因离开,可以使用该方法重新加入 ReplicaSet。
remove_instance(instance, {options}) 从 ReplicaSet 中移除 MySQL 实例。
remove_router_metadata(routerDef) 移除 MySQL Router 元数据信息,可以使用该方法清除已不存在的实例。
set_instance_option(instance, option, value) 更改 ReplicaSet 成员的选项值。例如从 MySQL Router 中隐藏某台实例,不参与读写分离:
rs.set_instance_option("instance", "tag:_hidden", true)
set_option(option, value) 更改 ReplicaSet 整体的选项值。
set_primary_instance(instance, {options}) 执行主动切换,将一个选定的 MySQL 实例提升为主服务器。
创建或升级 innodb ReplicaSet 的管理账户。
创建或升级 MySQL Router 的账号。
查询 ReplicaSet 状态,使用 rs.status(extended=0) 指定 extended 等级 0~2,获得更详细的信息。
此时 56 位主库,55 为备库。
rs.status()
因为实验环境 MySQL Shell 和主库部署在同台机器上,不方便通过关机实验,所以本次试验通过 kill MySQL 进程进行测试。
kill -9 mysql—pid
此时程序就报出 2003 异常:
ERROR 2003 (HY000): Can’t connect to MySQL server on ‘172.16.104.56:6446’ (111)
打开 MySQL Sehll 切换为 python 模式,登录到 55 会话:
\c rw_shell@172-16-104-55:3306
获取 ReplicaSet 对象:
rs = dba.get_replica_set()
查询 ReplicaSet 当前状态:
此时 MySQL Sehll 已经检测到 56 主库不可用,并建议切换实例:
“PRIMARY instance is not available, but there is at least one SECONDARY that could be force-promoted.”
使用 AdminAPi 进行切换:
rs.force_primary_instance('172-16-104-55:3306')
故障切换完成后,业务可以正常使用 Router 提供的端口连接,rw/ro 都分配到主库实例,因为当前只剩下主库。
此时需要手动将已恢复到 56 重新添加到 ReplicaSet 中,会自动补全期间的增量数据。
rs.rejoin_instance('172-16-104-56:3306')
查询当前 ReplicaSet 状态:
验证 MySQL Router 路由,备库恢复后,会自动修改路由策略,ro 端口重新路由到备库。
【1】https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-innodb-replicaset.html
【2】https://dev.mysql.com/doc/mysql-shell/8.0/en/admin-api-deploy-router.html
【3】https://dev.mysql.com/doc/refman/8.0/en/replication.html
【4】《MySQL 高可用解决方案》