导读
日常运维中, 难免遇到切换的场景, 但mysql的主从是逻辑复制, 没得真正的所谓MASTER,SLAVE. 主从复制无非就是几个特殊的进程而已. 感兴趣的可以看下之前写的mysql主从连接相关文章
https://www.modb.pro/db/625147
https://www.modb.pro/db/1788113344170905600
所以主从切换就稍微麻烦丢丢. (这里就不考虑回退方案了, 实际环境得考虑下回退方案哈)
切换逻辑
切换逻辑不复杂, 主要是检查得细致. 尽可能的提取把坑给排了. 大概分为3步: 切换前检查, 切换, 切换后检查. 就跟把大象装冰箱似的 =_=
切换前检查
IP是否填写正确, 网络是否通, 复制账号是否可用. 是否只读, 是否有连接. 数据是否一致(可选,主要是成本太高, 但可能埋下伏笔). 进程是否存在,配置文件是否存在(和内存参数是否一致就不检查了,太麻烦了…) 看起来有丢丢的多.命令参考如下:
# 声明变量, 可以是传参, 也可以脚本里面写死, 根据自己环境来. 我这里就不考虑mysql的端口了
MASTER_HOST='192.168.101.21'
SLAVE_HOST='192.168.101.22'
# IP判断
local_ip=`ip -4 addr | grep inet | awk '{print $2}' | awk -v ipaddr=${MASTER_HOST} -F '/' '{if ($1==ipaddr) print $1}'`
if [ "${local_ip}" == "" ];then
echo "当前IP不是主库IP, 请检查"
exit 1
fi
# 进程判断, 我这里就只管1个Mysqld进程的情况
mysqld_pid=`pidof mysqld`
if [ "${mysqld_pid}" == "" ];then
echo "mysql进程不存在"
exit 1
elif [ ${mysqld_pid} -eq ${mysqld_pid} ] 2>/dev/null;then
echo "mysql进程: ${mysqld_pid}"
else
echo "存在多个mysql进程: ${mysqld_pid}"
exit 1
fi
# 配置文件获取. 这里要求均在启动进程里面存在, 不能使用默认的配置文件. (根据自己实际情况修改)
my_cnf=`cat /proc/${mysqld_pid}/cmdline | sed 's/--/\n/g' | awk -F '=' '{if ($1=="defaults-file") print $2}`
if [ "${my_cnf}" == "" ];then
echo "mysqld未指定配置文件, 请检查"
exit 1
fi
# 从库查询出复制账号密码,并在主和从做验证
repl_password=`mysql -NB -e "select User_password from mysql.slave_master_info where Host='${MASTER_HOST}';"`
# 用户连接判断, 是否只读之类的我这里就不提供了.
# 从库还要检查主从状态和延迟
可能看起来有点多, 但检查越多, 切换的时候坑就越少. 主要检查内容如下:
切换
切换的时候就涉及到顺序问题了. 如果顺序不对, 可能就会有脏数据. 主要逻辑是主库先设置只读, 然后从库应用完日志并记录位点信息(非gtid情况下), 主库做change master, 从库reset slave然后取消只读. 取消或者设置只读的时候, 记得同步修改配置文件.
设置只读使用
set global super_read_only=on
, 该操作回自动设置read_only=on
取消只读使用set global read_only=off
, 该操作会自动设置super_read_only=off
之前有讲过的, 这样设置可以防止误操作
TIPS: 从库应用完日志, 不能光看延迟, 还要看IO线程和SQL线程的状态. 确保IO线程状态为: Waiting for master to send event
即已收到主库发来的所有日志. 确保SQL线程状态为: Slave has read all relay log; waiting for more updates
即已回放完所有数据.
切换后检查
主要检查 主从库的只读状态, 剩下的就是交给业务去验证了.
总结
主从切换逻辑主要是检查麻烦点, 涉及到参数的传递问题. 回切的话, 就把IP地址反过来填写就可以. 这次就不提供完整脚本了(如果有自动化平台,传递参数可能会比较方便; 非自动化环境的话, 估计就需要人工干预了, 当然也可以提前把相关信息查询出来.).
对于从库延迟要求在5秒以内, 主要是切换窗口太短, 延迟太大的话, 估计回放不完binlog.
对于业务连接要求是可以根据自己情况来的, 测试发现,存在业务连接的时候也能正常切换. 且数据一致.
数据一致性校验可以参考如下方法: 就是使用官方的checksum校验. (有pt的, 也可以使用pt-table-checksum)
# 获取校验值, 做过排序方便比较
mysql -h127.0.0.1 -P3314 -p123456 -NB -e 'select concat("CHECKSUM TABLE `",table_schema,"`.`",table_name,"`;") from information_schema.tables where table_schema not in ("sys","information_schema","mysql","performance");' | mysql -h127.0.0.1 -P3314 -p123456 -NB | sort > /tmp/.checksumalltable.txt
# 然后比较主和从的md5值即可
md5sum /tmp/.checksumalltable.txt
这里排查mysql之类的系统库是因为, 从库
mysql.slave_master_info
肯定有数据的, 因为这玩意导致数据不一致就太划不来了.
切换逻辑整体如下: