Keepalived+mysql双主来实现MySQL-HA
生产环境中一台mysql主机存在单点故障,所以我们要确保mysql的高可用性,即两台MySQL服务器如果其中有
一台MySQL服务器挂掉后,另外一台能立马接替其进行工作。
MySQL的高可用方案一般有如下几种:keepalived+双主,MHA,PXC,MMM,Heartbeat+DRBD等,比较常用的是keepalived+双主,MHA和PXC。
本节主要介绍了利用 keepalived 实现 MySQL 数据库的高可用。
Keepalived+mysql双主来实现MySQL-HA,我们必须保证两台MySQL数据库的数据完全一样,基本思路是两台MySQL互为主从关系,通过Keepalived配置虚拟IP,实现当其中的一台MySQL数据库宕机后,应用能够自动切换到另外一台MySQL数据库,保证系统的高可用。
一、实验环境
操作系统 | CentOS 7 |
---|---|
数据库版本 | V5.7 |
master A地址 | 192.168.206.130 |
master B地址 | 192.168.206.131 |
安装目录 | 在线安装 |
数据目录 | /var/lib/mysql |
注意下面几点:
1. 要保证同步服务期间之间的网络联通。即能相互ping通,能使用对方授权信息连接到对方数据库(防火墙开放3306端口)。
2. 关闭selinux。
3. 同步前,双方数据库中需要同步的数据要保持一致。这样,同步环境实现后,再次更新的数据就会如期同步了。
二、MySQL复制
1、MySQL支持哪些复制
(1)基于语句的复制
在主服务器上执行的sql语句,在从服务器上执行同样的语句。mysql默认采用基于语句的复制,效率比较高。一旦发现没法精确复制时,会自动选择基于行的复制。
(2)基于行的复制
把改变的内容复制过去,而不是把命令在从服务器上执行一遍,从mysql 5.0开始支持。
(3)混合类型的复制
默认采用基于语句的复制,一旦发现基于语句的无法精确复制时,就会采用基于行的复制。
2、MySQL复制解决的问题
- 数据分布(data distribution)
- 负载平衡(load balancing)
- 数据备份(backup),保证数据安全
- 高可用性与容错行(high availability and failover)
- 实现读写分离,缓解数据库压力
3、MySQL主从复制原理
master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中;slave服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变。如果发生改变,则开始一个I/O Thread请求master二进制事件,同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志 中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后I/O Thread和SQL Thread将进入睡眠状态,等待下一次被唤醒。
注意几点:
(1)master将操作语句记录到binlog日志中,然后授予slave远程连接的权限(master一定要开启binlog二进制日志功能;通常为了数据安全考虑,slave也开启binlog功能)。
(2)-slave开启两个线程:IO线程和SQL线程。其中:IO线程负责读取master的binlog内容到中继日志relay log里;SQL线程负责从relay log日志里读出binlog内容,并更新到slave的数据库里,这样就能保证slave数据和 master数据保持一致了。
(3)Mysql复制至少需要两个Mysql的服务,当然Mysql服务可以分布在不同的服务器上,也可以在一台服务器上启动多个服务。
(4)Mysql复制最好确保master和slave服务器上的Mysql版本相同(如果不能满足版本一致,那么要保证master主节点的版本低于slave从节点的版本)。
(5)master和slave两节点间时间需同步。
4、MySQL复制流程
Mysql复制的流程图如下:
如上图所示:
Mysql复制过程的第一部分就是master记录二进制日志。在每个事务更新数据完成之前,master在二日志记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务。
第二部分就是slave将master的binary log拷贝到它自己的中继日志。首先,slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志。
SQL slave thread(SQL从线程)处理该过程的最后一步。SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。
此外,在master中也有一个工作线程:和其它MySQL的连接一样,slave在master中打开一个连接也会使得master开始一个线程。复制过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操作不能在slave上并行操作。
5、MySQL复制的模式
(1)主从复制
主库授权从库远程连接,读取binlog日志并更新到本地数据库的过程;主库写数据后,从库会自动同步过来(从库跟着主库变)。
(2)主主复制
主从相互授权连接,读取对方binlog日志并更新到本地数据库的过程;只要对方数据改变,自己就跟着改变。
6、MySQL主从复制优点
(1)在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;(主库写,从库读,降压)
(2)在从主服务器进行备份,避免备份期间影响主服务器服务;(确保数据安全)
(3)当主服务器出现问题时,可以切换到从服务器。(提升性能)
7、MySQL主从复制工作流程细节
(1)MySQL支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。
MySQL复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器上已经记录到其二进制日志的保存的更新。当一个从服务器连接主服务器时,它通知主服务器定位到从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,并在本机上执行相同的更新。然后封锁并等待主服务器通知新的更新。从服务器执行备份不会干扰主服务器,在备份过程中主服务器可以继续处理更新。
(2)MySQL使用3个线程来执行复制功能,其中两个线程(Sql线程和IO线程)在从服务器,另外一个线程(IO线程)在主服务器。
当发出START SLAVE时,从服务器创建一个I/O线程,以连接主服务器并让它发送记录在其二进制日志中的语句。主服务器创建一个线程将二进制日志中的内容发送到从服务器。该线程可以即为主服务器上SHOW PROCESSLIST的输出中的Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷贝到从服务器数据目录中的本地文件中,即中继日志。第3个线程是SQL线程,由从服务器创建,用于读取中继日志并执行日志中包含的更新。在从服务器上,读取和执行更新语句被分成两个独立的任务。当从服务器启动时,其I/O线程可以很快地从主服务器索取所有二进制日志内容,即使SQL线程执行更新的远远滞后。
8、总结
(1)主从数据完成同步的过程
1)在Slave 服务器上执行sart slave命令开启主从复制开关,开始进行主从复制。
2)此时,Slave服务器的IO线程会通过在master上已经授权的复制用户权限请求连接master服务器,并请求从执行binlog日志文件的指定位置(日志文件名和位置就是在配置主从复制服务时执行change master命令指定的)之后开始发送binlog日志内容。
3)Master服务器接收到来自Slave服务器的IO线程的请求后,其上负责复制的IO线程会根据Slave服务器的IO线程请求的信息分批读取指定binlog日志文件指定位置之后的binlog日志信息,然后返回给Slave端的IO线程。返回的信息中除了binlog日志内容外,还有在Master服务器端记录的IO线程。返回的信息中除了binlog中的下一个指定更新位置。
4)当Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件(Mysql-relay-bin.xxx)的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容。
5)Slave服务器端的SQL线程会实时检测本地Relay Log 中IO线程新增的日志内容,然后及时把Relay LOG 文件中的内容解析成sql语句,并在自身Slave服务器上按解析SQL语句的位置顺序执行应用这样sql语句,并在relay-log.info中记录当前应用中继日志的文件名和位置点。
(2)主从复制条件
1)开启Binlog功能
2)主库要建立账号
3)从库要配置master.info(CHANGE MASTER to...相当于配置密码文件和Master的相关信息)
4)start slave 开启复制功能
(3)需要了解的
1)3个线程,主库IO,从库IO和SQL及作用
2)master.info(从库)作用
3)relay-log 作用
4)异步复制
5)binlog作用(如果需要级联需要开启Binlog)
(4)需要注意的
1)主从复制是异步的逻辑的SQL语句级的复制
2)复制时,主库有一个I/O线程,从库有两个线程,I/O和SQL线程
3)实现主从复制的必要条件是主库要开启记录binlog功能
4)作为复制的所有Mysql节点的server-id都不能相同
5)binlog文件只记录对数据库有更改的SQL语句(来自主库内容的变更),不记录任何查询(select,show)语句
三、配置两台MySQL主从复制
1、主从复制实现过程
(1)master配置
1)配置master数据库的my.cnf文件
在[mysqld]配置区域添加下面内容:
[mysqld]
server-id=1 #数据库唯一ID,主从的标识号绝对不能重复。
log-bin=mysql-bin #开启bin-log,并指定文件目录和文件名前缀
binlog-do-db=liting #需要同步liting数据库。如果是多个同步库,就以此格式另写几行即可。如果不指明对某个具体库同步,就去掉此行,表示同步所有库(除了ignore忽略的库)。
binlog-ignore-db=mysql #不同步mysql系统数据库。如果是多个不同步库,就以此格式另写几行;也可以在一行,中间逗号隔开。
sync_binlog = 1 #确保binlog日志写入后与硬盘同步
binlog_checksum = none #跳过现有的采用checksum的事件,mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none
binlog_format = mixed #bin-log日志文件格式,设置为MIXED可以防止主键重复。
温馨提示:
在主服务器上最重要的二进制日志设置是sync_binlog,这使得mysql在每次提交事务的时候把二进制日志的内容同步到磁盘上,即使服务器崩溃也会把事件写入日志中。
sync_binlog这个参数是对于MySQL系统来说是至关重要的,他不仅影响到Binlog对MySQL所带来的性能损耗,而且还影响到MySQL中数据的完整性。对于"sync_binlog"参数的各种设置的说明如下:
sync_binlog=0,当事务提交之后,MySQL不做fsync之类的磁盘同步指令刷新binlog_cache中的信息到磁盘,而让Filesystem自行决定什么时候来做同步,或者cache满了之后才同步到磁盘。
sync_binlog=n,当每进行n次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。
在MySQL中系统默认的设置是sync_binlog=0,也就是不做任何强制性的磁盘刷新指令,这时候的性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失。而当设置为“1”的时候,是最安全但是性能损耗最大的设置。因为当设置为1的时候,即使系统Crash,也最多丢失binlog_cache中未完成的一个事务,对实际数据没有任何实质性影响。
从以往经验和相关测试来看,对于高并发事务的系统来说,“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。
2)保证master与slave数据库一致
导出master数据库多余slave数据库中的数据,然后导入到slave数据库中。保证双方在同步环境实现前的数据一致。
注意:新建环境可忽略此步骤
导出数据库之前先锁定数据库
# 数据库只读锁定命令,防止导出数据库的时候有数据写入。unlock tables命令解除锁定
mysql> flush tables with read lock;
导出master数据库中需要同步的库(master数据库的root用户登陆密码:1234)
[root@master ~]# mysqldump -uroot liting -p1234 >/opt/liting.sql
# 将导出的sql文件上传到slave机器上
[root@master ~]# rsync -e "ssh -p22" -avpgolr /opt/liting.sql 192.168.0.104:/opt/
3)设置数据同步权限
mysql> grant replication slave,replication client on *.* to repl@'192.168.0.104' identified by "repl123"; #只允许192.168.0.104使用repl,且密码为"repl123"连接主库做数据同步
Query OK, 0 rows affected (0.02 sec)
#若要所有网段则设置repl@'%' ;部分网段:repl@'192.168.0.%'
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
温馨提示:
权限查看方式
mysql> show grants;
mysql> show grants for repl@'192.168.0.104';
4)查看主服务器master状态
注意File与Position项,从服务器需要这两项参数。
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 120 | liting | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
(2)slave配置
下面是slave数据库上的操作:
1)设置slave数据库的my.cnf文件
在[mysqld]配置区域添加下面内容:
[mysqld]
server-id=2 #设置从服务器id,必须于主服务器不同
log-bin=mysql-bin #启动MySQ二进制日志系统
replicate-do-db=liting #需要同步的数据库名。如果不指明同步哪些库,就去掉这行,表示所有库的同步(除了ignore忽略的库)。
replicate-ignore-db=mysql #不同步test数据库
slave-skip-errors = all #跳过所有的错误,继续执行复制操作
温馨提示:
当只针对某些库的某张表进行同步时,如下,只同步liting库的haha表和test库的heihei表:
replicate-do-db = liting
replicate-wild-do-table = liting.haha ``//``当只同步几个或少数表时,可以这样设置。注意这要跟上面的库指定配合使用;
replicate-do-db = test
replicate-wild-do-table = test.heihei ``//``如果同步的库的表比较多时,就不能这样一一指定了,就把这个选项配置去掉,直接根据指定的库进行同步。
2)保证master与slave数据库一致
在slave数据库中导入从master传过来的数据。
# 先创建一个liting空库,否则下面导入数据时会报错说此库不存在。
mysql> CREATE DATABASE liting CHARACTER SET utf8 COLLATE utf8_general_ci;
mysql> use liting;
# 导入master中多余的数据。
mysql> source /opt/liting.sql;
3)配置主从同步指令
mysql> stop slave; #执行同步前,要先关闭slave
mysql> change master to master_host='192.168.0.103',master_user='repl',master_password='repl123',master_log_file='mysql-bin.000007',master_log_pos=120;
mysql> start slave;
mysql> show slave status \G;
.......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
如上,当IO和SQL线程的状态均为Yes,则表示主从已实现同步了!
2、测试
下面测试下Mysql主从同步的效果,在master主数据库上写入新数据
mysql> use liting;
mysql>create table if not exists haha (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into huanqiu.haha values(100,'anhui');
Query OK, 1 row affected (0.00 sec)
然后在slave数据库上查看,发现master上新写入的数据已经同步过来了。
mysql> select * from liting.haha;
+-----+-----------+
| id | name |
+-----+-----------+
| 100 | anhui |
+-----+-----------+
1 rows in set(0.00 sec)
至此,主从同步环境已经实现!
四、配置两台MySQL主主复制
根据上面的主从环境部署,master和slave已经实现同步,即在master上写入新数据,自动同步到slave。而从库只能读不能写,一旦从库有写入数据,就会造成主从数据不一致!
下面就说下Mysql主主复制环境,在slave上更新数据时,master也能自动同步过来。
1、温馨提示
在做主主同步前,提醒下需要特别注意的一个问题:
主主复制和主从复制有一些区别,因为多主中都可以对服务器有写权限,所以设计到自增长重复问题,例如:
出现的问题(多主自增长ID重复)
1)首先在A和B两个库上创建test表结构;
2)停掉A,在B上对数据表test(存在自增长属性的ID字段)执行插入操作,返回插入ID为1;
3)然后停掉B,在A上对数据表test(存在自增长属性的ID字段)执行插入操作,返回的插入ID也是1;
4)然后同时启动A,B,就会出现主键ID重复
2、解决方法
只要保证两台服务器上的数据库里插入的自增长数据不同就可以了。
如:A插入奇数ID,B插入偶数ID,当然如果服务器多的话,还可以自定义算法,只要不同就可以了。
在下面例子中,在两台主主服务器上加入参数,以实现奇偶插入!
记住:在做主主同步时需要设置自增长的两个相关配置,如下:
auto_increment_offset 表示自增长字段从那个数开始,取值范围是1 .. 65535。这个就是序号。如果有n台mysql机器,则从第一台开始分为设1,2...n
auto_increment_increment 表示自增长字段每次递增的量,其默认值是1,取值范围是1 .. 65535。如果有n台mysql机器,这个值就设置为n。
在主主同步配置时,两台服务器的自增长参数设置如下:
auto_increment_increment 增长量都配置为2
auto_increment_offset 分别配置为1和2。这是序号,第一台从1开始,第二台就是2,以此类推.....
这样才可以避免两台服务器同时做更新时自增长字段的值之间发生冲突。(针对的是有自增长属性的字段)
3、主主同步实现操作过程
(1)master配置
1)配置master数据库的my.cnf文件
在[mysqld]配置区域添加下面内容:
[root@master ~]# vim /etc/my.cnf
#
server-id = 1
log-bin = mysql-bin
binlog-ignore-db = mysql,information_schema
sync_binlog = 1
binlog_checksum = none
binlog_format = mixed
#
auto-increment-increment = 2
#
auto-increment-offset = 1
slave-skip-errors = all
2)重启MySQL
[root@master ~]# systemctl restart mysqld
3)设置数据同步授权
防火墙开启3306端口
[root@master ~]# firewall-cmd --zone=public --add-port=3306/tcp --permanent
[root@master ~]# firewall-cmd --reload
要确保对方机器能使用下面权限连接到本机mysql。
mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password_check_user_name | OFF |
| validate_password_dictionary_file | |
| validate_password_length | 8 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | MEDIUM |
| validate_password_special_char_count | 1 |
+--------------------------------------+--------+
7 rows in set (0.00 sec)
mysql> set global validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_length=6;
Query OK, 0 rows affected (0.00 sec)
mysql> grant replication slave,replication client on *.* to repl@'192.168.206.131' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
最好将库锁住,仅仅允许读,以保证数据一致性;待主主同步环境部署后再解锁;锁住后,就不能往表里写数据,但是重启mysql服务后就会自动解锁!
# 注意该参数设置后,如果自己同步对方数据,同步前一定要记得先解锁!
mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+--------------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000002 | 613 | | mysql,information_schema | |
+------------------+----------+--------------+--------------------------+-------------------+
1 row in set (0.00 sec)
(2)slave配置
如果是克隆的mysql,需要修改uuid,不能与master的uuid相同。如下所示:
[root@slave ~]# vim /var/lib/mysql/auto.cnf
[auto]
server-uuid=5e007fd8-afb0-11ea-93a9-000c29bfd16d
1)配置slave数据库的my.cnf文件
[root@slave ~]# vim /etc/my.cnf
#
server-id= 2
log-bin = mysql-bin
binlog-ignore-db = mysql,information_schema
sync_binlog = 1
binlog_checksum = none
binlog_format = mixed
#
auto-increment-increment = 2
#
auto-increment-offset = 2
slave-skip-errors = all
2)重启MySQL
[root@slave ~]# systemctl restart mysqld
3)设置数据同步授权
防火墙开启3306端口
[root@slave ~]# firewall-cmd --zone=public --add-port=3306/tcp --permanent
[root@slave ~]# firewall-cmd --reload
要确保对方机器能使用下面权限连接到本机mysql。
同理,slave也要授权给master机器远程同步数据的权限。
mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password_check_user_name | OFF |
| validate_password_dictionary_file | |
| validate_password_length | 8 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | MEDIUM |
| validate_password_special_char_count | 1 |
+--------------------------------------+--------+
7 rows in set (0.00 sec)
mysql> set global validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_length=6;
Query OK, 0 rows affected (0.00 sec)
mysql> grant replication slave,replication client on *.* to repl@'192.168.206.130' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.02 sec)
mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+--------------------------+------------------ -+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+------------------ -+
| mysql-bin.000001 | 613 | | mysql,information_schema | |
+------------------+----------+--------------+--------------------------+------------------ -+
1 row in set (0.00 sec)
4、测试
(1)主主双向同步
1)slave同步master
确保slave上要同步的数据,提前在master上存在,最好双方数据保持一致。
#先解锁,将对方数据同步到自己的数据库中
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> change master to master_host='192.168.206.130',master_user='repl',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=150;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.206.130
Master_User: repl
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
Master_Server_Id: 1
Master_UUID: 5e007fd8-afb0-11ea-93a9-000c29bfd16c
Master_Info_File: /var/lib/mysql/master.info
这样就实现了slave->master的同步环境。
2)master同步slave
确保slave上要同步的数据,提前在master上存在,最好双方数据保持一致。
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to master_host='192.168.206.131',master_user='repl',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=150;
Query OK, 0 rows affected, 2 warnings (0.05 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.206.131
Master_User: repl
Master_Port: 3306
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
Master_UUID: 5e007fd8-afb0-11ea-93a9-000c29bfd16d
Master_Info_File: /var/lib/mysql/master.info
这样就实现了master->slave的同步环境。至此,主主双向同步环境已经实现!
(2)主主同步
1)在master上写入新数据
mysql> create database student;
Query OK, 1 row affected (0.03 sec)
mysql> use student;
Database changed
mysql> create table grade(id int);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into grade values(1),(2),(3);
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from grade;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
2)在slave数据库中查看
发现master新写入的数据已经同步过来了。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| student |
| sys |
+--------------------+
5 rows in set (0.06 sec)
mysql> use student;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> select * from grade;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
3) 在slave上删除数据
mysql> delete from grade where id=1;
Query OK, 1 row affected (0.35 sec)
4)在master数据库中查看
mysql> mysql> select * from grade;
+------+
| id |
+------+
| 2 |
| 3 |
+------+
2 rows in set (0.00 sec)
以上,主主同步实现。
五、Keepalived高可用
高可用:两台业务系统启动着相同的服务,如果有一台故障,另一台自动接管,我们将将这个称之为高可用。
1、Keepalived简介
keepalived是集群管理中保证集群高可用的一个软件解决方案,其功能类似于heartbeat,用来防止单点故障 keepalived是以VRRP协议为实现基础的,VRRP全称Virtual RouterRedundancy Protocol,即虚拟路由冗余协议。
2、Keepalived工作原理
虚拟路由冗余协议,可以认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组,这个组里面有一个master和多个backup,master上面有一个对外提供服务的vip,master会发组播(组播地址为224.0.0.18),当backup收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master。这样的话就可以保证路由器的高可用了。
3、Keepalived主要模块
keepalived主要有三个模块,分别是core 、check和vrrp。
(1)core模块为keepalived的核心,负责主进程的启动、维护以及全局配置文件的加载和解析。
(2)check负责健康检查,包括常见的各种检查方式。
(3)vrrp模块是来实现VRRP协议的。
4、keepalived的安装配置
(1)安装keepalived
在master1和master2上安装软件包keepalived,安装keepalived软件包与服务控制
在编译安装Keepalived之前,必须先安装内核开发包kernel-devel以及openssl-devel、popt-devel等支持库。
在两台master上进行如下操作:
1)下载Keepalived
[root@192 ~]# wget https://www.keepalived.org/software/keepalived-2.0.20.tar.gz
2)安装依赖库
[root@192 ~]# yum -y install kernel-devel openssl-devel popt-devel gcc
3)解压
[root@192 ~]# tar zxf keepalived-2.0.20.tar.gz
4)安装
[root@192 ~]# cd keepalived-2.0.20/
[root@192 keepalived-2.0.20]# ./configure --prefix=/ && make && make install
5)使用keepalived服务
systemctl enable keepalived
systemctl start keepalived
6)创建防火墙规则
若开启了防火墙,需要关闭防火墙或创建规则。
firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --reload
(2)修改Keepalived配置文件
1)配置区域
keepalived只有一个配置文件keepalived.conf,里面主要包括以下几个配置区域:
(1)global_defs:主要是配置故障发生时的通知对象以及机器标识。
(2)vrrp_instance:用来定义对外提供服务的VIP区域及其相关属性。
(3)virtual_server:虚拟服务器定义
2)配置说明
keepalived.conf文件配置内容如下:
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived //!表示注释
global_defs {
router_id MYSQL-1 //表示运行keepalived服务器的一个标识
}
vrrp_instance VI_1 {
# 指定keepalived的角色, 两台配置此处均是BACKUP,设为BACKUP将根据优先级决定主或从
state BACKUP
# 指定HA监测网络的接口
interface ens33
# 虚拟路由标识,这个标识是一个数字(取值在0-255之间,用来区分多个instance的VRRP组播),
# 同一个vrrp实例使用唯一的标识,确保和master2相同,同网内不同集群此项必须不同,否则发生冲突。
virtual_router_id 51
# 用来选举master的,要成为master,该项取值范围是1-255(在此范围之外会被识别成默认值100),
# 此处master2上设置为50
priority 100
# 发VRRP包的时间间隔,即多久进行一次master选举(可以认为是健康查检时间间隔)
advert_int 1
# 不抢占,即允许一个priority比较低的节点作为master,即使有priority更高的节点启动
nopreempt
# 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位)
authentication {
auth_type PASS
auth_pass 1111
}
# VIP区域,指定vip地址
virtual_ipaddress {
192.168.206.100
}
}
# 设置虚拟服务器,需要指定虚拟IP地址和服务端口,IP与端口之间用空格隔开
virtual_server 192.168.206.100 3306 {
# 设置运行情况检查时间,单位是秒
delay_loop 2
# 设置后端调度算法,这里设置为rr,即轮询算法
lb_algo rr
# 设置LVS实现负载均衡的机制,有NAT、TUN、DR三个模式可选
lb_kind DR
# 会话保持时间,单位是秒。
# 这个选项对动态网页是非常有用的,为集群系统中的session共享提供了一个很好的解决方案。
# 有了这个会话保持功能,用户的请求会被一直分发到某个服务节点,直到超过这个会话的保持时间。
persistence_timeout 60
# 指定转发协议类型,有TCP和UDP两种
protocol TCP
# 配置服务节点1,需要指定real server的真实IP地址和端口,IP与端口之间用空格隔开
# 注:master 2上此处改为192.168.206.130(即master2本机ip)
real_server 192.168.206.130 3306 {
# 配置服务节点的权值,权值大小用数字表示,数字越大,权值越高,
# 设置权值大小为了区分不同性能的服务器
weight 3
# 检测到realserver的mysql服务down后执行的脚本
notify_down /etc/keepalived/bin/mysql.sh
TCP_CHECK {
# 连接超时时间
connect_timeout 3
# 重连次数
nb_get_retry 3
# 重连间隔时间
delay_before_retry 3
# 健康检查端口
connect_port 3306
}
}
}
3)master1的配置
[root@master1 ~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id mysql-1
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.206.100
}
}
virtual_server 192.168.206.100 3306 {
delay_loop 6
lb_algo rr
lb_kind DR
persistence_timeout 60
protocol TCP
real_server 192.168.206.130 3306 {
weight 1
notify_down /etc/keepalived/bin/mysql.sh
TCP_CHECK {
connect_port 3306
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
[root@master1 ~]# systemctl start keepalived
4)master2的配置
将master1配置好的文件复制给master,稍加修改即可
[root@master1 ~]# scp /etc/keepalived/keepalived.conf root@192.168.206.131:/etc/keepalived/
[root@master2 ~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id mysql-2 # 此处需要修改
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 50 # 此处需要修改
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.206.100
}
}
virtual_server 192.168.206.100 3306 {
delay_loop 6
lb_algo rr
lb_kind DR
persistence_timeout 60
protocol TCP
real_server 192.168.206.131 3306 { # 修改为本机的ip
weight 1
notify_down /etc/keepalived/bin/mysql.sh
TCP_CHECK {
connect_port 3306
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
[root@master2 ~]# systemctl start keepalived
(3)编写检测脚本
在两台master上进行如下操作:
[root@master1 ~]# mkdir /etc/keepalived/bin
[root@master1 ~]# vim /etc/keepalived/bin/mysql.sh
#!/bin/bash
pkill keepalived
[root@master1 ~]# chmod +x /etc/keepalived/bin/mysql.sh
master1 和master2 上都添加此检测脚本,作用是当 mysql 停止工作时自动关闭本机的keepalived,从而实现将故障机器踢出(因每台机器上keepalived 只添加了本机为 realserver)。
当 mysqld 正常启动起来后,要手动启动 keepalived 服务。
(4)测试
1)测试一
在master1和master2分别执行ip addr show dev ens33命令查看master1和 master2对VIP(群集虚拟IP)的控制权。
master1主的查看结果:
master2主的查看结果:
从上图可以看出master1 是主服务器,master2 为备用服务器。
2)测试二
停止MySQL服务,看keepalived健康检查程序是否会触发我们编写的脚本。
停止master1主机的mysql服务
master1主的查看结果:
master2主的查看结果:
这说明在主服务上停止MySQL服务,触发了我们编写的脚本,进行自动故障切换。
3)MySQL 远程登录测试
我们找一台安装有MySQL 客户端,然后登录 VIP,看是否能登录。
在登录的两台 MySQL 服务器都要授权允许从远程登录。例如:
[root@master2 ~]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 83
Server version: 5.7.30-log MySQL Community Server (GPL)
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> set global validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_length=4;
Query OK, 0 rows affected (0.00 sec)
mysql> grant all on *.* to 'root'@'%' identified by '1234';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> exit
Bye
在客户端上测试登录
[root@master1 ~]# mysql -uroot -p -h 192.168.206.100 -P3306
mysql> show variables like 'server_id';
上图显示说明在客户端访问 VIP 地址,由 master1 主机提供响应的,因为 master1 当前是主服务器,将 master1 的 mysql 服务停止,在客户端执行 show variableslike‘server_id’;
[root@master1 ~]# systemctl stop mysqld
mysql> show variables like 'server_id';
上图显示说明在客户端的查询请求是由 master2 主机响应的,故障切换成功。
六、Keepalived使用总结
Keepalived+mysql双主一般来说,中小型规模的时候,采用这种架构是最省事的。 在master节点发生故障后,利用keepalived的高可用机制实现快速切换到备用节点。
在这个方案里,有几个需要注意的地方:
1、采用 keepalived 作为高可用方案时,两个节点最好都设置成 BACKUP模式,避免因为意外情况下(比如 脑裂)相互抢占导致往两个节点写入相同数据而引发冲突;
2、把两个节点的 auto_increment_increment(自增步长)和 auto_increment_offset(自增起始值)设成不同值。其目的是为了避免master 节点意外宕机时,可能会有部分 binlog 未能及时复制到slave上被应用,从而会导致slave新写入数据的自增值和原先master上冲突了,因此一开始就使其错开;当然了,如果有合适的容错机制能解决主从自增ID 冲突的话,也可以不这么做;
3、slave 节点服务器配置不要太差,否则更容易导致复制延迟。作为热备节点的 slave服务器,硬件配置不能低于 master 节点;
4、如果对延迟问题很敏感的话,可考虑使用 MariaDB 分支版本,或者直接上线 MySQL 5.7 最新版本,利用多线程复制的方式可以很大程度降低复制延迟。