脚本实现MySQL 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 组,如果要使用读写分离功能,则需要应用适配。
# 脚本实现自动进行故障转移
点击查看代码
#!/bin/bash
# MySQL 用户名
mysql_user='dba_rsadmin'
# 候选主机列表,这些是可能成为主库的备选主机
candidates=(mysql-01 mysql-02 mysql-03)
# 检查间隔时间(秒)
interval=2
# 最大检查次数
max_checks=5
# 存储状态信息的文件名
status_file=${0//.sh/}.status
# 日志函数,用于输出错误信息
log_err() {
echo $(date "+%F %T") $* >&2;
}
# 获取复制集群状态信息的函数
replicaset_status() {
for node in ${candidates[@]}; do
# 使用 mysqlsh 工具连接到候选主机,并获取复制集群状态信息
mysqlsh ${mysql_user}@${node}:3366 -e 'print(dba.getReplicaSet().status())'
# 如果命令执行成功,则返回 0,表示成功获取状态信息
[ $? -eq 0 ] && return 0
done
# 如果无法获取状态信息,则返回 1
return 1
}
# 从状态文件中获取主库地址的函数
get_primary_address() {
jq -r '.replicaSet.topology[]|select(.instanceRole == "PRIMARY")|.address' ${status_file}
}
# 从状态文件中获取从库地址的函数
get_secondary_addresses() {
jq -r '.replicaSet.topology[]|select(.instanceRole == "SECONDARY")|.address' ${status_file}
}
# 对指定主机进行健康检查的函数
health_check() {
mysqlsh --sql ${mysql_user}@${1} -e "select 1" 2>&1 >/dev/null
}
# 执行主库切换的函数
do_failover() {
mysqlsh ${mysql_user}@${1} -e 'dba.getReplicaSet().forcePrimaryInstance()'
}
# 主函数
main() {
while :; do
checks=0
while [ ${checks} -lt ${max_checks} ]; do
# 获取复制集群状态,并将结果保存到状态文件中
replicaset_status > ${status_file} 2>/dev/null
# 检查是否成功获取状态信息
if [ $? -eq 0 ]; then
# 获取当前主库地址
prim=$(get_primary_address)
# 对当前主库进行健康检查
health_check ${prim}
# 如果主库不可用
if [ $? -ne 0 ]; then
checks=$((checks+1))
sleep ${interval}
else
# 主库可用,跳出循环
break
fi
else
log_err "无法获取复制集群信息。"
exit 1
fi
done
if [ ${checks} -eq ${max_checks} ]; then
log_err "连续 ${max_checks} 次检查主库不可用,执行主库切换。"
# 遍历从库地址列表
for sec in $(get_secondary_addresses); do
# 对从库进行健康检查
health_check ${sec}
if [ $? -eq 0 ]; then
# 如果从库可用,则执行主库切换操作
do_failover ${sec}
case $? in
0)
log_err "主库切换成功,当前主库是 ${sec}"
break
;;
*)
log_err "主库切换失败"
break
;;
esac
fi
done
fi
# 输出主库健康检查通过的信息
log_err "健康检查通过,当前主库是 ${prim}"
# 等待一段时间后再进行下一次检查
sleep ${interval}
done
}
# 调用主函数开始执行脚本
main
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
上次更新: 10/2/2024
- 02
- Flink 集群部署指南 原创09-20
- 03
- MongoDB 集群Config Server 复制集的工作原理09-14