MySQL主从架构(读写分离-HA)

MySQL主从架构(HA)

MySQL Replication

在实际生产环境中,如果对数据库的读和写都在一个数据库服务器中操作。无论是在安全性、高可用性,还是高并发等各个方面都是完全不能满足实际需求,因此,一般来说都是通过主从复制(master-slave)的方式来同步数据,再通过读写分离来提升数据库的并发负载能力这样的方案来进行部署与实施。

什么是MySQL Replication(mysql主从复制)

1、主从复制是指当master(主)库的数据发生变化的时候,变化会实时的同步到一个或多个slave(从)库之中。

2、默认情况下属于异步复制,无需维持长连接。

3、通过配置,可以复制所有的库或者几个库,甚至库中的一些表。

4、replication是MySQL内建的,本身自带。

MySQL Replication的原理

简单的说就是master将数据库的更新操作写入二进制日志,slave同步这些二进制日志中的数据更新事件并写入中继日志文件中,然后读取relay日志,把二进制的日志解析成SQL语句,并执行这些SQL语句,使其与master中的数据一致。

注:

DML:SQL操作语句,update, insert,delete等数据更新操作语句。

Relay log:中继日志

MySQL Replication的作用

1、读写分离,提供查询服务

使用主从复制,让主库负责写,从库负责读。这样,即使主库进行数据更新操作出现了锁表的情景,通过读从库也可以保证业务的正常运作。

2、实时灾备,用于故障切换。

当系统中某个节点发生故障时,可以方便的故障切换,实现高可用(HA)。例如,做数据的热备,slave作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。

3、水平扩展数据库的负载能力

随着系统中业务访问量的增大,如果是单机部署数据库,就会导致I/O访问频率过高。有了主从复制,增加多个数据存储节点,将负载分布在多个从节点上,降低单机磁盘I/O访问的频率,提高单个机器的I/O性能。

MySQL Replication支持的复制类型

Statement:即基于语句的复制,会将对数据库操作的SQL语句写入到binlog中,效率比较高。

row:即基于行的复制,会将每一条数据的变化写入到binlog中。

mixed:即混合模型的复制,statement与row的混合,MySQL会根据执行的SQL语句选择日志保存方式。即交替使用行和语句、由MySQL服务器自行判断。

MySQL Replication如何工作

整体上来说,复制的工作过程有3个步骤:

(1) master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events);

(2) slave将master的binary log events拷贝到它的中继日志(relay log);

(3) slave根据中继日志中的事件,对salve数据库做相应的操作,使其与master中的数据一致。

MySQL Replication常见方案:

一主一从

一主多从

一主一从和一主多从是最常见的主从架构,实施起来简单并且有效,不仅可以实现HA,而且还能读写分离,进而提升集群的并发能力。

一主多从,master负责写操作,其他slave负责读,这种架构最大问题I/O压力集中,多台slave需要从master上同步数据,影响master的IO性能。

级联复制(M-S-S)

级联复制模式下,部分slave的数据同步不连接主节点,而是连接从节点。因为如果主节点有太多的从节点,就会损耗一部分性能用于replication,那么我们可以让3~5个从节点连接主节点,其它从节点作为二级或者三级与从节点连接,这样不仅可以缓解主节点的压力,并且对数据一致性没有负面影响。

例如,使用一台slave作为中继,分担master的压力,slave中继需要开启bin-log,并配置log-slave-updates

双主互备 (互为主从)

双主复制,也就是互做主从复制,每个master既是master,又是另外一台服务器的slave。这样任何一方所做的变更,都会通过复制应用到另外一方的数据库中。

很多人误以为这样可以做到MySQL负载均衡,实际没什么好处,每个服务器需要做同样的同步更新,破坏了事物的隔离性和数据的一致性。

多主一从(从5.7开始支持)

多主一从可以将多个MySQL数据库备份到一台存储性能比较好的服务器上。

MySQL主从复制原理

MySQL主从复制涉及到三个线程,一个运行在主节点(binlog dump thread),其余两个(I/O thread, SQL thread)运行在从节点,如下图所示:

  • 主节点 binary log dump 线程

当从节点连接主节点时,主节点会创建一个binlog dump 线程,用于发送bin-log的内容。在读取bin-log中的操作时,此线程会对主节点上的bin-log加锁,当读取完成,在发送给从节点之前,锁会被释放。

  • 从节点I/O线程

当从节点上执行`start slave`命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点binlog dump 线程发来的更新之后,保存在本地relay-log中。

  • 从节点SQL线程

SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。

注:对于每一个主从连接,都需要三个线程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个binary log dump 线程,而每个从节点都有自己的I/O线程,SQL线程。

主从复制的工作过程:

步骤一:主库上数据库的更新事件(update、insert、delete)被写到binlog

步骤二:从库启动之后,创建一个I/O线程,从库发起连接,连接到主库

步骤三:此时主库创建一个binlog dump thread线程,把binlog的内容发送到从库

步骤四:从库的I/O线程读取主库传过来的binlog内容并写入到relay log.

步骤五:从库还会创建一个SQL线程,从relay log里面读取内容,并执行读取到的更新事件,将更新内容写入到slave的数据库。

注:要实施复制,首先必须打开master 端的binary log(bin-log)功能,否则无法实现。因为整个复制过程实际上就是slave 从master 端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。

MySQL 主从复制模式

  • 异步模式(mysql async-mode)

MySQL主从复制默认是异步的模式,异步模式如下图所示,这种模式下,master事务的提交不需要经过slave的确认,slave是否接收到master的binlog,master并不关心。slave接收到master binlog后先写relay log,最后异步地去执行relay log中的sql应用到自身。这样就会有一个问题,由于master的提交不需要确保slave relay log是否被正确接受,当slave接受master binlog失败或者relay log应用失败,master无法感知。

假设master发生宕机并且binlog还没来得及被slave接收,而切换程序将slave提升为新的master,就会出现数据不一致的情况!另外,在高并发的情况下,传统的主从复制,从节点可能会与主产生较大的延迟(当然MySQL后续版本陆续做了优化,推出了并行复制,以此降低异步复制的延迟)

  • 半同步模式(MySQL semi-sync)

基于传统异步存在的缺陷,MySQL在5.5版本推出半同步复制。可以说半同步复制是传统异步复制的改进,在master事务的commit之前,必须确保一个slave收到relay log并且响应给master以后,才能进行事务的commit。但是slave对于relay log的应用仍然是异步进行的,原理如下图所示:

相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,所以,半同步复制最好在低延时的网络中使用。

半同步模式不是MySQL内置的,从MySQL5.5开始集成,需要master 和slave 安装插件开启半同步模式。

  • 全同步模式

指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。

部署MySQL主从同步(一主一从)

环境准备:

主机名

IP

系统版本/MYSQL版本

角色

Cong11

192.168.30.11

Centos7.5/5.7.26

master

Cong12

192.168.30.12

Centos7.5/5.7.26

slave

配置时间服务器

建立时间同步环境,在主节点上搭建时间同步服务器。

配置好本地yum源(略)

安装NTP

[root@cong11 ~]# yum -y install ntp

配置NTP

[root@cong11 ~]# vim /etc/ntp.conf //添加如下两行

server 127.127.1.0

fudge 127.127.1.0 stratum 8

参数说明:

server 127.127.1.0 //local clock,就和本地系统时间同步。127.127.1.0在这里是一个IP地址,不是网段。

127.127.1.0 为第8层。ntp和127.127.1.0同步完后,就变成了9层。 ntp是层次阶级的。同步上层服务器的stratum 大小不能超过或等于16。

重启NTPD服务

[root@cong11 ~]# systemctl enable ntpd

在服务器上关闭防火墙或指定端口进行开放(ntp协议——upd 123端口)

[root@cong11 ~]# systemctl stop firewalld

[root@cong11 ~]# systemctl disable firewalld

在从节点上进行时间同步

[root@cong12 ~]# yum -y install ntpdate

[root@cong12 ~]# /usr/sbin/ntpdate 192.168.30.11

配置cron计划任务

[root@cong12 ~]# crontab -l

*/10 * * * * /usr/sbin/ntpdate 192.168.30.11

配置主数据库服务器cong11

mysql> create database HA;

mysql> use HA;

mysql> create table t1(id int,name varchar(20));

mysql> insert into t1 values(1,'tom1');

创建主从复制的授权用户:

mysql>grant replication slave on *.* to slave@192.168.30.12 identified by "123456";

配置my.cnf:

[root@cong11 ~]# vi /etc/my.cnf 添加一下内容

[mysqld]

………….. //省略部分内容

log-bin=/data/mysql/log/mysql-bin-master #启用二进制日志

server-id=1 #数据库服务器ID标识

binlog-do-db=HA #可以被从服务器复制的库, 即二进制需要同步的数据库名

重启mysql

[root@cong11 ~]# systemctl restart mysqld

查看master状态信息:

mysql> show master status; //显示主服务器的当前binlog文件及事件位置

查看二进制日志:

mysql> show binlog events\G;

导出数据库

复制前要保证同步的数据库一致

[root@cong11 ~]# mysqldump -uroot -p123456 HA >HA.sql #可以导出数据库

将导出的数据库传给从服务器

[root@cong11 ~]# scp HA.sql root@192.168.30.12:~

配置从数据库服务器cong12
两台数据库服务器MySQL版本要一致

mysql> show variables like '%version%';

测试连接到主服务器是否成功

[root@cong12 ~]# mysql -uslave -p123456 -h 192.168.30.11

mysql> show databases; #只有复制的权限, 是看不到其它库的。正常

导入数据库,和主数据库服务器保持一致

[root@cong12 ~]# mysql -uroot -p123456 -e "create database HA;"

[root@cong12 ~]# mysql -uroot -p123456 HA<HA.sql

修改从服务器配置文件:

从服务器没必要开启bin-log日志

关闭MySQL

[root@cong12 ~]# systemctl stop mysqld

修改my.cnf配置文件
          1. [root@cong12 ~]# vi /etc/my.cnf

server-id = 2 #从服务器ID号,不要和主ID相同 ,如果设置多个从服务器,每个从服务器必须有一个唯一的server-id值,必须与主服务器的以及其它从服务器的不相同。这些ID值能唯一识别复制服务器群集中的每个服务器实例

relay-log=/data/mysql/log/relay-log-bin //中继日志文件的路径名称

relay-log-index=/data/mysql/log/slave-relay-bin.index //中继日志索引文件的路径名称

重启服务

[root@cong12 ~]# systemctl start mysqld

MySQL数据库里从配置

[root@cong12 ~]# mysql -uroot -p123456

mysql> stop slave; #停止slave

mysql>change master to master_host='192.168.30.11',master_user='slave',master_password='123456',master_log_file='mysql-bin-master.000001',master_log_pos=614;

截图如下:

mysql> start slave; #启动slave

mysql> show slave status\G //查看slave的状态

Slave_IO_Running :该线程连接到master机器,master机器上的binlog dump线程会将binlog的内容发送给该I/O线程。该I/O线程接收到binlog内容后,再将内容写入到本地的relay log。

Slave_SQL_Running:该线程读取I/O线程写入的relay log。并且根据relay log的内容对slave数据库做相应的操作。

看到2个yes说明设置成功

如何在master、slave上查看上述的线程?

在主服务器上查看binlog dump线程

[root@cong11 ~]# mysql -uroot -p123456

mysql> show processlist \G;

在从服务器上查看I/O线程和SQL线程

主服务器插入数据测试同步:

mysql> use HA;

mysql> insert into T1 values(1,'tom2');

mysql> select * from T1;

+------+------+

| id | name |

+------+------+

| 1 | Tom1 |

| 1 | tom2 |

+------+------+

2 rows in set (0.00 sec)

在从服务器查看数据是否同步

mysql> use HA;

mysql> select * from T1;

+------+------+

| id | name |

+------+------+

| 1 | Tom1 |

| 1 | tom2 |

+------+------+

2 rows in set (0.00 sec)

从上面的结果可以看到数据同步成功。

配置小结:

  • Master端

1、同步Master端的原始数据到所有Slave端

2、开启binlog日志,保持server-id唯一

3、配置Slave验证授权用户,权限replication slave

Slave端

1、开启relay日志,保持server-id唯一

2、执行change master语句,生成master.info文件

3、启动Slave复制(start slave)

Master端全备数据库同步到Slave端

在开始做主从复制之前(start slave前),需要把Master原有的数据都先同步到所有的Slave,否则在做同步复制之时,因为原有数据不一致导致同步失败。(注意,如果使用原来备份时间点,比如昨天凌晨的全备数据同步所有Slave数据时,还需要把当前时间点之前的所有binlog增量备份同步,使在主从复制时间点时,Master和所有Slave的数据保持一致)

排错:记一次MySQL主从数据库不同步的排查

如果遇到MySQL的主从数据库没有同步

先上Master库:

mysql>show processlist; 查看下进程是否Sleep太多。发现很正常。

mysql>show master status; 也正常。

再到Slave上查看

mysql> show slave status\G

Slave_IO_Running: Yes

Slave_SQL_Running: No

可见是Slave不同步

下面介绍两种解决方法:

方法一:忽略错误后,继续同步

该方法适用于主从库数据相差不大,或者要求数据可以不完全统一的情况,数据要求不严格的情况

解决:

mysql> stop slave;

#表示跳过一步错误,后面的数字可变

mysql> set global sql_slave_skip_counter =1;

mysql> start slave;

之后再用mysql> show slave status\G 查看:

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

ok,现在主从同步状态正常了。。。

方式二:重新做主从,完全同步

该方法适用于主从库数据相差较大,或者要求数据完全统一的情况

解决步骤如下:

1.先进入主库,进行锁表,防止数据写入

使用命令:

mysql> flush tables with read lock;

注意:该处是锁定为只读状态,语句不区分大小写

2.进行数据备份

#把数据备份到mysql.bak.sql文件

[root@cong1 ~]#mysqldump -uroot -p dbname> mysql.bak.sql

这里注意一点:数据库备份一定要定期进行,可以用shell脚本或者python脚本,都比较方便,确保数据万无一失

查看master 状态

mysql> show master status; //记下当前binlog文件和position

4.把mysql备份文件传到从库机器,进行数据恢复

#使用scp命令

[root@cong11 ~]# scp mysql.bak.sql root@192.168.30.12:/tmp/

5.停止从库的状态

mysql> stop slave;

6.然后到从库执行mysql命令,导入数据备份

mysql> source /tmp/mysql.bak.sql

7.设置从库同步,注意该处的同步点,就是主库show master status信息里的| File| Position两项

change master to master_host='192.168.30.11',master_user='slave', master_port=3306,master_password='123456',master_log_file='binlogfilename', master_log_pos=position;

8.重新开启从同步

mysql> start slave;

9.查看同步状态

mysql> show slave status\G 查看:

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

好了,同步完成啦。

主库解除锁表操作

mysql>unlock tables;

I/O线程出错
          1. 1、网络连通问题
          2. 2、防火前没有放开端口
          3. 3、对应的主机 IP地址写错了
SQL线程出错
          1. 主从服务器数据库结构不统一

部署MySQL主主双向主从复制 M-M

实验环境
          1. 通过MySQL主主复制:进行MySQL 双向同步数据库HA的配置

主机名

IP

系统版本/MySQL版本

角色

Cong11

192.168.30.11

Centos7.5/5.7.26

Master/slave

Cong12

192.168.30.12

Centos7.5/5.7.26

Slave/master

在上面主从的基础上进行配置

配置cong12为主服务器

它有两种身份:

身份1: cong11的从。 身份2: cong11的主

配置my.cnf
          1. [root@cong12 ~]# vi /etc/my.cnf

………. //省略部分内容

server-id = 2

log-bin=/data/mysql/log/mysql-bin-master

binlog-do-db=HA

创建主从复制的授权用户:

mysql> grant replication slave on *.* to 'slave'@'192.168.30.%' identified by '123456';

mysql> flush privileges; #记得刷新授权表

重启MySQL

[root@cong12 ~]# systemctl restart mysqld

mysql> show master status;

注:关闭防火墙或创建允许数据库连接规则

[root@cong12 ~]# systemctl stop firewalld

[root@cong12 ~]# systemctl disable firewalld

在cong11上配置cong11为cong12的从服务器
测试从帐号登陆

[root@cong11 ~]# mysql -uslave -p123456 -h 192.168.30.12

修改my.cnf

[root@cong11 ~]# vi /etc/my.cnf

………. //省略部分内容

relay-log=/data/mysql/log/relay-log-bin

relay-log-index=/data/mysql/log/slave-relay-bin.index

重启服务器

[root@cong11 ~]# systemctl restart mysqld

MySQL数据库里从配置

mysql> stop slave;

mysql>change master to master_host='192.168.30.12',master_user='slave',master_password='123456',master_log_file='mysql-bin-master.000001',master_log_pos=154;

mysql> start slave;

mysql> show slave status\G

插入数据测试:
在cong11上插入数据,cong12上查看

mysql> use HA;

mysql> insert into t1 values(4,'li4');

[root@cong12 ~]# mysql -uroot -p123456

mysql> use HA;

mysql> select * from t1; #在cong12查看数据OK

在cong12上插入数据,cong11上查看

mysql> insert into t1 values(5,'li5');

mysql> select * from t1; #在cong11上查看数据OK

部署M-S-S联级复制

实验环境:

恢复实验快照

主机

IP

系统版本

角色

cong11

192.168.30.11

Centos7.5/5.7.26

Master/NTP

cong12

192.168.30.12

Centos7.5/5.7.26

Slave中继

cong13

192.168.30.13

Centos7.5/5.7.26

Slave

部署Master cong11

注:确保三台服务器时间一致,关闭防火墙。

在主服务上授权用户:

[root@cong11 ~]# mysql -uroot -p123456

mysql> grant replication slave on *.* to 'repl'@'192.168.30.%' identified by '123456';

mysql> flush privileges;

创建数据库

mysql> create database HA;

mysql> use HA;

mysql> create table t1(id int,name varchar(20));

mysql> insert into t1 values(1,'tom1');

修改配置文件

[root@cong11 ~]# vi /etc/my.cnf

[mysqld]

………省略部分内容

server-id=1

binlog-do-db=HA

log-bin=/data/mysql/log/mysql-bin-master

sync-binlog=1

binlog-format=row

参数说明:

sync-binlog:此参数表示每一次写缓冲都会同步到磁盘;sync_binlog=1表示同步写缓冲和磁盘二进制日志文件,不使用文件系统缓存,在使用InnoDB事务引擎时,在复制环境中,为了保证最大的可用性,都设置为“1”,但会对影响IO的性能。

重启服务

[root@cong11 ~]# systemctl restart mysqld

查看master状态信息

mysql> show master status; //显示主服务器的当前binlog文件及事件位置

导出主服务器HA库完整备份, 拷贝到 中继服务器 和slave服务器

[root@cong11 ~]# mysqldump -uroot -p123456 -B HA>ha.sql

[root@cong11 ~]# scp ha.sql root@192.168.30.12:~

[root@cong11 ~]# scp ha.sql root@192.168.30.13:~

部署Slave中继 cong12
导入数据库ha.sql

[root@cong12 ~]#mysql -uroot -p123456 -e 'drop database HA;show databases';

[root@cong12 ~]# mysql -uroot -p123456 <ha.sql

配置my.cnf

修改主配置文件也要开启bin-log二进制日志:

[root@cong12 ~]# vi /etc/my.cnf

………… //省略部分内容

server-id=2

log-slave-updates=1 //此参数控制slave数据库是否把从master接受到的binlog以及在本slave执行的内容记录到slave的二进制日志中,在级联复制环境中,这个参数是必须要有的

log-bin=/data/mysql/log/mysql-bin-slave1

relay-log=/data/mysql/log/relay-log-bin

relay-log-index=/data/mysql/log/slave-relay-bin.index

#把从relay-log当中读取出来的二进制日志和在本机上执行的操作都记录到自己的二进制日志里面,这样才能使第三台slave通过中继slave读取到相应的数据变化

重启MySQL

[root@cong12 ~]# systemctl restart mysqld

配置从服务器

将cong12配置为cong11的从服务器

[root@cong12 ~]# mysql -uroot -p123456

mysql> stop slave;

mysql>change master to master_host='192.168.30.11',master_user='repl',master_password='123456',master_log_file='mysql-bin-master.000001',master_log_pos=154;

mysql> start slave;

在Slave中继 cong12上查看中继服务的状态

mysql> show slave status \G

在Slave中继服务器cong12中再授权一个用户给slave(cong13):

mysql> grant replication slave on *.* to 'repl'@'192.168.30.%' identified by '123456';

mysql> flush privileges;

mysql> show master status; //显示slave中继服务器的当前binlog文件及事件位置

部署SLAVE cong13
导入数据库ha.sql

[root@cong13 ~]# mysql -uroot -p123456 <ha.sql

配置my.cnf

[root@cong13 ~]# vi /etc/my.cnf

[mysqld]

………省略部分内容

server-id = 3

relay-log=/data/mysql/log/relay-log-bin

relay-log-index=/data/mysql/log/slave-relay-bin.index

重启MySQL

[root@cong13 ~]# systemctl restart mysqld

指定cong12中继服务器作为cong13的主:

[root@cong13 ~]# mysql -uroot -p123456

mysql> stop slave;

mysql>change master to master_host='192.168.30.12',master_user='repl',master_password='123456',master_log_file='mysql-bin-slave1.000001',master_log_pos=448;

mysql> start slave;

查看从服务的状态

mysql> show slave status \G

在Master上插入数据测试:
master插入数据

mysql> insert into t1 values(66,'tom666');

mysql> insert into t1 values(88,'tom888');

然后分别在slave中继,与slave上查看

Cong12中继查看:

mysql> select * from HA.t1;

Cong13 slave查看:

mysql> select * from HA.t1;

排错:

模拟故障1:
问题场景

由于历史遗留问题,MySQL主从库的表结构不一致,主库的某个表tableA比从库表tableA少了一个字段

当尝试在主库上更改表结构时,这行alter语句会随着binlog同步到从库,如果从库执行这行语句时出错,主从同步线程就会自动停止,那样只能人为手动处理错误,然后再启动slave上的主从同步线程。场景大概是下面这个样子:

先在cong13从库添加这个字段:

mysql> alter table t1 add age int default 0 after name;

再在cong11主库添加这个字段:

mysql> alter table t1 add age int default 0 after name;

修改主库上的表结构,添加一个字段

从库会同步主库的,但是从库已经存在了这个字段

在cong13从库上查看slave状态

mysql> show slave status\G

解决方法1:
          1. 跳过错误的事物
          2. Cong13从库上执行:
          3. mysql> stop slave;
          4. mysql> set global sql_slave_skip_counter=1; #跳过slave上的1个错误
          5. mysql> start slave;
          6. mysql> show slave status\G #恢复正常
解决方法2:

slave比较少的时候还可以,但是当从库有几十台时,逐台去处理既费时又容易出错,怎样在主库这一侧一劳永逸地避免呢?

那很简单,我们不要让主库将alter语句记录到binlog中就行

我们直接在主库中关闭binlog记录

mysql> set sql_log_bin=off;

然后我们再执行alter语句

mysql> alter table t1 add age int default 0 after name;

再开启bin-log

mysql> set sql_log_bin=on;

错误2:

主从的binlog日志文件对不上

查看从的状态

mysql> show slave status\G

到它的主上查看状态

mysql> show master status;

Slave上不对应

Slave上操作:

mysql> stop slave;

mysql> change master to master_host='192.168.30.12',master_user='repl',master_password='123456',master_log_file='mysql-bin-slave1.000002',master_log_pos=415;

mysql> start slave;

查看slave的binlog

mysql> show slave status\G

附加知识点:

MySQL主从复制存在的问题:

  • 主库宕机后,数据可能丢失
  • 从库只有一个SQL Thread,主库写压力大,复制很可能延时

解决方法:

  • 半同步复制 --> 解决数据丢失的问题
  • 并行复制 --> 解决从库复制延迟的问题

MySQL并行复制:

设置:

set global slave_parallel_workers=10; //设置SQL线程数为10

MySQL读写分离-mycat

MySQL读写分离的概述

MySQL作为目前世界上使用最广泛的免费数据库,相信所有从事系统运维的工程师都一定接触过。但在实际的生产环境中,由单台MySQL作为独立的数据库是完全不能满足实际需求的,无论是在安全性,高可用性以及高并发等各个方面。

因此,一般来说都是通过主从复制(Master-Slave)的方式来同步数据,再通过读写分离(MySQL-Proxy/Amoeba)来提升数据库的并发负载能力 这样的方案来进行部署与实施的

读写分离工作原理:

基本的原理是让主数据库处理事务性增、改、删操作(insert、update、delete),而从数据库处理select查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

说明: http://heylinux.com/wp-content/uploads/2011/06/mysql-master-salve-proxy.jpg

为什么要读写分离:

面对越来越大的访问压力,单台的服务器的性能成为瓶颈,需要分担负载

1、主从只负责各自的写和读,极大程度的缓解X锁和S锁争用

2、从库可配置MyISAM引擎,提升查询性能以及节约系统开销

3、增加冗余,提高可用性

实现读写分离的方式:

一般有两种方式实现
应用程序层实现,网站的程序实现

应用程序层实现指的是在应用程序内部及连接器中实现读写分离

优点:

A:应用程序内部实现读写分离,安装既可以使用

B:减少一定部署难度

C:性能很好

缺点:

A:架构一旦调整,代码要跟着变

B:难以实现高级应用,如自动分库,分表

C:无法适用大型应用场景

中间件层实现

中间件层实现是指在外部中间件程序实现读写分离

常见的中间件程序

Cobar:

阿里巴巴B2B开发的关系型分布式系统,管理将近3000个MySQL实例。 在阿里经受住了考验,后面由于作者的走开的原因cobar没有人维护 了,阿里也开发了tddl替代cobar。

MyCAT:

社区爱好者在阿里cobar基础上进行二次开发,解决cobar当时存在的一些问题,并且加入了许多新的功能在其中。目前MyCAT社区活跃度很高,目前已经有一些公司在使用MyCAT。总体来说支持度比较高,也会一直维护下去,

OneProxy:

数据库界大牛,前支付宝数据库团队领导楼总开发,基于mysql官方的proxy思想利用c进行开发的,OneProxy是一款商业收费的中间件, 楼总舍去了一些功能点,专注在性能和稳定性上。有朋友测试过说在高并发下很稳定。

Vitess:

这个中间件是Youtube生产在使用的,但是架构很复杂。与以往中间件不同,使用Vitess应用改动比较大,要使用他提供语言的API接口,我们可以借鉴他其中的一些设计思想。

Kingshard:

Kingshard是前360Atlas中间件开发团队的陈菲利用业务时间用go语言开发的,目前参与开发的人员有3个左右,目前来看还不是成熟可以使用的产品,需要在不断完善。

Atlas:

360团队基于mysql proxy 把lua用C改写。原有版本是支持分表, 目前已经放出了分库分表版本。在网上看到一些朋友经常说在高并发下会经常挂掉,如果大家要使用需要提前做好测试。

MaxScale与MySQL Route:

这两个中间件都算是官方的吧,MaxScale是mariadb (MySQL原作者维护的一个版本)研发的,目前版本不支持分库分表。MySQL Route是现在MySQL官方Oracle公司发布出来的一个中间件。

优点:

A:架构设计更灵活

B:可以在程序上实现一些高级控制,如:透明化水平拆分,failover,监控

C:可以依靠些技术手段提高mysql性能,

D:对业务代码的影响小,同时也安全

缺点:

需要一定的开发运维团队的支持

什么是mycat

• 一个彻底开源的,面向企业应用开发的大数据库集群

• 支持事务、ACID、可以替代MySQL的加强版数据库

• 一个可以视为MySQL集群的企业级数据库,用来替代昂贵的Oracle集群

• 一个融合内存缓存技术、NoSQL技术、HDFS大数据的新型SQL Server

• 结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品

http://img.blog.csdn.net/20160516110849013

服务安装与配置

通过mycat来实现读写分离:使用mycat提供的读写分离功能,mycat连接多个数据库,数据源只需要连接mycat,对于开发人员而言他还是连接了一个数据库(实际是mysql的mycat中间件),而且也不需要根据不同业务来选择不同的库,这样就不会有多余的代码产生。

实验环境

服务器信息如下(为方便做实验,关闭各个linux的iptables/firewalld防火墙和selinux)。

主机名

IP

系统版本/MySQL版本

角色

mycat-node

192.168.30.10

Centos7.5/1.6.6.1

Mycat/NTP

Cong11

192.168.30.11

Centos7.5/5.7.26

Master

Cong12

192.168.30.12

Centos7.5/5.7.26

slave

Cong13

192.168.30.13

Centos7.5/5.7.26

slave

1、四台机器分别修改主机名,并做hosts绑定

# vi /etc/hosts

192.168.30.10 mycat-node

192.168.30.11 cong11

192.168.30.12 cong12

192.168.30.13 cong13

2、建立时间同步环境,在mycat-node上配置NTP服务,为其他三台mysql服务器提供时间校对服务。

配置好本地yum源(略)

安装NTP

[root@mycat-node ~]# yum -y install ntp

配置NTP

[root@mycat-node ~]# vim /etc/ntp.conf //添加如下两行

server 127.127.1.0

fudge 127.127.1.0 stratum 8

启动NTPD服务:

[root@mycat-node ~]# systemctl enable ntpd

[root@mycat-node ~]# systemctl start ntpd

其他服务器连接NTP校对同步时间

# yum -y install ntpdate

# /usr/sbin/ntpdate 192.168.30.10

3、配置主从复制(一主两从:cong11作为master,cong12、cong13为slave)

1)主服务器cong11的配置:

mysql> create database HA;

mysql> use HA;

mysql> create table T1(id int,name varchar(20));

mysql> insert into T1 values(1,'Tom1');

创建主从复制的授权用户,允许slave主机连接master:

mysql> grant replication slave on *.* to 'slave'@'192.168.30.%' identified by "123456";

mysql> flush privileges;

配置my.cnf:

[root@cong11 ~]# vim /etc/my.cnf 添加一下内容

[mysqld]

………… //省略部分内容

server-id=1

log-bin=/data/mysql/log/mysql-bin-master

binlog-do-db=HA

sync-binlog=1

binlog-format=mixed

重启mysql:

[root@cong11 ~]# systemctl restart mysqld

将数据库锁住,仅仅允许读,以保证数据一致性:

mysql> flush tables with read lock;

mysql> flush privileges;

查看master状态信息:

mysql> show master status; //显示主服务器的当前binlog文件及事件位置

导出数据库:

复制前要保证同步的数据库一致

[root@cong11 ~]# mysqldump -uroot -p123456 HA >HA.sql #可以导出数据库

将导出的数据库传给从服务器

[root@cong11 ~]# scp HA.sql root@192.168.30.12:~

[root@cong11 ~]# scp HA.sql root@192.168.30.13:~

2)接着是slave从节点操作(cong12,cong13)

导入数据库,和主数据库服务器保持一致:

[root@cong12 ~]# mysql -uroot -p123456 -e 'create database HA;'

[root@cong12 ~]# mysql -uroot -p123456 HA <HA.sql

[root@cong13 ~]# mysql -uroot -p123456 -e 'create database HA;'

[root@cong13 ~]# mysql -uroot -p123456 HA < HA.sql

从节点cong12主机:/etc/my.cnf文件设置:

[mysqld]

………… //省略部分内容

server-id=2

relay-log=/data/mysql/log/relay-log-bin

relay-log-index=/data/mysql/log/slave-relay-bin.index

replicate-do-db=HA //只复制指定表

#replicate-ignore-db=mysql

重启mysql服务:

[root@cong12 ~]# systemctl restart mysqld

进行主从配置:

mysql>change master to master_host='192.168.30.11',master_user='slave',master_password='123456',master_log_file='mysql-bin-master.000001',master_log_pos=154;

mysql> start slave;

mysql> show slave status\G;

从节点cong13主机:/etc/my.cnf文件设置:

[mysqld]

………… //省略部分内容

server-id=3

relay-log=/data/mysql/log/relay-log-bin

relay-log-index=/data/mysql/log/slave-relay-bin.index

replicate-do-db=HA //只复制指定表

#replicate-ignore-db=mysql

其他配置参考cong12的设置(略)

通过上面的设置,主从复制环境已经OK(Slave_IO_Running和Slave_SQL_Running状态均为YES)

在cong11主节点上操作

mysql> unlock tables;

准备安装包

上传我们的mycat软件包到mycat-node

[root@mycat-node ~]# ls

网上下载地址:

MyCAT有提供编译好的安装包,支持windows、Linux、Mac、Solaris等系统上安装与运行。 官方下载主页http://www.mycat.io

解压软件

[root@mycat-node ~]# tar -zxvf Mycat-server-1.6.6.1-release-20181031195535-linux.tar.gz -C /usr/local/

目录解释如下:

[root@mycat-node ~]# cd /usr/local/mycat/

[root@mycat-node mycat]# ls

bin catlet conf lib logs version.txt

  • bin程序目录:

mycat命令,启动、重启、停止等

例如:Linux下运行:./mycat console

注:mycat支持的命令{ console | start | stop | restart | status | dump }

  • conf目录

存放配置文件,server.xml是Mycat服务器参数调整和用户授权的配置文件,schema.xml是数据库读写分离配置文件,rule.xml是分片(分库分表)规则的配置文件,分片规则的具体一些参数信息单独存放为文件,也在这个目录下。配置文件修改,需要重启Mycat或者通过8066端口reload.

  • lib目录

主要存放mycat依赖的一些jar文件,mycat是java开发的。

  • logs目录

日志文件,包括Mycat启动的日志和运行的日志。日志存放在logs/mycat.log中,每天一个文件,日志的配置是在conf/log4j2.xml中,根据自己的需要,可以调整输出级别为debug,debug级别下,会输出更多的信息,方便排查问题.

wrapper.log:为程序启动的日志,启动时的问题看这个

mycat.log:为脚本执行时的日志,SQL脚本执行报错后的具体错误内容,查看这个文件。mycat.log是最新的错误日志,历史日志会根据时间生成目录保存。

Mycat 需要安装JDK 1.7 或者以上版本
上传jdk版本

[root@mycat-node ~]# ls

[root@mycat-node ~]# tar -zxvf jdk-8u171-linux-x64.tar.gz -C /usr/local/

配置JDK环境变量

[root@mycat-node ~]# vim /etc/profile #在文件最后加入一下行

JAVA_HOME=/usr/local/jdk1.8.0_171

PATH=$JAVA_HOME/bin:$PATH

CLASSPATH=$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar

export PATH JAVA_HOME CLASSPATH

[root@mycat-node ~]# source /etc/profile #使环境变量生效

查看java环境

[root@mycat-node ~]# java -version

服务启动与启动设置

配置mycat环境变量

[root@mycat-node ~]# ln -s /usr/local/mycat/bin/* /usr/local/bin/

在conf/server.xml文件中配置mycat用户账号和授权信息

server.xml文件其实跟读写分离策略关系不大,但是需要用此文件来配置连接MyCat的用户及权限等。

配置Mycat的连接信息(账号密码):

[root@mycat-node conf]# cd /usr/local/mycat/conf/

[root@mycat-node conf]# cp server.xml server.xml.bak

[root@mycat-node ~]# vim server.xml

参数说明:

<!--xxxxxxxxxxxxx-->表示注释

<user name="mycatroot" defaultAccount="true"> //mycat对外的连接账户名

<property name="password">123456</property> //密码

<property name="schemas">HA</property> //表示mycat的逻辑数据库名称,可以自定义。

</user>

<user name="mycatreadonly"> //mycat对外的连接账户名

<property name="password">123456</property> //密码

<property name="schemas">HA</property>

<property name="readOnly">true</property> //只读权限

</user>

参数 说明

user 用户配置节点

name 登录的用户名,也就是连接Mycat的用户名。

password 登录的密码,也就是连接Mycat的密码

schemas 数据库名,这里会和schema.xml中的配置关联,多个用逗号分开,例如,这个用户需要管理两个数据库db1,db2,则配置db1,db2

privileges 配置用户针对表的增删改查的权限

readOnly mycat逻辑库所具有的权限。true为只读,false为读写都有,默认为false。

我这里配置了一个账号mycatroot,密码为123456,逻辑数据库为HA,这些信息都可以自己随意定义,读写权限都有,没有针对表做任何特殊的权限。账号mycatreadonly,密码为123456,逻辑数据库为HA,权限是只读。

注意:

server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录mycat时使用的账号信息。

逻辑库名(如上面的HA,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代理的真实mysql数据库的表,要在schema.xml里面也定义,否则会导致mycat服务启动失败!

如果设置多个连接mycat的用户名和密码,那么就需要在schema.xml文件中定义多个对应的库。

编辑MyCAT的配置文件schema.xml,关于dataHost的配置信息

schema.xml是最主要的配置项,此文件关联mysql读写分离策略、分库分表策略都是在此文件中配置的。
MyCat作为中间件,它只是一个代理,本身并不进行数据存储,需要连接后端的MySQL物理服务器,此文件就是用来连接MySQL服务器的!

schemaxml文件中配置参数解释

参数 说明

schema 数据库设置,此数据库为逻辑数据库,name与server.xml中schema对应。

dataNode 分片信息,也就是分库相关配置。

dataHost 物理数据库,真正存储数据的数据库。

[root@mycat-node ~]# cd /usr/local/mycat/conf/

[root@mycat-node conf]# cp schema.xml schema.xml.bak

[root@mycat-node ~] # vim schema.xml

参数说明:

  • schema属性解释:

<schema name="HA" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">

</schema>

一个<schema>相当一个数据库,其中

Name: 逻辑数据库名,与server.xml中的schema对应

sqlMaxLimit: select 时默认的limit,避免查询全表

dataNode='dn1' 分库的时候用到,不分也可以。dataNode对应<dataNode>的name

  • dataNode属性解释:

<dataNode name="dn1" dataHost="dh1" database="HA" />

name:指定逻辑数据节点名称,与schema中的dataNode一致。

dataHost:对应< dataHost >的name

database:真正要使用的数据库名称。如果一个节点上有多个库,可使用表达式db$0-99,表示指定0-99这100个数据库;

  • dataHost属性解释

有三个参数需要注意,balance和 switchType、writeType

其中,balance指的负载均衡类型,目前的取值有4种:

balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上。

balance="1",全部的readHost与stand by writeHost(备主)参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。

balance="2",所有读操作都随机的在writeHost、readhost上分发。

balance="3",所有读请求随机的分发到wiriterHost对应的readhost执行,writerHost不负担读压力

switchType指的是切换的模式,目前的取值也有4种:

switchType='-1' 表示不自动切换

switchType='1' 默认值,表示自动切换

switchType='2' 基于MySQL主从同步的状态决定是否切换,心跳语句为 show slave status

switchType='3'基于MySQL galary cluster的切换机制(适合集群)(1.4.1),心跳语句为 show status like 'wsrep%'

writeType表示写模式:

writeType="0",所有的操作发送到配置的第一个writehost

writeType="1",随机发送到配置的所有writehost

writeType="2",不执行写操作

其他参数说明:

maxCon:指定物理主机服务最大支持1000个连接;

minCon:指定物理主机服务最小保持10个连接;

heartbeat:这个标签内指明用于和后端数据库进行心跳检查的语句

writeHost & readHost:这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。唯一不同的是,writeHost指定写实例、readHost指定读实例,组着这些读写实例来满足系统的要求。在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。

配置方式一

<writeHost host="cong11" url="192.168.30.11:3306" password="123456" user="root"/>

<writeHost host="cong12" url="192.168.30.12:3306" password="123456" user="root"/>

<writeHost host="cong13" url="192.168.30.13:3306" password="123456" user="root"/>

配置方式二

<writeHost host="hostM1" url="192.168.30.11:3306" password="123456" user="root">

<readHost host="hostS2" url="192.168.30.12:3306" password="123456" user="root"/>

<readHost host="hostS3" url="192.168.30.13:3306" password="123456" user="root"/>

</writeHost>

启动之前最好将log的级别改为debug,这样方便查错,修改方法:

进入mycat/conf

#vim log4j2.xml

<asyncRoot level="info" includeLocation="true">

改为

<asyncRoot level="trace" includeLocation="true">

给所有mysql root远程登陆权限

mysql> grant all on *.* to root@'192.168.30.%' identified by '123456';

mysql>flush privileges;

启动mycat服务

[root@mycat-node ~]# mycat console #先使用console进行检测

按ctrl+c

检测成功,执行开启

[root@mycat-node ~]# mycat start

mycat支持的命令{ console | start | stop | restart | status | dump }

检测端口8066

[root@mycat-node ~]# netstat -antup | grep 8066

如果没有端口,查看日志

[root@mycat-node ~]# tail /usr/local/mycat/logs/mycat.log

连接mycat

使用mycatroot账号登陆

[root@mycat-node ~]# mysql -u mycatroot -p123456 -h 192.168.30.10 -P 8066

mysql> show databases;

mysql> use HA;

mysql> show tables;

mysql> select * from T1;

使用mycatonly账号登陆

使用mycatonly只读账号登陆测试是否有写权限

[root@mycat-node ~]# mysql -umycatreadonly -p123456 -P 8066 -h192.168.30.10

mysql> use HA;

mysql> insert into T1 values(2,'tom2');

模拟故障:从服务器挂掉了

[root@cong13 ~]# systemctl stop mysqld #关闭从cong13 mysqld

[root@mycat-node ~]# mysql -umycatroot -p123456 -P 8066 -h192.168.30.10

mysql> use HA;

mysql> insert into T1 values(2,'tom2');

Query OK, 1 row affected (0.00 sec)

mysql> select * from T1;

说明读写都没有问题。

模拟故障:主服务器挂掉了

[root@cong11 ~]# systemctl stop mysqld #关闭主服务器

在客户端测试读写

[root@mycat-node ~]# mysql -umycatroot -p123456 -P 8066 -h192.168.30.10

mysql> use HA;

mysql> select * from T1; #查询T1表

MySQL [HA]>insert into T1 values(3,'tom3');

说明:ERROR 1184 (HY000): 拒绝连接 #主数据库停止了,是无法写操作的,但不影响读.

MySQL高可用架构之MHA

简介:

MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。

该软件由两部分组成:MHA Manager(管理节点)和MHA Node(数据节点)。MHA Manager可以单独部署在一台独立的机器上管理多个master-slave集群,也可以部署在一台slave节点上。MHA Node运行在每台MySQL服务器上,MHA Manager会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master,然后将所有其他的slave重新指向新的master。整个故障转移过程对应用程序完全透明。

在MHA自动故障切换过程中,MHA试图从宕机的主服务器上保存二进制日志,最大程度的保证数据的不丢失,但这并不总是可行的。例如,如果主服务器硬件故障或无法通过ssh访问,MHA没法保存二进制日志,只进行故障转移而丢失了最新的数据。使用MySQL 5.5开始的半同步复制,可以大大降低数据丢失的风险。MHA可以与半同步复制结合起来。如果只有一个slave已经收到了最新的二进制日志,MHA可以将最新的二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点的数据一致性。

目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当master,一台充当备用master,另外一台充当从库,因为至少需要三台服务器,出于机器成本的考虑,淘宝也在该基础上进行了改造,目前淘宝TMHA已经支持一主一从。MHA 适合任何存储引擎, 只要能主从复制的存储引擎它都支持,不限于支持事物的 innodb 引擎。

官方介绍:https://code.google.com/p/mysql-master-ha/

MHA工作原理

相对比其它HA软件,MHA的目的在于维持MySQL Replication中Master库的高可用性,其最大特点是可以修复多个Slave之间的差异日志,最终使所有Slave保持数据一致,然后从中选择一个充当新的Master,并将其它Slave指向它。

(1)从宕机崩溃的master保存二进制日志事件(binlog events);

(2)识别含有最新更新的slave;

(3)应用差异的中继日志(relay log)到其他的slave;

(4)应用从master保存的二进制日志事件(binlog events);

(5)提升一个slave为新的master;

(6)使其他的slave连接新的master进行复制;

MHA软件组成

MHA软件由两部分组成,Manager工具包和Node工具包

Manager工具包主要包括以下几个工具:

masterha_check_ssh 检查MHA的SSH配置状况

masterha_check_repl 检查MySQL复制状况

masterha_manger 启动MHA

masterha_stop 停止MHA

masterha_check_status 检测当前MHA运行状态

masterha_master_monitor 检测master是否宕机

masterha_master_switch 控制故障转移(自动或者手动)

masterha_conf_host 添加或删除配置的server信息

Node工具包

(这些工具通常由MHA Manager的脚本触发,无需人为操作)主要包括以下几个工具:

save_binary_logs 保存和复制master的二进制日志

apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的slave

filter_mysqlbinlog 去除不必要的ROLLBACK事件(MHA已不再使用这个工具)

purge_relay_logs 清除中继日志(不会阻塞SQL线程)

注意:

为了尽可能的减少主库硬件损坏宕机造成的数据丢失,因此在配置MHA的同时建议配置成MySQL 5.5的半同步复制。(不是必须)

部署MHA

搭建环境

角色

主机名

IP地址

Server id

类型

Software

Manager

Cong10

192.168.30.10

管理节点

Mha4mysql-manager、mha4mysql-node

Master

Cong11

192.168.30.11

1

主mysql(写入)

mha4mysql-node

slave1

Cong12

192.168.30.12

2

从mysql(读)

mha4mysql-node

Slave2

Cong13

192.168.30.13

3

从mysql(读)

mha4mysql-node

其中master对外提供写服务, slave1提供读服务,slave2也提供读服务,一旦master宕机,将会把其中一个slave提升为新的master,其他slave指向新的master。

一、基础环境准备

在配置好IP地址及主机名后检查selinux,iptables/firewall设置,关闭selinux,iptables/firewall服务以便后期主从同步不出错。

注:时间要同步(在本实验环境中192.168.30.10主机作为NTP时间服务器)略

配置所有主机相互SSH登录无密码验证

[root@cong10 ~]# ssh-keygen -t rsa

[root@cong10 ~]# ssh-copy-id 192.168.30.10

[root@cong10 ~]# ssh-copy-id 192.168.30.11

[root@cong10 ~]# ssh-copy-id 192.168.30.12

[root@cong10 ~]# ssh-copy-id 192.168.30.13

[root@cong11 ~]# ssh-keygen -t rsa

[root@cong11 ~]# ssh-copy-id 192.168.30.10

[root@cong11 ~]# ssh-copy-id 192.168.30.11

[root@cong11 ~]# ssh-copy-id 192.168.30.12

[root@cong11 ~]# ssh-copy-id 192.168.30.13

[root@cong12 ~]# ssh-keygen -t rsa

[root@cong12 ~]# ssh-copy-id 192.168.30.10

[root@cong12 ~]# ssh-copy-id 192.168.30.11

[root@cong12 ~]# ssh-copy-id 192.168.30.12

[root@cong12 ~]# ssh-copy-id 192.168.30.13

[root@cong13 ~]# ssh-keygen -t rsa

[root@cong13 ~]# ssh-copy-id 192.168.30.10

[root@cong13 ~]# ssh-copy-id 192.168.30.11

[root@cong13 ~]# ssh-copy-id 192.168.30.12

[root@cong13 ~]# ssh-copy-id 192.168.30.13

测试ssh无交互登录

[root@cong10 ~]# for i in 10 11 12 13 ; do ssh 192.168.30.$i hostname ; done

cong10

cong11

cong12

cong13

在其他主机上执行同样的测试操作。

上传需要的软件包

上传我们的软件包

[root@cong10 ~]# ls

anaconda-ks.cfg mha4mysql-manager-0.57-0.el7.noarch.rpm mha4mysql-node-0.57-0.el7.noarch.rpm mhapath.tar.gz

yum安装软件依赖包

所有的服务器都需要安装软件依赖,搭建本地yum源用来安装MHA的软件依赖,如果有网的话,可以yum install -y epel-release安装epel源,用epel扩展源安装软件依赖

配置本地yum源

[root@cong10 ~]# vim /etc/yum.repos.d/mhapath.repo

[mha]

name=mhapath

baseurl=file:///root/mhapath

enabled=1

gpgcheck=0

[root@cong10 ~]# tar -zxvf mhapath.tar.gz #解压依赖包

[root@cong10 ~]# vim /etc/yum.repos.d/centos7.repo

[CentOS7]

name=CentOS-server

baseurl=file:///mnt

enabled=1

gpgcheck=0

[root@cong10 ~]# ls /etc/yum.repos.d/

centos7.repo mhapath.repo

[root@cong10 ~]# mount /dev/sr0 /mnt #挂载光驱

拷贝软件包和yum配置文件到其他节点

[root@cong10 ~]# scp -r /etc/yum.repos.d/* 192.168.30.11:/etc/yum.repos.d/

[root@cong10 ~]# scp -r /etc/yum.repos.d/* 192.168.30.12:/etc/yum.repos.d/

[root@cong10 ~]# scp -r /etc/yum.repos.d/* 192.168.30.13:/etc/yum.repos.d/

或者:

[root@cong10 ~]# for ip in 11 12 13 ; do scp -r /etc/yum.repos.d/* 192.168.30.$ip:/etc/yum.repos.d/ ; done

[root@cong10 ~]# scp -r /root/mha4mysql-node-0.57-0.el7.noarch.rpm 192.168.30.11:/root

[root@cong10 ~]# scp -r /root/mha4mysql-node-0.57-0.el7.noarch.rpm 192.168.30.12:/root

[root@cong10 ~]# scp -r /root/mha4mysql-node-0.57-0.el7.noarch.rpm 192.168.30.13:/root

或者:

[root@cong10 ~]# for ip in 11 12 13 ; do scp /root/mha4mysql-node-0.57-0.el7.noarch.rpm 192.168.30.$ip:/root ; done

[root@cong10 ~]# scp -r mhapath 192.168.30.11:/root

[root@cong10 ~]# scp -r mhapath 192.168.30.12:/root

[root@cong10 ~]# scp -r mhapath 192.168.30.13:/root

或者:

[root@cong10 ~]# for ip in 11 12 13 ; do scp -r /root/mhapath 192.168.30.$ip:/root ; done

在manager主机和各个node节点安装软件依赖件包

注:在数据库节点只要安装MHA的node工具包,在管理节点需要安装manager工具包和node工具包。

[root@cong10 ~]# yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager --skip-broken --nogpgcheck

[root@cong10 ~]# rpm -ivh mha4mysql-node-0.57-0.el7.noarch.rpm

[root@cong11 ~]# mount /dev/sr0 /mnt

[root@cong11 ~]# yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager --skip-broken --nogpgcheck

[root@cong11 ~]# rpm -ivh mha4mysql-node-0.57-0.el7.noarch.rpm

[root@cong12 ~]# mount /dev/sr0 /mnt

[root@cong12 ~]# yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager --skip-broken --nogpgcheck

[root@cong12 ~]# rpm -ivh mha4mysql-node-0.57-0.el7.noarch.rpm

[root@cong13 ~]# mount /dev/sr0 /mnt

[root@cong13 ~]# yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager --skip-broken --nogpgcheck

[root@cong13 ~]# rpm -ivh mha4mysql-node-0.57-0.el7.noarch.rpm

安装完成后会在/usr/bin/目录下生成以下脚本文件:

[root@cong10 ~]# cd /usr/bin/

[root@cong10 bin]# ll app* filter* purge* save*

-rwxr-xr-x 1 root root 16381 5月 31 2015 apply_diff_relay_logs

-rwxr-xr-x 1 root root 4807 5月 31 2015 filter_mysqlbinlog

-rwxr-xr-x 1 root root 8261 5月 31 2015 purge_relay_logs

-rwxr-xr-x 1 root root 7525 5月 31 2015 save_binary_logs

安装MHA Manager

MHA Manager中主要包括了几个管理员的命令行工具,例如master_manger,master_master_switch等。MHA Manger也依赖于perl模块。

安装MHA Manger依赖的perl模块

[root@cong10 ~]# yum install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker perl-CPAN -y

安装MHA Manager软件包:

[root@cong10 ~]# rpm -ivh mha4mysql-manager-0.57-0.el7.noarch.rpm

安装完成后会在/usr/bin目录下面生成以下脚本文件:

[root@cong10 ~]# ll /usr/bin/mast*

-rwxr-xr-x 1 root root 1995 5月 31 2015 /usr/bin/masterha_check_repl

-rwxr-xr-x 1 root root 1779 5月 31 2015 /usr/bin/masterha_check_ssh

-rwxr-xr-x 1 root root 1865 5月 31 2015 /usr/bin/masterha_check_status

-rwxr-xr-x 1 root root 3201 5月 31 2015 /usr/bin/masterha_conf_host

-rwxr-xr-x 1 root root 2517 5月 31 2015 /usr/bin/masterha_manager

-rwxr-xr-x 1 root root 2165 5月 31 2015 /usr/bin/masterha_master_monitor

-rwxr-xr-x 1 root root 2373 5月 31 2015 /usr/bin/masterha_master_switch

-rwxr-xr-x 1 root root 5171 5月 31 2015 /usr/bin/masterha_secondary_check

-rwxr-xr-x 1 root root 1739 5月 31 2015 /usr/bin/masterha_stop

搭建主从复制环境

为了尽可能的减少主库硬件损坏宕机造成的数据丢失,因此在配置MHA的同时建议配置成MySQL的半同步复制。

注:mysql半同步插件是由谷歌提供,具体位置/usr/local/mysql/lib/plugin/下,一个是master用的semisync_master.so,一个是slave用的semisync_slave.so,下面我们就来具体配置一下。

如果不清楚Plugin的目录,用如下查找:

1、分别在主从节点上安装相关的插件(master,备主master,slave),在MySQL上安装插件需要数据库支持动态载入。检查是否支持,用如下检测:

所有mysql数据库服务器,安装半同步插件(semisync_master.so,semisync_slave.so)

其他mysql主机采用同样的方法安装半同步插件

检查Plugin是否已正确安装:

mysql> show plugins;

mysql> select * from information_schema.plugins;

查看半同步相关信息:

上图可以看到半同复制插件已经安装,只是还没有启用,所以是off

在cong11配置主数据库服务器
配置my.cnf:

[root@cong11 ~]# vim /etc/my.cnf #在最后添加以下行

server-id=1

log-bin=/data/mysql/log/mysql-bin

log-bin-index=/data/mysql/log/mysql-bin.index

binlog_format=mixed
rpl_semi_sync_master_enabled=1

rpl_semi_sync_master_timeout=10000

rpl_semi_sync_slave_enabled=1

relay_log_purge=0

relay-log = /data/mysql/log/relay-bin

relay-log-index = /data/mysql/log/slave-relay-bin.index

binlog-do-db=HA #可以被从服务器复制的库。二进制需要同步的数据库名

log_slave_updates=1 #只有开启log_slave_updates,从库binlog才会记录主库同步的操作日志

注:相关参数解释

rpl_semi_sync_master_enabled=1 1表是启用,0表示关闭

rpl_semi_sync_master_timeout=10000 毫秒单位,该参数表示主服务器等待确认消息,10秒后,不再等待,变为异步方式。

relay_log_purge=0禁止 SQL 线程在执行完一个 relay log 后自动将其删除,对于MHA场景下,对于某些滞后从库的恢复依赖于其他从库的relay log,因此采取禁用自动删除功能,

[root@cong11 ~]# systemctl restart mysqld #重启服务

创建需要同步的数据库:

[root@cong11 ~]# mysql -uroot -p123456

mysql> create database HA;

mysql> use HA;

mysql> create table test(id int,name varchar(20));

mysql> insert into test values(1,'tom1');

授权:

mysql> grant replication slave on *.* to repl@'192.168.30.%' identified by '123456';

mysql> grant all privileges on *.* to manager@'192.168.30.%' identified by '123456';

mysql> flush privileges; #刷新权限

第一条grant命令是创建一个用于主从复制的帐号,在master和备主 master的主机上创建即可。

第二条grant命令是创建MHA管理账号,所有mysql服务器上都需要执行。MHA会在配置文件里要求能远程登录到数据库,所以要进行必要的赋权。

查看master的状态

导出HA数据库到从服务器

[root@cong11 ~]# mysqldump -uroot -p123456 -B HA>HA.sql

[root@cong11 ~]# scp HA.sql root@192.168.30.12:~

[root@cong11 ~]# scp HA.sql root@192.168.30.13:~

在cong12配置从服务:
导入数据库

[root@cong12 ~]# mysql -uroot -p123456 <HA.sql

配置my.cnf:

[root@cong12 ~]# vim /etc/my.cnf #在最后加入以下行

server-id=2

log-bin=/data/mysql/log/mysql-bin

log-bin-index=/data/mysql/log/mysql-bin.index

binlog_format=mixed

rpl_semi_sync_master_enabled=1

rpl_semi_sync_master_timeout=10000

rpl_semi_sync_slave_enabled=1

relay_log_purge=0

relay-log=/data/mysql/log/relay-bin

relay-log-index=/data/mysql/log/slave-relay-bin.index

binlog-do-db=HA

log_slave_updates=1 #只有开启log_slave_updates,从库binlog才会记录主库同步的操作日志

[root@cong12 ~]# systemctl restart mysqld #重启服务器

授权

[root@cong12 ~]# mysql -uroot -p123456

mysql> grant replication slave on *.* to repl@'192.168.30.%' identified by '123456';

mysql> grant all privileges on *.* to manager@'192.168.30.%' identified by '123456';

mysql> flush privileges; #刷新权限

建立主从关系

mysql> stop slave;

mysql>change master to master_host='192.168.30.11',master_user='repl',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=1350;

mysql> start slave;

mysql> show slave status\G

在cong13配置从服务:
导入数据库

[root@cong13 ~]# mysql -uroot -p123456 <HA.sql

配置my.cnf:

[root@cong13 ~]# vim /etc/my.cnf

server-id=3

log-bin=/data/mysql/log/mysql-bin

log-bin-index=/data/mysql/log/mysql-bin.index

binlog_format=mixed
rpl_semi_sync_master_enabled=1

rpl_semi_sync_master_timeout=10000

rpl_semi_sync_slave_enabled=1

relay_log_purge=0

relay-log = /data/mysql/log/relay-bin

relay-log-index = /data/mysql/log/slave-relay-bin.index

binlog-do-db=HA #可以被从服务器复制的库。二进制需要同步的数据库名

log_slave_updates=1 #只有开启log_slave_updates,从库binlog才会记录主库同步的操作日志

[root@cong13 ~]# systemctl restart mysqld #重启服务

授权

[root@cong13 ~]# mysql -uroot -p123456

mysql> grant replication slave on *.* to repl@'192.168.30.%' identified by '123456';

mysql> grant all privileges on *.* to manager@'192.168.30.%' identified by '123456';

mysql> flush privileges; #刷新权限

建立主从关系

mysql> stop slave;

mysql>change master to master_host='192.168.30.11',master_user='repl',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=1350;

mysql> start slave;

mysql> show slave status\G;

两台slave服务器设置read_only

从库对外提供读服务,只所以没有写进配置文件,是因为slave随时会提升为master

[root@cong12 ~]# mysql -uroot -p123456 -e 'set global read_only=1'

[root@cong13 ~]# mysql -uroot -p123456 -e 'set global read_only=1'

到这里整个集群环境已经搭建完毕,剩下的就是配置MHA软件了。

在master上查看半同步相关信息:

mysql> show variables like '%rpl_semi_sync%';

在master上查看半同步状态:

mysql> show status like '%rpl_semi_sync%';

有几个状态参数值得关注的:

rpl_semi_sync_master_status :显示主服务是异步复制模式还是半同步复制模式  

rpl_semi_sync_master_clients :显示有多少个从服务器配置为半同步复制模式  

rpl_semi_sync_master_yes_tx :显示从服务器确认成功提交的数量 (即master成功接收到slave的回复的次数。)

rpl_semi_sync_master_no_tx :显示从服务器确认不成功提交的数量  (即master 等待超时的次数)

rpl_semi_sync_master_tx_avg_wait_time :事务因开启 semi_sync ,平均需要额外等待的时间 (即master 花在每个事务上的平均等待时间) 

Rpl_semi_sync_master_tx_wait_time  :master 花在所有事物上的等待时间

rpl_semi_sync_master_net_avg_wait_time :事务进入等待队列后,到网络平均等待时间(即master 等待slave 回复的平均等待时间。单位毫秒.)  

Rpl_semi_sync_master_net_wait_time  :master 总的等待时间

Rpl_semi_sync_master_net_waits  :master 等待slave 回复的的总的等待次数。

Rpl_semi_sync_master_no_times:master 关闭半同步复制的次数。

Rpl_semi_sync_master_timefunc_failures  :记录master调用类似 gettimeofday()等函数的失败次数

Rpl_semi_sync_master_tx_waits  :master总的等待次数

Rpl_semi_sync_master_wait_sessions  :当前有多少个session 因为slave 的回复而造成等待

配置MHA

创建MHA的工作目录,并且创建相关配置文件

与绝大多数Linux应用程序类似,MHA的正确使用依赖于合理的配置文件。MHA的配置文件与mysql的my.cnf文件配置相似,采取的是param=value的方式来配置,配置文件位于管理节点,通常包括每一个mysql server的主机名,mysql用户名,密码,工作目录等等。

[root@cong10 ~]# mkdir -p /etc/masterha

[root@cong10 ~]# mkdir -p /var/log/masterha/app1

[root@cong10 ~]# vim /etc/masterha/app1.cnf

修改app1.cnf配置文件,修改后的文件内容如下

[server default]

manager_workdir=/var/log/masterha/app1 #设置manager的工作目录

manager_log=/var/log/masterha/app1/manager.log #设置manager的日志

master_binlog_dir=/data/mysql/log #设置master 保存binlog的位置,以便MHA可以找到master的日志,我这里的也就是mysql的数据目录,注:所有mysql的binlog文件路径都要与该路径一致。也可以在mysql定义区域单独指向每个mysql的binlog位置。

master_ip_failover_script= /usr/bin/master_ip_failover #设置自动故障切换时候的脚本

master_ip_online_change_script=/usr/bin/master_ip_online_change #设置手动切换时候的切换脚本

user=manager #设置监控用户manager

password=123456 #监控用户manager的密码

ping_interval=1 #设置监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应的时候自动进行failover

remote_workdir=/tmp #设置远端mysql在发生切换时binlog的保存位置

repl_user=repl #设置复制环境中的复制用户名

repl_password=123456 #设置复制用户的密码

report_script=/usr/local/send_report #设置发生切换后发送的报警的脚本

shutdown_script="" #设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机防止发生脑裂,这里没有使用)

ssh_user=root #设置ssh的登录用户名

[server1]

hostname=192.168.30.11

port=3306

#candidate_master=1

[server2]

hostname=192.168.30.12

port=3306

#candidate_master=1 #设置为候选master,如果设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的slave

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

[server3]

hostname=192.168.30.13

port=3306

          1. /etc/masterha/app1.cnf 配置文件内容如下:

[server default]

manager_workdir=/var/log/masterha/app1

manager_log=/var/log/masterha/app1/manager.log

master_binlog_dir=/data/mysql/log

master_ip_failover_script= /usr/bin/master_ip_failover

master_ip_online_change_script=/usr/bin/master_ip_online_change

user=manager

password=123456

ping_interval=1

remote_workdir=/tmp

repl_user=repl

repl_password=123456

report_script=/usr/local/send_report

shutdown_script=""

ssh_user=root

[server1]

hostname=192.168.30.11

port=3306

[server2]

hostname=192.168.30.12

port=3306

[server3]

hostname=192.168.30.13

port=3306

检查SSH配置

检查MHA Manger到所有MHA Node的SSH连接状态:

[root@cong10 ~]# masterha_check_ssh --conf=/etc/masterha/app1.cnf

如果报错:请检查你所有节点是不是都配置了SSH免密登陆

检查整个复制环境状况

通过masterha_check_repl脚本查看整个集群的复制状态

[root@cong10 ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf

在验证时,若遇到这个错误:Can't exec "mysqlbinlog" ......

解决方法是在所有mysql服务器上执行:

[root@cong10 ~]# ln -s /usr/local/mysql/bin/* /usr/local/bin/

[root@cong10 ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf

这是因为/etc/masterha/app1.cnf文件中关于自动故障切换和手动故障切换的脚本不存在,解决方法先暂时将这两行注释掉。如下所示

#master_ip_failover_script=/usr/bin/master_ip_failover

#master_ip_online_change_script=/usr/bin/master_ip_online_change

再次执行[root@cong10 ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf

验证成功的话会自动识别出所有服务器和主从状况。

注:如果报如下错误

这是因为之前健康检查报错,需要删除之前健康检查的文件

[root@cong10 ~]# rm -rf /var/log/masterha/app1/app1.master_status.health

检查MHA Manager的状态:

通过master_check_status脚本查看Manager的状态

[root@cong10 ~]# masterha_check_status --conf=/etc/masterha/app1.cnf

app1 is stopped(2:NOT_RUNNING).

注意:如果正常,会显示"PING_OK",否则会显示"NOT_RUNNING",这代表MHA监控没有开启。

开启MHA Manager监控

[root@cong10 ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf \

--remove_dead_master_conf --ignore_last_failover < /dev/null > \

/var/log/masterha/app1/manager.log 2>&1 &

启动参数介绍:

--remove_dead_master_conf 该参数代表当发生主从切换后,老的主库的ip将会从配置文件中移除。

--manger_log 日志存放位置

--ignore_last_failover 在缺省情况下,如果MHA检测到连续发生宕机,且两次宕机间隔不足8小时的话,则不会进行Failover故障转移,该参数代表忽略上次MHA触发切换产生的文件。默认情况下,MHA发生切换后会在日志目录,也就是上面设置的/data产生app1.failover.complete文件,下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后删除该文件,为了方便,这里设置为--ignore_last_failover。

再次查看MHA Manager监控是否正常

[root@cong10 ~]# masterha_check_status --conf=/etc/masterha/app1.cnf

app1 (pid:10265) is running(0:PING_OK), master:192.168.30.11

可以看见已经在监控了,而且master的主机为192.168.30.11

查看启动日志

[root@cong10 ~]# tail -20 /var/log/masterha/app1/manager.log

其中"Ping(SELECT) succeeded, waiting until MySQL doesn't respond.."说明整个系统已经开始监控了。

关闭MHA Manage监控

关闭很简单,使用masterha_stop命令完成

[root@cong10 ~]# masterha_stop --conf=/etc/masterha/app1.cnf

模拟故障

开启监控

[root@cong10 ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf \

--remove_dead_master_conf --ignore_last_failover < /dev/null > \

/var/log/masterha/app1/manager.log 2>&1 &

打开新窗口观察日志

[root@cong10 ~]# tail -0f /var/log/masterha/app1/manager.log

模拟主库挂掉

[root@cong11 ~]# systemctl stop mysqld

看日志是否切换master成功

可以看到master已经切换到192.168.30.12

从日志信息中可以看到 master failover 已经成功了,并可以看出故障转移的大体流程。

登陆从cong13查看show slave status\G是否成功切换

[root@cong13 ~]# mysql -uroot -p123456

mysql> show slave status\G

可以看到 master 的 IP 现在为 192.168.30.12,已经切换到和192.168.30.12同步了,本来是和192.168.30.11同步的,说明 MHA 已经把cong12提升为了新的 master,IO线程和SQL线程也正确运行,MHA 搭建成功。

查看cong12主从状态

[root@cong12 ~]# mysql -uroot -p123456

mysql> show processlist \G

发现只剩下cong13的slave,MHA把原先的master(cong11)踢掉了

关于配置VIP配合MHA使用

使用VIP 可以实现mysql master服务器的高可用。

vip配置可以采用两种方式,一种通过keepalived的方式管理虚拟ip的浮动;另外一种通过脚本方式启动虚拟ip的方式(即不需要keepalived或者heartbeat类似的软件)。

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

在mysql主上配置VIP

下面是通过脚本的方式管理VIP。如果使用脚本管理vip的话,需要手动在master服务器上绑定一个vip由于刚才把mysql主切换到cong12上,这里在cong12上配置。

[root@cong12 ~]# ifconfig ens33:1 192.168.30.200 netmask 255.255.255.0 up

[root@cong12 ~]# ifconfig

在主配置文件里开启脚本

在主配置文件添加master_ip_failover_script=/usr/bin/master_ip_failover,MHA切换master后,会把原先的msater清除,把刚才清掉的cong11的mysql 添加进主配置文件,设为slave。

[root@cong10 ~]# vim /etc/masterha/app1.cnf #添加或修改以下标红部分

[server default]

manager_log=/var/log/masterha/app1/manager.log

manager_workdir=/var/log/masterha/app1

master_binlog_dir=/data/mysql/log

password=123456

ping_interval=1

remote_workdir=/tmp

repl_password=123456

repl_user=repl

report_script=/usr/local/send_report

shutdown_script=""

ssh_user=root

user=manager

master_ip_failover_script=/usr/bin/master_ip_failover #开启脚本

[server1] # 添加master

hostname=192.168.30.12

port=3306

[server2]

hostname=192.168.30.11

port=3306

[server3]

hostname=192.168.30.13

port=3306

把cong11设为mysql从服务器

主从切换后续工作

重构:

重构就是你的主挂了,切换到备主 master上,备主master变成了主,因此重构就是将原来的主库修复成一个新的slave

主库切换后,把原主库修复成新从库,原主库数据文件完整的情况下,可通过以下方式找出最后执行的CHANGE MASTER命令:

[root@cong10 ~]# grep "CHANGE MASTER TO MASTER" /var/log/masterha/app1/manager.log | tail -1

Fri Jul 26 20:51:43 2019 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='192.168.30.12', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=2311, MASTER_USER='repl', MASTER_PASSWORD='xxx';

[root@cong11 ~]# systemctl start mysqld

[root@cong11 ~]# mysql -uroot -p123456

mysql> stop slave;

mysql>CHANGE MASTER TO MASTER_HOST='192.168.30.12', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=2311, MASTER_USER='repl', MASTER_PASSWORD='123456';

mysql> start slave;

mysql> show slave status\G

查看cong12master状态

[root@cong12 ~]# mysql -uroot -p123456

mysql> show processlist \G

主从配置OK

编写脚本/usr/bin/master_ip_failover,要会perl脚本语言

要会perl脚本语言

这里是修改/usr/local/bin/master_ip_failover,修改完成后内容如下,我的vip使用的是192.168.30.200/24.

[root@cong10 ~]# vim /usr/bin/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

);

my $vip = '192.168.30.200/24';

my $key = '1';

my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";

my $ssh_stop_vip = "/sbin/ifconfig ens33:$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";

#`ssh $ssh_user\@cluster1 \" $ssh_start_vip \"`;

exit 0;

}

else {

&usage();

exit 1;

}

}

# A simple system call that enable the VIP on the new master

sub start_vip() {

`ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;

}

# A simple system call that disable the VIP on the old_master

sub stop_vip() {

`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";

}

给脚本添加可执行权限

[root@cong10 ~]# chmod +x /usr/bin/master_ip_failover

检查SSH配置

检查MHA Manger到所有MHA Node的SSH连接状态:

[root@cong10 ~]# masterha_check_ssh --conf=/etc/masterha/app1.cnf

检查整个集群复制环境状况

需要删除之前健康检查的文件

[root@cong10 ~]# rm -rf /var/log/masterha/app1/app1.master_status.health //如果存在就删除

[root@cong10 ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf

开启MHA Manager监控

[root@cong10 ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf \

--remove_dead_master_conf --ignore_last_failover < /dev/null > \

/var/log/masterha/app1/manager.log 2>&1 &

[1] 16396

查看MHA Manager监控是否正常

[root@cong10 ~]# masterha_check_status --conf=/etc/masterha/app1.cnf

app1 (pid:16396) is running(0:PING_OK), master:192.168.30.12

查看启动日志

[root@cong10 ~]# tail -20 /var/log/masterha/app1/manager.log

打开新窗口观察日志

[root@cong10 ~]# tail -0f /var/log/masterha/app1/manager.log

模拟主库挂掉

[root@cong12 ~]# systemctl stop mysqld

看日志是否切换master成功

可以看到master已经切换到192.168.30.11

登陆从cong13查看show slave status\G是否成功切换

[root@cong13 ~]# mysql -uroot -p123456

mysql> show slave status\G

查看cong11 主从状态

[root@cong11 ~]# mysql -uroot -p123456

mysql> show processlist \G

查看VIP是否漂移过来

[root@cong11 ~]# ifconfig

注意:master切换以后,MHA监控就会停止,会在配置文件删除出问题的主机配置信息,我们可以把出问题的mysql服务器修复好以后,重新添加进集群,开启MHA监控。

主从切换后续工作

重构:

重构就是你的主挂了,切换到备主 master上,备主master变成了主,因此重构就是将原来的主库修复成一个新的slave

主库切换后,把原主库修复成新从库,原主库数据文件完整的情况下,可通过以下方式找出最后执行的CHANGE MASTER命令:

[root@cong10 ~]# grep "CHANGE MASTER TO MASTER" /var/log/masterha/app1/manager.log

将cong12修复为cong11的从库

[root@cong12 ~]# systemctl start mysqld

mysql> stop slave;

mysql> CHANGE MASTER TO MASTER_HOST='192.168.30.11', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154, MASTER_USER='repl', MASTER_PASSWORD='123456';

mysql> start slave;

mysql> show slave status\G;

[root@cong10 ~]# vim /etc/masterha/app1.cnf #添加或修改以下标红部分

manager_log=/var/log/masterha/app1/manager.log

manager_workdir=/var/log/masterha/app1

master_binlog_dir=/data/mysql/log

master_ip_failover_script=/usr/bin/master_ip_failover

password=123456

ping_interval=1

remote_workdir=/tmp

repl_password=123456

repl_user=repl

report_script=/usr/local/send_report

shutdown_script=""

ssh_user=root

user=manager

[server1] //添加master

hostname=192.168.30.11

port=3306

[server2]

hostname=192.168.30.12 //修改192.168.30.11为192.168.30.12

port=3306

[server3]

hostname=192.168.30.13

port=3306

开启MHA Manager监控

[root@cong10 ~]# nohup masterha_manager --conf=/etc/masterha/app1.cnf \

--remove_dead_master_conf --ignore_last_failover < /dev/null > \

/var/log/masterha/app1/manager.log 2>&1 &

查看MHA Manager监控是否正常

[root@cong10 ~]# masterha_check_status --conf=/etc/masterha/app1.cnf

app1 (pid:16396) is running(0:PING_OK), master:192.168.30.11

posted @ 2023-07-21 09:13  ღ᭄遇见你²⁰²²  阅读(810)  评论(0)    收藏  举报