MySQL 官方高可用方案:Innodb ReplicaSet
说明
MySQL Innodb ReplicaSet 是 MySQL 团队在 2020 年推出的一款产品,用来帮助用户快速部署和管理主从复制,在数据库层仍然使用的是主从复制技术。
ReplicaSet 主要包含三个组件:MySQL Router、MySQL Server 以及 MySQL Shell 高级客户端。
MySQL Shell 负责管理 ReplicaSet 包括部署、切换、节点加入等,都可以通过内置 AdminAPI 自动化完成。
MySQL Router 是一款轻量级中间件,可在应用程序和 ReplicaSet 之间提供透明路由和读写分离功能。
基于系统的高可用要求,ReplicaSet 可提供 RTO 等于数分钟,RPO < 1 秒 的高可用性,适用于对高可用要求不高的场景。因为它无法自动进行故障转移,当发生故障时,需要运维人员通过 AdminAPI 进行主备切换。另外 MySQL Router 读写分离提供的是两个端口 r/w 和 ro 组,如果要使用读写分离功能,则需要应用适配。
1. 安装部署
1.1 环境说明
IP | hostname | Role |
172.16.104.55 | 172-16-104-55 | Master |
172.16.104.56 | 172-16-104-56 | Slave |
vi /etc/hosts 172.16.104.55 172-16-104-55 172.16.104.56 172-16-104-56
1.2 MySQL Shell 安装
安装 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 模式演示:
1.3 配置 MySQL 实例
部署好 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 条件,可进入下一步。
1.4 创建 ReplicaSet
使用 MySQL Shell 连接到主实例,否则测试中会报 session 错误。
An open session is required to perform this operation.
\c rw_shell@172-16-104-55:3306
创建 ReplicaSet 默认当前进入的实例为主库实例:
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
1.5 查询帮助
查看某个对象有多少种方法,当然也可以直接使用 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 状态 ]
1.6 切换上下文
退出 MySQL Shell 后,再次进入如何管理之前创建 ReplicaSet 呢?
首先进入主库实例:
\c rw_shell@172-16-104-55:3306
通过使用下方命令,获取当前会话的 ReplicaSet 操作对象:
rs = dba.get_replica_set()
2. Router 配置
MySQL Router 是一款轻量级的中间件,可以为 inoodb ReplicaSet 提供应用程序的透明路由和读写分离。
2.1 安装 router
官方下载地址: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
2.2 创建 router 用户
rs.setup_router_account('op_router')
2.3 启动 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 &
2.4 验证
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
3. ReplicaSet 维护
3.1 手动切换
使用 MySQL Sehll 连接到 ReplicaSet 中,此时 55 为 Primary 实例:
rs.set_primary_instance('172-16-104-56:3306')
查询 ReplicaSet 状态:
rs.status()
使用 6446 写端口连接数据库,查看 Server-id 是否为 56,验证 router 切换后是否路由正确:
mysql -h172.16.104.56 -P6446 -urw_shell -p -e'select @@server_id;' -- result:563306
3.2 维护方法
AdminAPI 提供了一系列的方法,用户管理 ReplicaSet,运维人员可以通过这些方法对 ReplicaSet 实现日常运维管理。
3.2.1 add_instance
add_instance(instance, {options}) 方法用于给现有的 ReplicaSet 添加只读实例,可以通过 clone 模式完整数据 copy 到新实例。
dryRun:检查阶段记录需要修改的项目,不实际执行。
lebel:为实例添加标签,标签会现在在 ststus() 方法输出的内容中。
recoveryMethod:指定数据恢复方法,包括自动、克隆或增量。
waitRecovery:恢复过程的详细级别。
cloneDonor:克隆数据的提供者,使用 “主机:端口” 格式。
interactive:是否开启命令执行向导。
timeout:事务同步操作的超时设置,默认为 0 表示强制等待事务同步结束。
3.2.2 disconnect
disconnect() 方法用于断开当前使用 ReplicaSet 上下文环境,管理多个 ReplicaSet 时会用到。
3.2.3 force_primary_instance
force_primary_instance(instance, {options}) 在当前主节点不可用且无法恢复的创建中,该方法将执行主服务器的强制故障转移功能。目标实例将提升为主服务器,而其它服务器将切换到新的主服务器。
3.2.4 list_routers
list_routers() 列出现 MySQL Router 实例。该方法列出为集群注册的所有 MySQL Router 实例信息。
3.2.5 rejoin_instance
rejoin_instance(instance, {options}) 将 MySQL 实例重新加入 ReplicaSet 主,当某实例因意外原因离开,可以使用该方法重新加入 ReplicaSet。
3.2.6 remove_instance
remove_instance(instance, {options}) 从 ReplicaSet 中移除 MySQL 实例。
3.2.7 remove_router_metadata
remove_router_metadata(routerDef) 移除 MySQL Router 元数据信息,可以使用该方法清除已不存在的实例。
3.2.8 set_instance_option
set_instance_option(instance, option, value) 更改 ReplicaSet 成员的选项值。例如从 MySQL Router 中隐藏某台实例,不参与读写分离:
rs.set_instance_option("instance", "tag:_hidden", true)
3.2.9 set_option
set_option(option, value) 更改 ReplicaSet 整体的选项值。
3.2.10 set_primary_instance
set_primary_instance(instance, {options}) 执行主动切换,将一个选定的 MySQL 实例提升为主服务器。
3.2.11 setup_admin_account
创建或升级 innodb ReplicaSet 的管理账户。
3.2.12 setup_router_account
创建或升级 MySQL Router 的账号。
3.2.13 status
查询 ReplicaSet 状态,使用 rs.status(extended=0) 指定 extended 等级 0~2,获得更详细的信息。
4. 故障切换
4.1 查询当前状态
rs.status()
4.2 关闭主库实例
因为实验环境 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)
4.3 使用 AdminAPI 切换
打开 MySQL Sehll 切换为 python 模式,登录到 55 会话:
\c rw_shell@172-16-104-55:3306
获取 ReplicaSet 对象:
rs = dba.get_replica_set()
查询 ReplicaSet 当前状态:
此时 MySQL Sehll 已经检测到主库不可用,并建议切换实例:
"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')
4.4 恢复 ReplicaSet
故障切换完成后,业务可以正常使用 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 高可用解决方案》