思维导图
主从复制
基本介绍
主从复制搭建:
1、两台+ 同版本的mysql实例;server_id 各不相同
2、主库方面:二进制日志;复制用户
3、从库方面:通过备份恢复初始化数据(将主库之前的数据拿到从库中:采用最近的一次全备)
1、你怎么监控复制延时:
1、second behind master 只能查看出秒数
2、查看日志量 (也可以利用pt-heartbeat工具)
2、主从延时的原因有哪些
主库方面
(binlog是否实时写入 sync_binlog=1)(5.6版本以前dump线程串行工作;5.7开启dump gtid 并行工作 根据gtid写入binlog的落盘顺序) (减少大事务 和线上做DDL导致全局锁)
从库方面
(SQL线程 5.6 默认是串行的;5.7 基于逻辑时钟进行并发回放) (大量DDL 导致锁的争用问题)
特殊从库
延时从库:异步同步到从库中
过滤复制:白名单、黑名单 两者只选其一
gtid
半同步:mysql版本过渡的产物(dump 通过tcp ip方式发送给IO线程后就不管了(有ack的确认 但是只是放在IO的缓存中了 没有落地到relaylog 中,所以不能保证从库的数据一定会落盘),不管IO线程是否接受到了)
半同步作用于IO线程处,在主从双节点上安装插件 semi-sync 作用:只有当日志信息从IO缓存中落地到relaylog中才会给主库反馈一个确认的信息
GTID复制:
只要主库生成的gtid号码 会在传输到从库时,一同传输过去,可以根据gtid号码进行确认是否
gtid和传统主从复制的差异
不同点:
1、搭建时的命令:
master_auto_position=1 自动寻找复制起点
分为两种情况:
没有备份: 自动从主库的第一个gtid对应的position号码开始复制
有备份:
mysqldump -A --master-date=2 /tmp/full.sql
SET @GLOBAL.GTID purged=’ :1-10’;
从库会自动从第11个gtid开始复制
enforce-gtid-consistency=true 强制gtid一致性
log_bin=/data/binlog/mysql-bin 开启binlog日志
log-slave-updates=1 从库强制更新binlog日志
gtid-mode =on 开启gtid
功能:主从之间 自动校验gtid一致性:主库binlog 检验于 从库relaylog 和 binlog
MHA的高可用
1、数据损坏的类型
物理损坏:磁盘、主机、程序、实例、数据文件
逻辑损坏:drop 等
高可用是架构在主从之上的。一主两从
高可用技术解决物理损坏
高可用解决方案选型依据
高可用解决方案选型依据全年无故障率
无故障时间 故障时间 解决方案
99.9% 0.1% = 525.6 min KA+双主 :人为干预
99.99% 0.01% = 52.56 min MHA :半自动化
应用场景:比较适合非金融类互联网公司。 facebook MHA ,淘宝 TMHA --》polardb。 替代产品: ORCH go语言。
99.999% 0.001% = 5.256 min PXC 、 MGR 、MGC
应用场景: 金融类业务。
99.9999% 0.0001% = 0.5256 min 自动化、云化、平台化
MHA基础环境实施
准备3节点MySQL GTID 复制。
略。
MHA 软件结构
manager 组件
masterha_manger 启动MHA
masterha_check_ssh 检查MHA的SSH配置状况
masterha_check_repl 检查MySQL复制状况,配置信息
masterha_master_monitor 检测master是否宕机
masterha_check_status 检测当前MHA运行状态
masterha_master_switch 控制故障转移(自动或者手动)
masterha_conf_host 添加或删除配置的server信息
node 组件
save_binary_logs 保存和复制master的二进制日志
apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的
purge_relay_logs 清除中继日志(不会阻塞SQL线程)
MHA软件安装及配置
程序软连接
ln -s /data/app/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
ln -s /data/app/mysql/bin/mysql /usr/bin/mysql
各节点进行互信
db01:
rm -rf /root/.ssh
ssh-keygen
cd /root/.ssh
mv id_rsa.pub authorized_keys
scp -r /root/.ssh 10.0.0.52:/root
scp -r /root/.ssh 10.0.0.53:/root
各节点验证
db01:
ssh 10.0.0.51 date
ssh 10.0.0.52 date
ssh 10.0.0.53 date
db02:
ssh 10.0.0.51 date
ssh 10.0.0.52 date
ssh 10.0.0.53 date
db03:
ssh 10.0.0.51 date
ssh 10.0.0.52 date
ssh 10.0.0.53 date
安装软件
#所有节点安装Node软件依赖包
yum install perl-DBD-MySQL -y
rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm
#Manager软件安装(db03)
yum install -y perl-Config-Tiny epel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes
yum install -y mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
在db01主库中创建mha需要的用户
grant all privileges on *.* to mha@'10.0.0.%' identified by 'mha';
Manager配置文件准备(db03)
#创建配置文件目录
mkdir -p /etc/mha
#创建日志目录
mkdir -p /var/log/mha/app1
#编辑mha配置文件
cat > /etc/mha/app1.cnf <<EOF
[server default]
manager_log=/var/log/mha/app1/manager # MHA的工作日志设置
manager_workdir=/var/log/mha/app1 # MHA工作目录
master_binlog_dir=/data/binlog # 主库的binlog目录
user=mha # 监控用户
password=mha # 监控密码
ping_interval=2 # 心跳检测的间隔时间
repl_password=123 # 复制用户
repl_user=repl # 复制密码
ssh_user=root # ssh互信的用户
[server1] # 节点信息....
hostname=10.0.0.51
port=3306
[server2]
hostname=10.0.0.52
port=3306
candidate_master=1
[server3]
no_master=1
hostname=10.0.0.53
port=3306
EOF
状态检查(db03)
masterha_check_ssh --conf=/etc/mha/app1.cnf
masterha_check_repl --conf=/etc/mha/app1.cnf
开启MHA-manager
开启MHA(db03):
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
查看MHA状态
[root@db03 ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:4719) is running(0:PING_OK), master:10.0.0.51
MHA工作原理
站在产品经理的角度看高可用应该如何设计?
1、启动MHA 软件
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
同一个软件通过不同的配置文件来启动不同的集群
2、 监控
自动调用脚本 masterha_check_ssh 每隔ping_interval(2)秒 去执行一次这个脚本,如果连续四次还是没有 说明主库宕机
/usr/bin/masterha_master_monitor
,每隔ping_interval秒探测1次,连续4次还没有,说明主库宕机。
[root@slave2 bin]# mysql -umha -pmha -h 10.0.0.51 -e "select user();"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+
| user() |
+---------------+
| [email protected] |
+---------------+
[root@slave2 bin]#
3、监控到之后 再选择一个主库
日志量 latest
备选主 pref
哪些不被选主 bad
no_master=1
log_bin 二进制日志没开
check_slave_delay,如果从库落后主库100M的日志量(可以关闭)
alive 存活节点数组 52 53
lastest 最接近主库的从库 ****第二优先级
pref candidate_master=1 备选主 *****优先级最高
bad 设定no_master =1 则不参与选主 ***第三优先级
log_bin 日志没有开启 不参与选主
check_slave_delay 如果从库落后主库100M的日志量 则不会参与选主
选主条件:
①latest 日志量
②备选主 pref candidate_master=1
如果多个从库从这 两个选主条件都满足 那么就会按照配置文件的顺序
选主原理:首先他在alived中查找主机清单,然后排除bad,最后根据pref和latest的优先级选主
如果设置了no_master =1 即使已经没有可以切换的从库了 只剩了配置no_master =1 那么也不会切换给这个配置的从库
=============
数组:
alive : 存活
latest :最新
pref :备选
bad :不选
选主判断:
伪代码:
if 情况
=1. 如果pref和bad数组当中slave的个数为0,则选择latest数组当中的第一个slave为master。
db02没有candidate_master,又没有以下bad三种情况,db02恰好是latest。
=2. 循环对比latest数组和perf数组的slave,如果存在相同的slave,并且这个slave不在bad数组当中,该slave会被推选为新的master。
db02 pref , latest ,又不是bad,会被选主。
=3. 循环对比slaves数组pref数组当中的slave,如果有一个slave相同并且不在bad数组当中,该就会成为新的master。
db02 ,不是latest,不是bad,是pref。会被选择。
=4. 循环latest数组,如果又循环到的slave不在bad数组当中,这个slave就会成为master。
也就是说就算添加了candidate_master=1,该slave也不一定会成为主库。
db02 , latest ,不是bad
db03 , pref,不是latest ,不是bad
=5. 从活着的slave当中进行循环,如果循环到的slave不在bad数组当中,那么这个slave就会成为主库。
db02 ,slaves ,不是bad 。
else 如果进行了多次选择都找不到主库,那么主库选择失败,failover失败。
==============
4、数据补偿
情景1:原来的主库 ssh能连接
各个从节点调用save_binary_logs脚本 立即保存缺失部分的binary 到各自节点/var/tmp目录中
情景2:原主库ssh不能连接
从从1调用apply_diff_relay_logs 进行relay-log日志差异补偿给从2 但是如果原主 10 从1 8 从2 6
原主库 10的数据以及不能ssh登录 那么只能将从1的 8 中的 6 7 补偿给 从2 与原来的数据相比 仍然缺少 9 10 两个日志
额外数据补偿
binlog_server
主库日志的冗余机制
原主库ssh能连接
各个从节点调用: save_binary_logs 脚本,立即保存缺失部分的binlog到各自节点/var/tmp目录。
原主库ssh不能连接
从节点调用apply_diff_relay_logs ,进行relay-log日志差异补偿。
额外数据补偿(主库日志冗余机制)
binlog_server.
5、切换主从关系
解除所有从库主从身份。stop slave ; restart slalve
重构新的主从关系 change master to
6、vip应用透明
7、故障提醒
8、额外数据补偿
9、剔除故障节点
10、manager 程序自杀
dos2unix /usr/local/bin/* 利用命令将脚本中的一些中文字符识别出来
应用透明(VIP)
vip 介绍
#作用网卡:
eth0:1
ens33:1
#IP
vip : 10.0.0.55/24
一定是一个空闲地址。
一定要和对外提供服务的地址同一网段。
不能跨网段。
vip 故障转移脚本
上传脚本文件到/usr/local/bin
[root@db03 mha_script]# \cp -a * /usr/local/bin
修改权限
[root@db03 bin]# chmod +x /usr/local/bin/*
修改内容
[root@db03 bin]#vim /usr/local/bin/master_ip_failover
my $vip = '10.0.0.55/24';
my $key = '1';
my $if = 'ens33';
my $ssh_start_vip = "/sbin/ifconfig $if:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig $if:$key down";
my $ssh_Bcast_arp= "/sbin/arping -I $if -c 3 -A 10.0.0.55";
解释
my $vip = '10.0.0.55/24'; vip地址
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip"; 修改网卡名字
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down";
my $ssh_Bcast_arp= "/sbin/arping -I eth0 -c 3 -A 10.0.0.55";vip地址
修改Manager 配置文件
vim /etc/mha/app1.cnf
master_ip_failover_script=/usr/local/bin/master_ip_failover
重启MHA
[root@db03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
[root@db03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
手工在主库添加VIP
[root@db02 ~]# ifconfig ens33:1 10.0.0.55/24
故障提醒功能
准备脚本
[root@db03 bin]# vim send_report
my $smtp='smtp.qq.com'; # smtp服务器
my $mail_from='[email protected]'; # 发件箱
my $mail_user='22654481'; # 用户名 QQ号
my $mail_pass='gemghsvgkeyzcagh'; # 授权码
my $mail_to=['[email protected]']; # 收件箱
#my $mail_to=['[email protected]','[email protected]'];
我的配置文件
my $smtp='smtp.163.com';
my $mail_from='[email protected]';
my $mail_user='[email protected]';
my $mail_pass='liushiya111';
#my $mail_to=['[email protected]','[email protected]'];
my $mail_to='[email protected]';
修改配置文件
vim /etc/mha/app1.cnf
#添加一行:
report_script=/usr/local/bin/send_report
重启MHA
[root@db03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
[root@db03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
日志补偿的冗余方案–binlog_server
创建必要目录(db03)
mkdir -p /data/binlog_server/
chown -R mysql.mysql /data/*
cd /data/binlog_server/
[root@db03 ~]# mysql -e "show slave status \G"|grep "Master_Log"
mysqlbinlog -R --host=10.0.0.51 --user=mha --password=mha --raw --stop-never mysql-bin.000002 &
注意:
拉取日志的起点,需要按照目前从库的已经获取到的二进制日志点为起点
配置文件设置
vim /etc/mha/app1.cnf
[binlog1]
no_master=1
hostname=10.0.0.53
master_binlog_dir=/data/binlog_server/
重启MHA
[root@db03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
[root@db03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
MHA高可用,故障模拟及恢复演练
模拟故障
db01:
/etc/init.d/mysqld stop
db03: 看日志
[root@db03 binlog_server]# tail -f /var/log/mha/app1/manager
MHA的维护操作 - 在线切换功能
只切换角色
masterha_master_switch --conf=/etc/mha/app1.cnf --master_state=alive --new_master_host=10.0.0.52 --orig_master_is_new_slave --running_updates_limit=10000
注意:
master_ip_online_change_script is not defined. If you do not disable writes on the current master manually, applications keep writing on the current master. Is it ok to proceed? (yes/NO): yes
- 此种方法切换,要注意将原主库,FTWRL(Flush table with read lock),否则会造成主从不一致。
- 手工切换vip
- 重新拉去新主库的binlog
master_ip_online_change_script功能实现
功能: 在线切换时,自动锁原主库,VIP自动切换
准备切换脚本
vim /usr/local/bin/master_ip_online_change
my $vip = "10.0.0.55/24";
my $key = "1";
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key $vip down";
my $ssh_Bcast_arp= "/sbin/arping -I ens33 -c 3 -A 10.0.0.55";
修改MHA配置文件
vim /etc/mha/app1.cnf
master_ip_online_change_script=/usr/local/bin/master_ip_online_change
停 MHA
[root@db03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
检查repl
[root@db03 bin]# masterha_check_repl --conf=/etc/mha/app1.cnf
在线切换
masterha_master_switch --conf=/etc/mha/app1.cnf --master_state=alive --new_master_host=10.0.0.51 --orig_master_is_new_slave --running_updates_limit=10000
重构binlogserver
[root@db03 bin]# ps -ef |grep mysqlbinlog
root 28144 16272 0 17:50 pts/1 00:00:00 mysqlbinlog -R --host=10.0.0.52 --user=mha --password=x x --raw --stop-never mysql-bin.000005
root 28529 16272 0 18:03 pts/1 00:00:00 grep --color=auto mysqlbinlog
[root@db03 bin]# kill -9 28144
[root@db03 bin]# cd /data/binlog_server/
[root@db03 binlog_server]# ll
total 4
-rw-r----- 1 root root 194 Apr 1 17:50 mysql-bin.000005
[root@db03 binlog_server]# rm -rf *
[root@db03 binlog_server]# mysqlbinlog -R --host=10.0.0.51 --user=mha --password=mha --raw --stop-never mysql-bin.000009 &
[1] 28534
启动MHA
[root@db03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
[root@db03 binlog_server]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:28535) is running(0:PING_OK), master:10.0.0.51
- MHA故障通用修复方法
9.0 检查三节点是否启动
9.1 检查主从关系
1主2从:
[root@db03 binlog_server]# mysql -e "show slave status\G" |grep "Master_Host"
Master_Host: 10.0.0.52
[root@db01 data]# mysql -e "show slave status\G" |grep "Master_Host"
修复1主从:
db01:
change master to
master_host='10.0.0.52',
master_user='repl',
master_password='123' ,
MASTER_AUTO_POSITION=1;
start slave;
[root@db01 data]# mysql -e "show slave status\G" |grep "Master_Host"
Master_Host: 10.0.0.52
检查vip是否在主库
[root@db02 data]# ip a
检查binlog_server状态
[root@db03 binlog_server]# ps -ef |grep mysqlbinlog
root 77828 39593 0 17:53 pts/2 00:00:00 grep --color=auto mysqlbinlog
[root@db03 binlog_server]#
修复binlog_server:
[root@db03 binlog_server]# rm -rf /data/binlog_server/*
[root@db03 binlog_server]# cd /data/binlog_server/
[root@db03 ~]# mysql -e "show slave status \G"|grep "Master_Log"
[root@db03 ~]# mysqlbinlog -R --host=10.0.0.52 --user=mha --password=mha --raw --stop-never mysql-bin.000002 &
检查配置文件
三个节点是否存在:
[root@db03 binlog_server]# cat /etc/mha/app1.cnf
添加新节点到配置文件:
masterha_conf_host --command=add --conf=/etc/mha/app1.cnf --hostname=10.0.0.51 --block=server1 --params="port=3306"
++++++++
masterha_conf_host --command=delete --conf=/etc/mha/app1.cnf --block=server1
++++++++
检查ssh互信和repl
[root@db03 ~]# masterha_check_ssh --conf=/etc/mha/app1.cnf
[root@db03 ~]# masterha_check_repl --conf=/etc/mha/app1.cnf
启动MHA
[root@db03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
[root@db03 ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:78201) is running(0:PING_OK), master:10.0.0.52
[root@db03 ~]#