GTID主从复制 MHA高可用 binlogserver实时备份 Atlas中间件读写分离

GTID主从复制

什么是GTID

从MySQL 5.6.2 开始新增了一种基于 GTID 的复制方式,用以替代以前传统的复制方式,到MySQL5.6.10后逐渐完善。
通过 GTID 保证了每个在主库上提交的事务在集群中有一个唯一的ID。
这种方式强化了数据库的主备一致性,故障恢复以及容错能力,那么它如何做到的呢?

  • 要想在分布式集群环境中不丢失事务,就必须为每个事务定制一个全局唯一的ID号,并且该ID是趋势递增的,以此我们便可以方便地顺序读取、不丢事务,其实GTID就是一种很好的分布式ID实践方案,它满足分布ID的两个基本要求:
  1. 全局唯一性

  2. 趋势递增

GTID (Global Transaction ID全局事务ID)是如何做到全局唯一且趋势递增的呢,它是由UUID+TID两部分组成

UUID是数据库实例的标识符
[root@db01 mysql]# cat /var/lib/mysql/auto.cnf 
[auto]
server-uuid=af75cabb-ea33-11eb-afd9-000c29c6f63b

TID表示事务提交的数量,会随着事务的提交递增
#具体形式:af75cabb-ea33-11eb-afd9-000c29c6f63b:23

因此他与主库上提交的每个事务相关联,GTID不仅对其发起的服务器是唯一的,
而且在给定复制设置中的所有服务器都是唯一的,即所有的事务和所有的GTID都是1对1的映射。

当在主库上提交事务或者被从库应用时,可以定位和追踪每一个事务,对DBA来说意义就很大了,我们可以适当的解放出来,不用手工去可以找偏移量的值了,而是通过change master to master_host="xxx"master_auto_position=1的即可方便的搭建从库,在故障修复中也可以采用master_auto_position="x"的方式。5.7版本GTID做了增强,不手工开启也自动维护匿名的GTID信息。

部署基于GTID的主从复制

注意:

主库和从库都要开启bin log 

主库和从库的server-id必须不同 

要有主从复制用户

主库:192.168.15.51

vim /etc/my.cnf
[mysqld]
server-id=51
binlog_format=row
log-bin=mysql-bin
skip-name-resolve 		# 跳过域名解析(非必须)
gtid-mode=on 			# 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true 	# 强制GTID的一致性
log-slave-updates=1 	# slave更新是否记入日志(5.6必须的)
relay_log_purge = 0		 # 关闭relay_log自动清除功能,保障故障时的数据一致

从库1:192.168.15.7

  • 配置如下,只有server-id与主不同
vim /etc/my.cnf
[mysqld]
server-id=7
binlog_format=row
log-bin=mysql-bin
skip-name-resolve 		# 跳过域名解析(非必须)
gtid-mode=on 			# 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true 	# 强制GTID的一致性
log-slave-updates=1 	# slave更新是否记入日志(5.6必须的)
relay_log_purge = 0		 # 关闭relay_log自动清除功能,保障故障时的数据一致

从库2:192.168.15.8

  • 配置如下,只有server-id与主不同
vim /etc/my.cnf
[mysqld]
server-id=8
binlog_format=row
log-bin=mysql-bin
skip-name-resolve 		# 跳过域名解析(非必须)
gtid-mode=on 			# 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true 	# 强制GTID的一致性
log-slave-updates=1 	# slave更新是否记入日志(5.6必须的)
relay_log_purge = 0		 # 关闭relay_log自动清除功能,保障故障时的数据一致

主库创建复制账户

mysql> GRANT REPLICATION SLAVE ON *.* TO nana@'%' IDENTIFIED BY 'Na123***';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

两个从库开启复制

# 两个从库开启复制
mysql> change master to 
    -> master_host='192.168.15.51',
    -> master_user='nana',
    -> master_password='Na123***',
    -> MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

# 启动从库的复制
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

# 查看从库的复制状态信息
mysql> select * from mysql.user\G
mysql> show variables like '%gtid%';

如果想制作双主,步骤如下

# 找一台从库,假设为192.168.15.7,在该主机上创建账号
GRANT REPLICATION SLAVE ON *.* TO lala@'%' IDENTIFIED BY 'La123***';
flush privileges;

# 在主库上执行下述操作,指向从库192.168.15.7
mysql> change master to 
    -> master_host='192.168.15.7',
    -> master_user='lala',
    -> master_password='La123***',
    -> MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

# 开启主库的slave
start slave;

跳过事务

传统的复制例,如果主从复制遇到了某条sql错误,SQL停了,我们可以通过下述操作跳过错误
stop slave;
set global sql_slave_skip_counter=1;
start slave;
在传统的主从里,counter=1是跳过一条sql,而GTID是基于事务的主从复制,如果跳过就是跳过一整个事务,所以上述方法并不适用于GTID

#跳过事务的方法:
1. 停止slave进程
mysql> stop slave;
2. 设置事务号,执行show slave status\G查看Retrieved_Gtid_Set的值即事务号
在session里设置gtid_next,即跳过这个GTID
mysql> set gtid_next= 'af75cabb-ea33-11eb-afd9-000c29c6f63b:1'
3. 设置空事物
mysql> begin; commit;
4. 恢复事物号
mysql> set session gtid_next = automatic;
5. 启动slave进程
mysql> start slave;

重置主从同步

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

# 删除所有relay log,相当于重置 
mysql> reset slave;
Query OK, 0 rows affected (0.00 sec)

GTID优缺点总结

GTID相比传统复制的优点(新特性):

  1. 一个事务对应一个唯一ID,一个GTID在一个服务器上只会执行一次,强化了一致性

  2. GTID是用来代替传统复制的方法,GTID复制与普通复制模式的最大不同就是不需要指定二进制文件名和位置,直接自动查找

  3. GTID会开启多个SQL线程,每一个库,开启一个SQL线程

  4. 支持延时复制

GTID的限制:

  1. 不支持非事务引擎

  2. 不支持 create table t1(...) select * from t2; 语句复制(主库直接报错)
    原理:会生成两个sql,一个是DDL创建表SQL,一个是insert into 插入数据的sql。
    由于DDL会导致自动提交,所以这个sql至少需要两个GTID,但是GTID模式下,只能给这个sql生成一个GTID 。

  3. 不允许一个SQL同时更新一个事务引擎表和非事务引擎表

  4. 在一个复制组中,必须要求统一开启GTID或者是关闭GTID

  5. 开启GTID需要重启(5.7除外)

  6. 开启GTID后,就不再使用原来的传统复制方式

  7. 对于create temporary tabledrop temporary table语句不支持

  8. 不支持sql_slave_skip_counter

  9. mysqldump 备份起来很麻烦,需要额外加参数 --set-gtid=on

MHA高可用

MHA背景介绍

MHA 是Perl语言写的,开源的MYSQL故障切换方案;全称:Master High Availability,故障切换时间10-30s
有人说,我不要MHA行不行啊; 可以,没问题, 如果主数据库故障了?

首先,你需要手动一个一个地登录上所有的slave从库,然后一个个对比,看谁执行的bin log比较新,然后将其作为主库。
接下来,你还需要手动把所有的从库change master到新选出的主库。
一个字“费劲”!

这要是别的事,也还可以忍,但主库挂掉,会导致业务无法访问,一堆人站你旁边看着你,到时候一紧张再忘记开写了、slave挂不上去,这个影响时间就不是一星半点了;

为了解决上述问题,就有人写了个程序,来执行自动的主从故障切换,这就是MHA;

MHA简介

MHA(Master High Availability)是由日本人 yoshinorim(原就职于DeNA现就职于FaceBook)开发的一款成熟的、开源的 MySQL 的高可用程序。它为 MySQL主从复制架构提供了自动故障切换( automating master failover) 功能。

MHA 在监控到 master 节点故障时,会提升其中拥有最新数据的 slave 节点成为新的master 节点,
在此期间,MHA会通过于其它从节点获取额外信息来避免一致性方面的问题,
从而在最大程度上保证数据的一致性,以达到真正意义上的高可用,而且整个故障转移过程对应用程序完全透明。
最值得称赞的一点是:这一自动故障切换操作,MHA能在10~30秒之内完成。

此外,MHA 还提供了 master 节点的在线切换 功能,即按需切换 master/slave 节点,大概0.5-2秒内即可完成。

目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,例如一主二从。因为至少需要三台服务器,出于机器成本的考虑,淘宝也在该基础上进行了改造,目前淘宝的TMHA已经支持一主一从。

MHA工作原理

MHA由node和manager组成;

  • MHA Node(数据节点):

    相当于监控客户端,所有数据库机器都需要部署node
    
  • MHA Manager(管理节点)

    Manager相当于服务端,MHA Manager会定时探测集群中的master节点,
    当master出现故障时,它可以自动将最新数据的slave提升为新的master,
    然后将所有其他的slave重新指向新的master(如果原主库恢复,只能当从库)。
    
    通常单独部署在一台独立机器上管理多个 master/slave 集群(组),
    每个 master/slave 集群称作一个 application,用来管理统筹整个集群。
    
    Manager应该尽量避免部署在主库上,
    否则主机一挂则全挂,不仅主库完蛋了,负责自动迁移的Manager也完蛋了,也没人负责自动故障迁移了,导致架构不可用了。
    
    可以考虑部署在某一个slave上,此时这台主机挂掉了,只是挂了一个slave,以及Manager,
    如果此时你不是倒了霉,(主库也挂了),那还不至于架构不可用。
    但有一点需要注意的是:如果Manager部署在slave上,那么该slave就无法被升级为主库;
    

在这里插入图片描述

MHA自动故障切换的步骤

Manager会每隔3秒钟探测一次MASTER主库; (Hi, 主库你还活着吗?)

ping_interval 控制间隔时间;

ping_type 控制探测方式,SELECT(执行SELECT 1)和CONNECT(创建连接/断开连接)

如果Manager探测到MASTER主库故障、无法访问,Manager会执行下面操作:

1. 从其他node发起ssh连接,检查主库是否能够SSH上去;

2. 从其他node发起mysql连接,检查MASTER库是否能够登陆;

如果所有Node节点ssh连接、msyql主库连接均连接失败,则开始故障转移。

1. 找到数据最新的从库(通过对比relay-log,查看show slave status即可)
2. 将最新的从库上的新数据同步到其他从库
3. 提升一个从库为主库(一般情况提升数据最新的,二般情况提升我们指定的从库为主库)
4. 通过原来主库的bin log补全新的主库数据
5. 其他从库以新的主库为主做主从复制

MHA的优点总结

  1. 自动的故障检测与转移,通常在10-30秒以内;

  2. MHA还提供在线主库切换的功能,能够安全地切换当前运行的主库到一个新的主库中(通过将从库提升为主库),大概0.5-2秒内即可完成。

  3. 很好地解决了主库崩溃数据的一致性问题

  4. 不需要对当前的mysql环境做重大修改

  5. 不需要在现有的复制框架中添加额外的服务器,仅需要一个manager节点,而一个Manager能管理多套复制,所以能大大地节约服务器的数量;

  6. 性能优秀,可以工作在半同步和异步复制框架,支持gtid,当监控mysql状态时,仅需要每隔N秒向master发送ping包(默认3秒),所以对性能无影响。你可以理解为MHA的性能和简单的主从复制框架性能一样。

  7. 只要replication支持的存储引擎都支持MHA,不会局限于innodb

  8. 对于一般的keepalived高可用,当vip在一台机器上的时候,另一台机器是闲置的,而MHA中并无闲置主机。

部署MHA

环境准备在这里插入图片描述

先基于上一小节完成基于GTID的一主两从复制,在做主从之前,要保证主从数据的一致性。

  1. 所有数据库服务器都需要开启bin log日志

  2. 所有数据库都需要有主从复制用户,但我们之前在主库上执行过下述命令,从库已经同步过去了,所以不必重复创建,重复创建了也没用

     grant replication slave on *.* to nana@'%' identified by 'Na123***'; 
     flush privileges;
    
  3. 需要在主库上创建一个管理用户,用于日后MHA的管理

     # 在主库上执行即可,从库会同步过去 
     grant all on *.* to 'mhaadmin'@'%' identified by 'Na123***'; 
     flush privileges; 
    
  4. MHA 对 MYSQL 复制环境有特殊要求,例如各节点都要开启二进制日志及中继日志,各个"slave节点"必须显式启用read-only属性,并关闭relay_log_purge功能等。所以我们需要:

    1. 在从库上进行操作 	
    # 设置只读,不要添加配置文件,因为从库以后可能变成主库 
    mysql> set global read_only=1; 	
    
    2. 在所有库上都进行操作(这一步我们在5.3小节已经做过了,此处忽略即可) 
     # 关闭MySQL自动清除relaylog的功能 	
     mysql> set global relay_log_purge = 0; 	 	
     
    # 编辑配置文件 
    [root@mysql-db02 ~]# vim /etc/my.cnf 	
    [mysqld] 	
    # 禁用自动删除relay log永久生效 
    relay_log_purge = 0
    

配置免密登录(所有主机之间互做)

创建秘钥对
#正常创建 ssh-keygen 需要交互 按回车,用以下方法跳过交互
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
#发送公钥,包括自己
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.7
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.8
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.9
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.51

ssh root@192.168.15.7 hostname
ssh root@192.168.15.8 hostname
ssh root@192.168.15.9 hostname
ssh root@192.168.15.51 hostname

安装软件包(所有机器都执行安装)

- 安装依赖
# 安装yum源
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm

# 安装MHA依赖的perl包
yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager

- 注意先后顺序
1. 先在所有主机上安装node包
wget https://qiniu.wsfnk.com/mha4mysql-node-0.58-0.el7.centos.noarch.rpm --no-check-certificate
rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm

2. 然后再去manager主机安装manager包(manager机器,192.168.15.9)
wget https://qiniu.wsfnk.com/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm --no-check-certificate
rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm

配置MHA Manager

在Manager主机192.168.15.9上进行操作

- 在Manager主机192.168.15.9上进行操作
1. 在Manager主机上创建工作目录
mkdir -p /service/mha/
mkdir /service/mha/app1

2. 修改配置
vim /service/mha/app1.cnf		# 为什么叫app1呢,因为他可以管理很多套集群,后面的可以叫app
[server default]			
# 日志存放路径
manager_log=/service/mha/manager.log
# 定义工作目录位置
manager_workdir=/service/mha/app1
# binlog存放目录(如果三台数据库机器部署的路径不一样,可以将配置写到相应的server下面)
# master_binlog_dir=/usr/local/mysql/data

# 设置ssh的登录用户名
ssh_user=root
# 如果端口修改不是22的话,需要加参数,不建议改ssh端口
# 否则后续如负责VIP漂移的perl脚本也都得改,很麻烦
ssh_port=22

# 管理用户
user=mhaadmin
password=Na123***

# 复制用户
repl_user=nana
repl_password=Na123***

# 检测主库心跳的间隔时间
ping_interval=1

[server1]
# 指定自己的binlog日志存放目录
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.51
port=3306

[server2]
# 暂时注释掉,先不使用
# candidate_master=1
# check_repl_delay=0
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.7
port=3306

[server3]
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.8
port=3306

# 1、设置了以下两个参数,则该从库成为候选主库,优先级最高
# 不管怎样都切到优先级高的主机,一般在主机性能差异的时候用         
candidate_master=1
# 不管优先级高的备选库,数据延时多久都要往那切
check_repl_delay=0

# 2、上述两个参数详解如下:
# 设置参数candidate_master=1后,则判断该主机为为候选master,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的slave。

# 默认情况下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slave作为一个新的master,
# 因为对于这个slave的恢复需要花费很长时间,通过设置check_repl_delay=0, MHA触发切换在选择一个新的master的时候将会忽略复制延时,
# 这个参数对于设置了candidate_master=1的主机非常有用,因为这个候选主在切换的过程中一定是新的master

# 3、应该为什么节点设置这俩参数,从而把该节点的优先级调高
# (1) 多地多中心,设置本地节点为高权重
# (2) 在有半同步复制的环境中,设置半同步复制节点为高权重
# (3) 你觉着哪个机器适合做主节点,配置较高的 、性能较好的

3. 检测mha配置状态
#测试免密连接
1.使用mha命令检测ssh免密登录
masterha_check_ssh --conf=/service/mha/app1.cnf
#	ALL SSH ... successfilly 表示ok了
	
2.使用mha命令检测主从状态
masterha_check_repl --conf=/service/mha/app1.cnf
#	... Health is OK

#如果出现问题,可能是反向解析问题,配置文件加上
    skip-name-resolve
#还有可能是主从状态,mha用户密码的情况

4. 启动MHA
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &

命令参数:
# 该参数代表当发生主从切换后,宕机库的配置信息将会从配置文件中移除。
--remove_dead_master_conf       

# 日志存放位置
--manger_log                  
  
# 在缺省情况下,如果MHA检测到连续发生宕机,且两次宕机间隔不足8小时的话,则不会进行Failover,之所以这样限制是为了避免ping-pong效应。
# 该参数代表忽略上次MHA触发切换产生的文件,默认情况下,MHA发生切换后会在日志目录,也就是上面设置的manager_workdir目录中产生app1.failover.complete文件,
# 下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后收到删除该文件,
# 为了方便,这里设置为--ignore_last_failover。
--ignore_last_failover        

# MHA的安全机制:
1. 完成一次切换后,会生成一个锁文件在工作目录中
2. 下次切换之前,会检测锁文件是否存在
3. 如果锁文件存在,8个小时之内不允许第二次切换

测试自动切换与恢复

演练包括自动切换手动切换两部分。

当主库宕机时,会发生自动切换,我们先来模拟以下被动切换与恢复

模拟被动切换一定要停止数据,不要重启数据库

被动切换

#查看日志
tail -f /service/mha/manager.log

# 停掉主库master
systemctl stop mysqld
	提升数据量最多的为主库
	如果数据量一样,根据配置文件里面server的顺序切换

#如果把原主库修复,再把提升的主库停止,谁会是主库?
	数据量一样的情况下,根据server标签来切换的,标签越小优先级越高
	
#分析日志内容

#日志最后有一个sendreport机制,可以发送邮件给我们运维,不过一般不用,我们有zabbix可以帮我们监控

#最后执行的时候删除了主库的server信息,他会给他加上注释,然后删除注释的内容

修复MHA故障的主库

MHA环境修复步骤:
#1.启动宕机的主库
systemctl start mysqld

#2.将宕机的库作为从库指向新主库,此时为'192.168.15.8',
# 可以通过查看日志文件确认新主库地址: grep -i 'change master to' /service/mha/manager.log 

stop slave;
CHANGE MASTER TO MASTER_HOST='192.168.15.8', 
MASTER_PORT=3306, 
MASTER_AUTO_POSITION=1, 
MASTER_USER='nana', 
MASTER_PASSWORD='Na123***';
start slave;

3.如果启动manager时加入了参数--remove_dead_master_conf ,则此处需要将修复后的数据库信息配置到文件中
vim /service/mha/app1.cnf
[server1]
# 指定自己的binlog日志存放目录
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.51
port=3306

5.再次启动MHA(故障迁移一次masterha_manager就结束了,所以故障库修复后需要重新启动)
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &

6.检测MHA启动状态
masterha_check_status --conf=/service/mha/app1.cnf

主库切换优先级

- 依据数据量是否最新进行自动切换
1.做好主从

2.在主库上创建表
	create database if not exists test;
	create table test.t1(id int);
	
3.在主库运行下述脚本
for i in `seq 1 1000000`
do
    mysql -e "insert into test.t1 values($i);"
    sleep 1
done

4.将某一台从库的IO线程停止,该从库的数据必然落后了
	stop slave io_thread;
	
5.停止主库查看切换情况
	肯定不会选择那个停掉io先从的从库当新主库,但是该从库的io线程会
	启动起来,然后指向新主库,并且数据更新到了最新

依据优先级进行切换

1.配置优先级测试
candidate_master=1
check_repl_delay=0

为自动切换主库配置vip漂移脚本

VIP漂移的两种方式

1. 通过keepalived的方式,管理虚拟IP的漂移
2. 通过MHA自带脚本方式,管理虚拟IP的漂移(推荐)

为了防止脑裂发生,推荐生产环境采用脚本的方式来管理虚拟vip,而不是使用 keepalived来完成。

配置文件中指定脚本路径

- 在Manager主机192.168.15.9上进行操作
vim /service/mha/app1.cnf
[server default]
#指定自动化切换主库后,执行的vip迁移脚本路径
master_ip_failover_script=/service/mha/master_ip_failover

编写脚本

- 脚本主要修改以下几行
# 要求所有数据库网卡名必须一致
my $vip = '192.168.15.250/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down"; 
- 在Manager主机192.168.15.9上进行操作
vim /service/mha/master_ip_failover
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use Getopt::Long;

my (
$command,   $ssh_user,  $orig_master_host,
$orig_master_ip,$orig_master_port, $new_master_host, $new_master_ip,$new_master_port
);

#定义VIP变量
my $vip = '192.168.15.250/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down"; 

GetOptions(
'command=s'     => \$command,
'ssh_user=s'        => \$ssh_user,
'orig_master_host=s'    => \$orig_master_host,
'orig_master_ip=s'  => \$orig_master_ip,
'orig_master_port=i'    => \$orig_master_port,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s'   => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
);

exit &main();

sub main {
print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
if ( $command eq "stop" || $command eq "stopssh" ) {
my $exit_code = 1;
eval {
print "Disabling the VIP on old master: $orig_master_host \n";
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}

elsif ( $command eq "start" ) {
my $exit_code = 10;
eval {
print "Enabling the VIP - $vip on the new master - $new_master_host \n";
&start_vip();
$exit_code = 0;
};

if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}

elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";
exit 0;
}
else {
&usage();
exit 1;
}
}

sub start_vip() {
`ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}
sub stop_vip() {
return 0 unless ($ssh_user);
`ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
sub usage {
print
"Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}
添加执行权限,否则mha无法启动
chmod +x /service/mha/master_ip_failover

手动绑定vip到主库,假设此时主库为192.168.15.8那台机器

# ssh到主库所在服务器,然后执行
ifconfig eth0:1 192.168.15.250/24  # 注意与脚本中对应eth0:1


#补充:我们在做keepalived的时候它会帮我们添加VIP,实际上操作就是
	ifconfig eth0:1 192.168.15.250/24
	
	切换的时候就是把VIP所在机器
	ifconfig eth0:1 down
	
	然后切换到另一台机器去执行
	ifconfig eth0:1 192.168.15.250/24

测试vip漂移

找一台主机(可以考虑在管理节点),朝着vip提交写请求
# 强调:先执行一下ssh root@192.168.15.250,把yes输入一下,退出后再执行下述脚本
for i in `seq 1 1000000`
do
    ssh root@192.168.15.250 "mysql -e 'insert into test.t1 values($i);'"
    sleep 1
    echo "$i ok"
done

重启MHA

- 在Manager主机192.168.15.9上进行操作
# 停止mha
masterha_stop --conf=/service/mha/app1.cnf

# 启动mha
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &	

停止主库,测试ip漂移,并验证写操作是否中断

- 在Manager主机192.168.15.9上进行操作
# 查看日志
tail -f /service/mha/manager.log

- 切换到主库,停止主库运行
# 停止主库
systemctl stop mysqld

查看日志,通过ip a命令查看虚拟ip地址是否进行了切换,切换的主机是否是新的Manager主机。

为手动切换主库配置vip漂移脚本

配置文件中指定脚本路径

- 在Manager主机192.168.15.9上进行操作
vim /service/mha/app1.cnf 
[server default]
#指定手动切换主库后,执行的vip迁移脚本路径
master_ip_online_change_script="/service/mha/master_online_change"

编写手动切换主库后对应的vip迁移脚本

- 在Manager主机192.168.15.9上进行操作
vim /service/mha/master_online_change
#!/bin/bash
source /root/.bash_profile

vip=`echo '192.168.15.250/24'`  #设置VIP
key=`echo '1'`

command=`echo "$1" | awk -F = '{print $2}'`
orig_master_host=`echo "$2" | awk -F = '{print $2}'`
new_master_host=`echo "$7" | awk -F = '{print $2}'`
orig_master_ssh_user=`echo "${12}" | awk -F = '{print $2}'`
new_master_ssh_user=`echo "${13}" | awk -F = '{print $2}'`

#要求服务的网卡识别名一样,都为eth0(这里是)
stop_vip=`echo "ssh root@$orig_master_host /usr/sbin/ifconfig eth0:$key down"`
start_vip=`echo "ssh root@$new_master_host /usr/sbin/ifconfig eth0:$key $vip"`

if [ $command = 'stop' ]
  then
	echo -e "\n\n\n****************************\n"
	echo -e "Disabled thi VIP - $vip on old master: $orig_master_host \n"
	$stop_vip
	if [ $? -eq 0 ]
	  then
	echo "Disabled the VIP successfully"
	  else
	echo "Disabled the VIP failed"
	fi
	echo -e "***************************\n\n\n"
  fi

if [ $command = 'start' -o $command = 'status' ]
  then
	echo -e "\n\n\n*************************\n"
	echo -e "Enabling the VIP - $vip on new master: $new_master_host \n"
	$start_vip
	if [ $? -eq 0 ]
	  then
	echo "Enabled the VIP successfully"
	  else
	echo "Enabled the VIP failed"
	fi
	echo -e "***************************\n\n\n"
fi

添加执行权限,否则mha无法启动

- 在Manager主机192.168.15.9上进行操作
chmod +x /service/mha/master_online_change

手动绑定vip到主库

ifconfig eth0:1 192.168.15.250

手动切换主库验证vip漂移

- 在Manager主机192.168.15.9上进行操作
# 先停掉mha
masterha_stop --conf=/service/mha/app1.cnf

# 将主库切换到192.168.15.7
masterha_master_switch --conf=/service/mha/app1.cnf --master_state=alive --new_master_host=192.168.15.7 --orig_master_is_new_slave --running_updates_limit=10000 --interactive=0

binlogserver实时备份

如果主库断电或者断网,binlog如何保存?可以为MHA配置binlogserver,实时同步备份binglog

  • binlogserver是官方mysqlbinlog自带的功能,mysqlbinlog会伪装成一个slave,连接读取,请求指定的binlog file,主库获取接收到这个请求之后就创建一个binlog dump线程推送binlog给mysqlbinlog server。binlogserver在MHA高可用集群中,只同步bin log日志,充当主库的bing log日志备份。

准备一台新的mysql实例(与主库板块一致),GTID必须开启 ! ! !

# 修改配置文件,与主库板块一致
vim /etc/my.cnf
[mysqld]
server-id=9
binlog_format=row
log-bin=mysql-bin
skip-name-resolve 		# 跳过域名解析(非必须)
gtid-mode=on 			# 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true 	# 强制GTID的一致性
log-slave-updates=1 	# slave更新是否记入日志(5.6必须的)
relay_log_purge = 0		 # 关闭relay_log自动清除功能,保障故障时的数据一致
1.  前期准备
准备一台新的mysql实例(与主库板块一致),GTID必须开启。 
然后改mysql主机就用于实时拉取主库的binlog,并不与主库同步,只是用来拉取主库的binlog,防止主库突然断电。

2. 停止MHA
masterha_stop --conf=/service/mha/app1.cnf

3. 创建binlog存放目录并设置权限
mkdir -p /bak/binlog/
chown -R mysql.mysql /bak/binlog

4. 手动执行备份binlog
# 切换到备份目录下
cd /bak/binlog

# 查看所有从库show slave status\G
mysqlbinlog  --no-defaults -R --host=主库ip地址 --user=mhaadmin --password=Na123*** --raw --stop-never mysql-bin.000002 &
 
# 注意:写成mysql-bin.000002则会从该文件开始拉取一直到最新的
mysqlbinlog  --no-defaults -R --host=192.168.15.51 --user=mhaadmin --password=Na123***  --raw --stop-never mysql-bin.000002 &

5. 在app1.cnf开启binlogserver功能
vim /service/mha/app1.cnf 
[binlog1]
no_master=1
# binlogserver主机的ip地址
hostname=192.168.15.9
# 不能跟当前机器数据库的binlog存放目录一样
master_binlog_dir=/bak/binlog/

6. 加速ssh连接,关闭DNS解析,防止连接超时
vim /etc/ssh/sshd_config
UseDNS no

7. 再次启动mha
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &

8. 登录主库验证
mysql> flush logs; 		-- 看到binlogserver主机上/bak/binlog目录下新增日志

常用命令汇总

1. 重置slave
stop slave;
reset slave;

2. 查看
SHOW SLAVE STATUS;          # 查看从库复制状态
SHOW MASTER STATUS;         # 查看当前binlog位点
SHOW SLAVE HOSTS;           # 查看从库列表

3. 重做slave指向主库
stop slave;
CHANGE MASTER TO MASTER_HOST='192.168.15.8', 
MASTER_PORT=3306, 
MASTER_AUTO_POSITION=1, 
MASTER_USER='nana', 
MASTER_PASSWORD='Na123***';
start slave;

4. 停止mha
masterha_stop --conf=/service/mha/app1.cnf

5. 查看ssh与主从状态
masterha_check_ssh --conf=/service/mha/app1.cnf
masterha_check_repl --conf=/service/mha/app1.cnf

6. 启动mha
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &
	
7. 查看mha状态
masterha_check_status --conf=/service/mha/app1.cnf

8. 修改mha配置文件
cat >> /service/mha/app1.cnf << EOF
[server default]
manager_log=/service/mha/manager.log
manager_workdir=/service/mha/app1
master_ip_failover_script=/service/mha/master_ip_failover
master_ip_online_change_script="/service/mha/master_online_change"
password=666
ping_interval=1
repl_password=123
repl_user=nana
ssh_port=22
ssh_user=root
user=mhaadmin

[server1]
hostname=192.168.15.51
master_binlog_dir=/var/lib/mysql
port=3306

[server2]
hostname=192.168.15.7
master_binlog_dir=/var/lib/mysql
port=3306

[server3]
hostname=192.168.15.8
master_binlog_dir=/var/lib/mysql
port=3306

EOF

MySQL中间件Atlas

atlas简介

Mysql 的 proxy 中间件有比较多的工具,例如,mysql-proxy(官方提供), atlas , cobar, mycat,tddl, tinnydbrouter等等。
Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bug,添加了很多功能特性。目前该项目在360公司内部得到了广泛应用,很多MySQL业务已经接入了Atlas平台,每天承载的读写请求数达几十亿条。同时,有超过50家公司在生产环境中部署了Atlas,超过800人已加入了我们的开发者交流群,并且这些数字还在不断增加。而且安装方便。配置的注释写的蛮详细的,都是中文。

Atlas官方链接:
https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md

Atlas下载链接:
https://github.com/Qihoo360/Atlas/releases

Atlas主要功能(代理)

  1. 读写分离
  2. 从库负载均衡
  3. IP过滤
  4. 自动分表
  5. DBA可平滑上下线DB(不影响用户的体验,把你的数据库下线)
  6. 自动摘除宕机的DB

Atlas相对于官方MySQL-Proxy的优势

  1. 将主流程中所有Lua代码用C重写,Lua仅用于管理接口
  2. 重写网络模型、线程模型
  3. 实现了真正意义上的连接池
  4. 优化了锁机制,性能提高数十倍

使用场景

Atlas是一个位于前端应用与后端MySQL数据库之间的中间件,在后端DB看来,Atlas相当于连接它的客户端,在前端应用看来,Atlas相当于一个DB。Atlas作为服务端与应用程序通讯,它实现了MySQL的客户端和服务端协议,同时作为客户端与MySQL通讯。它对应用程序屏蔽了DB的细节,同时为了降低MySQL负担,它还维护了连接池。

Atlas使得应用程序员无需再关心读写分离、分表等与MySQL相关的细节,可以专注于编写业务逻辑,同时使得DBA的运维工作对前端应用透明,上下线DB前端应用无感知。

企业读写分离及分库分表其他方案了解

  1. Mysql-proxy(oracle)

  2. Mysql-router(oracle)

  3. Atlas (Qihoo 360)

  4. Atlas-sharding (Qihoo 360)

  5. Cobar(是阿里巴巴(B2B)部门开发)

  6. Mycat(基于阿里开源的Cobar产品而研发)

  7. TDDL Smart Client的方式(淘宝)

  8. Oceanus(58同城数据库中间件)

  9. OneProxy(原支付宝首席架构师楼方鑫开发 )

  10. vitess(谷歌开发的数据库中间件)

  11. Heisenberg(百度)

  12. TSharding(蘑菇街白辉)

  13. Xx-dbproxy(金山的Kingshard、当当网的sharding-jdbc )

  14. amoeba

部署Atlas中间件实现读写分离

在这里插入图片描述

安装Atlas

# 虽然包时el6的,但是centos7也能用
wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm

rpm -ivh Atlas-2.2.1.el6.x86_64.rpm

配置Atlas

[root@manager ~]# cd /usr/local/mysql-proxy/conf
[root@manager mysql-proxy]# vim test.cnf
[mysql-proxy]
# 用来登录atlas管理接口的账号和密码,部署登录msyql数据
admin-username = haha
admin-password = Na123***
proxy-backend-addresses = 192.168.15.250:3306 # 写节点(主库)
# 考虑到虚拟MHA高可用ip地址漂移,我们通常会把主库的ip地址也加入可读节点,这里为了实验效果,不加入可读节点
proxy-read-only-backend-addresses = 192.168.15.7:3306,192.168.15.8:3306 # 只读节点(从库)

# 用来登录msyql的账号和加密密码,都是存在与mysql库的账号免密,我们需要指定我们自己的,可以指定多个
# 注意一定要是加密密码,需要执行
# /usr/local/mysql-proxy/bin/encrypt Na123***,得到Na123***的加密密码
pwds = dada:3ZEe+9pSb6Ya8s/oWZlMvQ==, nana:3ZEe+9pSb6Ya8s/oWZlMvQ==    
daemon = true       # 后台运行
keepalive = true    # 监测节点心跳
event-threads = 4   # 并发数量,设置cpu核数一半
log-level = message   # 日志级别
log-path = /usr/local/mysql-proxy/log  # 日志目录
sql-log = On   # sql记录(可做审计)
proxy-address = 0.0.0.0:3306    # 业务连接端口
admin-address = 0.0.0.0:2345    # 管理连接端口
charset=utf8   # 字符集

根据Atlas中间件配置文件创建用户

- 在Atlas主机从创建用户
# 用来登录atlas管理接口的账号和密码
mysql> grant all on *.* to 'haha'@'%' identified by 'Na123***';
Query OK, 0 rows affected, 1 warning (0.01 sec)

- 在mysql主库创建用户
# 用来登录msyql的账号
mysql> grant all on *.* to 'dada'@'%' identified by 'Na123***';
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> grant all on *.* to 'nana'@'%' identified by 'Na123***';
Query OK, 0 rows affected, 1 warning (0.01 sec)

启动服务

# 关闭Atlas主机的MySQL,避免端口号冲突
systemctl stop mysqld

# 1. 启动,配置文件名为test.conf对应此处的test
/usr/local/mysql-proxy/bin/mysql-proxyd test start

# 2. 验证启动(没起来他也显示OK)
ps -ef|grep [m]ysql-proxy
netstat -lntup|grep [m]ysql-proxy

# 3. 查看日志定位问题
tail -f /usr/local/mysql-proxy/log/test.log

Atlas使用

# 进入管理接口,使用配置文件中指定的管理账号与密码
mysql -uhaha -pNa123*** -h127.0.0.1 -P2345

#查看帮助,依据帮助查找可执行的管理操作
mysql> SELECT * FROM help;

#查看后端的数据库
mysql> SELECT * FROM backends;

在任意一台机器上,登录atlas主机

#1、为了很好地观察读写分离的效果,可以先把从库的sql延迟设置大
stop slave;
CHANGE MASTER TO MASTER_DELAY = 60;
start slave;
	
#2、登录atlas来进行测试
# -u、-p为atlas配置文件中pwds指定的账号和密码
# -h后的地址为atlas主机的地址
# -P自定atlas监听的ip
mysql -udada -pNa123*** -h 192.168.15.9 -P 3306

mysql> create database db1;
此时去主库查看,发现有db1库,但是去所有从库查看发现都没有
过了一分钟后从库上都有db1了,然后我们通过atlas也可以查看到了
mysql> show databases;

Atlas管理功能简介

连接管理服务,使用配置文件中管理接口账户

mysql -uhaha -pNa123*** -h 192.168.15.9 -P 2345

持久化配置文件

mysql> save config;
Empty set (0.00 sec)

查看所有节点

mysql> SELECT * FROM backends;
+-------------+---------------------+-------+------+
| backend_ndx | address             | state | type |
+-------------+---------------------+-------+------+
|           1 | 192.168.15.250:3306 | up    | rw   |
|           2 | 192.168.15.7:3306   | up    | ro   |
|           3 | 192.168.15.8:3306   | up    | ro   |
+-------------+---------------------+-------+------+
3 rows in set (0.00 sec)

节点的上线和下线

- 节点下线
mysql> set offline 1;
+-------------+---------------------+---------+------+
| backend_ndx | address             | state   | type |
+-------------+---------------------+---------+------+
|           1 | 192.168.15.250:3306 | offline | rw   |
+-------------+---------------------+---------+------+
1 row in set (0.00 sec)

mysql> SELECT * FROM backends;
+-------------+---------------------+---------+------+
| backend_ndx | address             | state   | type |
+-------------+---------------------+---------+------+
|           1 | 192.168.15.250:3306 | offline | rw   |
|           2 | 192.168.15.7:3306   | up      | ro   |
|           3 | 192.168.15.8:3306   | up      | ro   |
+-------------+---------------------+---------+------+
3 rows in set (0.00 sec)
- 节点上线
mysql> set online 1;
+-------------+---------------------+---------+------+
| backend_ndx | address             | state   | type |
+-------------+---------------------+---------+------+
|           1 | 192.168.15.250:3306 | unknown | rw   |
+-------------+---------------------+---------+------+
1 row in set (0.00 sec)

mysql> SELECT * FROM backends;
+-------------+---------------------+-------+------+
| backend_ndx | address             | state | type |
+-------------+---------------------+-------+------+
|           1 | 192.168.15.250:3306 | up    | rw   |
|           2 | 192.168.15.7:3306   | up    | ro   |
|           3 | 192.168.15.8:3306   | up    | ro   |
+-------------+---------------------+-------+------+
3 rows in set (0.00 sec)

添加删除节点

- 删除节点
mysql> remove backend 3;
Empty set (0.00 sec)

mysql> SELECT * FROM backends;
+-------------+---------------------+-------+------+
| backend_ndx | address             | state | type |
+-------------+---------------------+-------+------+
|           1 | 192.168.15.250:3306 | up    | rw   |
|           2 | 192.168.15.7:3306   | up    | ro   |
+-------------+---------------------+-------+------+
2 rows in set (0.00 sec)
- 添加节点
mysql> add slave 192.168.15.8:3306;
Empty set (0.00 sec)

mysql> SELECT * FROM backends;
+-------------+---------------------+-------+------+
| backend_ndx | address             | state | type |
+-------------+---------------------+-------+------+
|           1 | 192.168.15.250:3306 | up    | rw   |
|           2 | 192.168.15.7:3306   | up    | ro   |
|           3 | 192.168.15.8:3306   | up    | ro   |
+-------------+---------------------+-------+------+
3 rows in set (0.00 sec)

用户管理

- 在主库增加数据库用户
mysql> grant all on *.* to user1@'%' identified by 'Na123***';
Query OK, 0 rows affected, 1 warning (0.00 sec)

-  查看当前用户
mysql> select * from pwds;
+----------+--------------------------+
| username | password                 |
+----------+--------------------------+
| dada     | 3ZEe+9pSb6Ya8s/oWZlMvQ== |
| nana     | 3ZEe+9pSb6Ya8s/oWZlMvQ== |
+----------+--------------------------+
2 rows in set (0.00 sec)

- 增加Atlas用户
mysql> add pwd user1:Na123***;
Empty set (0.00 sec)

mysql> select * from pwds;
+----------+--------------------------+
| username | password                 |
+----------+--------------------------+
| dada     | 3ZEe+9pSb6Ya8s/oWZlMvQ== |
| nana     | 3ZEe+9pSb6Ya8s/oWZlMvQ== |
| user1    | 3ZEe+9pSb6Ya8s/oWZlMvQ== |
+----------+--------------------------+
3 rows in set (0.00 sec)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值