zoukankan      html  css  js  c++  java
  • Mysql双主加Keepalived+读写分离

    一、MySQL于keepalived简介**

    前言:

    在企业中,数据库高可用一直是企业的重中之重,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要作改动。因此,如果是双主或者多主,就会增加mysql入口,增加高可用。不过多主需要考虑自增长ID问题,这个需要特别设置配置文件,比如双主,可以使用奇偶,总之,主之间设置自增长ID相互不冲突就能完美解决自增长ID冲突问题。

    1.1、MySQL**

    1.1.1、MySQL主从复制原理

    复制分成三步:

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

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

    3. slave重做中继日志中的事件,将改变反映它自己的数据。

    下图描述了这一过程:

     

     

     

    1.1.2、MySQL双主构建思路

    1.两台mysql都可读写,互为主备,默认只使用一台(masterA)负责数据的写入,另一台(masterB)备用;

    2.masterA是masterB的主库,masterB又是masterA的主库,它们互为主从;

    3.两台主库之间做高可用,可以采用keepalived等方案(使用VIP对外提供服务);

    4.所有提供服务的从服务器与masterB进行主从同步(双主多从);

    5.建议采用高可用策略的时候,masterA或masterB均不因宕机恢复后而抢占VIP(非抢占模式);

    这样做可以在一定程度上保证主库的高可用,在一台主库down掉之后,可以在极短的时间内切换到另一台主库上(尽可能减少主库宕机对业务造成的影响),减少了主从同步给线上主库带来的压力;

    但是也有几个不足的地方:

    1.masterB可能会一直处于空闲状态(可以用它当从库,负责部分查询);

    2.主库后面提供服务的从库要等masterB先同步完了数据后才能去masterB上去同步数据,这样可能会造成一定程度的同步延时;

    架构的简易图如下:

    1.1.3、MySQL双主和主从模式的区别

    主从是对主操作数据,从会实时同步数据。反之对从操作,主不会同步数据,还有可能造成数据紊乱,导致主从失效。 主主则是无论对那一台操作,另一个都会同步数据。一般用作高容灾方案

    1.2、Keepalived介绍**

    Keepalived是一个基于VRRP协议来实现的WEB 服务高可用方案,可以利用其来避免单点故障。一个WEB服务至少会有2台服务器运行Keepalived,一台为主服务器(MASTER),一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,主服务器会发送特定的消息给备份服务器,当备份服务器收不到这个消息的时候,即主服务器宕机的时候,备份服务器就会接管虚拟IP,继续提供服务,从而保证了高可用性。

    1.2.1、keepalived理论工作原理

    keepalived可提供vrrp以及health-check功能,可以只用它提供双机浮动的vip(vrrp虚拟路由功能),这样可以简单实现一个双机热备高可用功能。

    keepalived是一个类似于layer3, 4 & 5交换机制的软件,也就是我们平时说的第3层、第4层和第5层交换。Keepalived的作用是检测web 服务器的状态。 Layer3,4&5工作在IP/TCP协议栈的IP层,TCP层,及应用层,原理分别如下:

      Layer3:Keepalived使用Layer3的方式工作式时,Keepalived会定期向服务器群中的服务器

      发送一个ICMP的数据包(既我们平时用的Ping程序),如果发现某台服务的IP地址没有激活,Keepalived便报告这台服务器失效,并将它从服务器群中剔除,这种情况的典型例子是某台服务器被非法关机。Layer3的方式是以服务器的IP地址是否有效作为服务器工作正常与否的标准。在本文中将采用这种方式。

      Layer4:如果您理解了Layer3的方式,Layer4就容易了。Layer4主要以TCP端口的状态来决定服务器工作正常与否。如web server的服务端口一般是80,如果Keepalived检测到80端口没有启动,则Keepalived将把这台服务器从服务器群中剔除。

      Layer5:Layer5就是工作在具体的应用层了,比Layer3,Layer4要复杂一点,在网络上占用的带宽也要大一些。Keepalived将根据用户的设定检查服务器程序的运行是否正常,如果与用户的设定不相符,则Keepalived将把服务器从服务器群中剔除。

    vip即虚拟ip,是附在主机网卡上的,即对主机网卡进行虚拟,此IP仍然是占用了此网段的某个IP。

    1.2.2、keepalived高可用故障切换转移原理

    Keepalived高可用服务对之间的故障切换转移,是通过 VRRP (Virtual Router Redundancy Protocol ,虚拟路由器冗余协议)来实现的。

     

    核心:

      在 Keepalived服务正常工作时,主 Master节点会不断地向备节点发送(多播的方式)心跳消息,用以告诉备Backup节点自己还活看,当主 Master节点发生故障时,就无法发送心跳消息,备节点也就因此无法继续检测到来自主 Master节点的心跳了,于是调用自身的接管程序,接管主Master节点的 IP资源及服务。而当主 Master节点恢复时,备Backup节点又会释放主节点故障时自身接管的IP资源及服务,恢复到原来的备用角色。

    VRRP ,全 称 Virtual Router Redundancy Protocol ,中文名为虚拟路由冗余协议 ,VRRP的出现就是为了解决静态踣甶的单点故障问题,VRRP是通过一种竞选机制来将路由的任务交给某台VRRP路由器的。

    1.3、目的:

    解决mysql数据库Master-Slave 单点故障问题。

    1.3,1、实现方式:

    1. Master-Master Replication 实现数据同步。

    2.通过keepalived虚拟IP 从网络层实现单点故障时IP自动切换,从而实现高可用。

    3.通过keepalived配置实现read读指向Slave节点,实现读写分离。

     

    缺点:根据线上实际应用情况,只考虑单点网络故障及机器设备故障时虚拟ip自动切换(只切换一次)。不考虑mysql服务异常等情况,数据库异常可通过nagios等监控,防止多次来回切换,造成数据混乱!且故障节点恢复时,要人工操作及注意步骤。

     

    1.3.2、MySQL双主读写分离模式

    1、使用两个MySQL数据库db01,db02,互为Master和Slave,即:

    一边db01作为db02的master,一旦有数据写向db01时,db02定时从db01更新

    另一边db02也作为db01的master,一旦有数据写向db02时,db01也定时从db02获得更新

    (这不会导致循环,MySQL Slave默认不会记录Master同步过来的变化)

    2、但从AppServer的角度来说,同时只有一个结点db01扮演Master,另外一个结点db02扮演Slave,不能同时两个结点扮演Master。即AppSever总是把write操作分配某个数据库(db01),除非db01 failed,被切换。

    3、如果扮演Slave的数据库结点db02 Failed了:

    a)此时appServer要能够把所有的read,write分配给db01,read操作不再指向db02

    b)一旦db02恢复过来后,继续充当Slave角色,并告诉AppServer可以将read分配给它了.

    4、如果扮演Master的数据库结点db01 Failed了

    a)此时appServer要能够把所有的写操作从db01切换分配给db02,也就是切换Master由db02充当

    b)db01恢复过来后,充当Slave的角色,Master由db02继续扮演。

    测试环境:

    服务器:

    DB1:192.168.25.31、centos7.6、mysql5.7、keepalived、hostname:DB1

    DB2:192.168.25.32、centos7.6、mysql5.7、keepalived、hostname:DB2

    Slave1:192.168.25.34、cenots7.6、mysql5.7、hostname:slave

    VIP:192.168.25.200(虚拟)

    远程客户端:192.168.25.35(用来调用vip测试)

    步骤

     

    二:实现两台MySQL主主同步

    2.1、安装MySQL

    DB1、DB2两台服务器分别安装MySQL,这两台均已安装过程省略

    2.2、修改MySQL配置文件

    分别修改配置文件,在/etc/my.cnf文件中得[mysqld]段加配置信息

     DB1:
     
     [root@DB1 ~]# vim /etc/my.cnf
     
     server-id=1
     
     log-bin=mysql-bin
     
     relay-log=mysql-relay-bin
     
     replicate-wild-ignore-table=mysql.%
     
     replicate-wild-ignore-table=test.%
     
     replicate-wild-ignore-table=information_schema.%
     
     
     
     auto-increment-increment = 2
     
     auto-increment-offset = 1
     
     slave-skip-errors = all

    解释:

    server-id=1(节点标识,每台的server-id不能养,必须全局唯一)

    log-bin=mysql-bin(开启binlog日志,用于主从数据复制)

    relay-log=mysql-relay-bin(开启relay-log日志,relay-log日志记录的是从服务器I/O 线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后SQL线程会读取relay-log日志的内容并应用到从服务器)

    replicate-wild-ignore-table=mysql.%(复制过滤选项)

    auto-increment-increment = 2(字段一次递增多少)

    auto-increment-offset = 1(自增字段的起始值:1、3、5、7、等奇数)

    保存重启,使其配置生效

     [root@DB1 ~]# service mysqld restart
     
     Shutting down MySQL.. SUCCESS!
     
     Starting MySQL. SUCCESS!
     
     DB2:
     
     [root@DB2 ~]# vim /etc/my.cnf
     
     server-id=2
     
     log-bin=mysql-bin
     
     relay-log=mysql-relay-bin
     
     replicate-wild-ignore-table=mysql.%
     
     replicate-wild-ignore-table=test.%
     
     replicate-wild-ignore-table=information_schema.%
     
     
     
     auto-increment-increment = 2
     
     auto-increment-offset = 2
     
     slave-skip-errors = all
     
     保存重启,使其配置生效
     
     [root@DB2 ~]# service mysqld restart
     
     Shutting down MySQL.. SUCCESS!
     
     Starting MySQL. SUCCESS!
     
     Slave1:
     
     [root@slave1 ~]# vim /etc/my.cnf
     
     [mysqld]
     
     
     
     server-id=3
     
     log-bin=mysql-bin
     
     log-slave-updates
     
     relay-log=mysql-relay-bin
     
     replicate-wild-ignore-table=mysql.%
     
     replicate-wild-ignore-table=test.%
     
     replicate-wild-ignore-table=information_schema.%
     
     
     
     auto-increment-increment = 2
     
     auto-increment-offset = 3
     
     slave-skip-errors = all

     

    #注:在执行主主互备之前要保证两台服务器上MySQL数据一致

    2.3、MySQL配置DB1、DB2主主模式

    2.3.1、先查看log bin日志和pos位置

    DB1:

     [root@DB1 ~]# mysql -uroot -pwww.123
     
     mysql> show master status;

     

     DB2:
     
     [root@DB2 ~]# mysql -uroot -pwww.123
     
     mysql> show master status;

    2.3.2、DB1、DB2互相提升访问权限

     

    DB1:

    在DB1的数据库创建DB2的复制用户并授权

     mysql> grant replication slave on *.* to 'cproot'@'192.168.25.32' identified by 'cpwww.123';
     
     Query OK, 0 rows affected, 1 warning (0.02 sec)
     
     刷新并查看log bin日志和pos位置
     
     mysql> flush privileges;
     
     Query OK, 0 rows affected (0.02 sec)
     
     
     
     mysql> show master status;

    DB2:

     mysql> grant replication slave on *.* to 'cproot'@'192.168.25.31'identified by 'cpwww.123'; 
     
     Query OK, 0 rows affected, 1 warning (0.02 sec)
     
     mysql> flush privileges;
     
     Query OK, 0 rows affected (0.01 sec)
     
     mysql> show master status;

     

    在DB2的数据库中将DB1设置为自己得主服务器

     mysql> change master to master_host='192.168.25.31',master_user='cproot',master_password='cpwww.123',master_log_file='mysql-bin.000001',master_log_pos=613;
     
     Query OK, 0 rows affected, 2 warnings (0.11 sec)

     

    DB1:

    在DB1的数据库中将DB2设置为自己的主服务器

     mysql> change master to master_host='192.168.25.32',master_user='cproot',master_password='cpwww.123',master_log_file='mysql-bin.000001',master_log_pos=613;
     
     Query OK, 0 rows affected, 2 warnings (0.11 sec)

     

    分别查看DB1、DB2服务器状态

    DB2:

    mysql> start slave;
    Query OK, 0 rows affected (0.01 sec)
    mysql> show slave statusG;

    如果slave_io不是yes是  这样得话那就有三种可能错误需要排查

    1,网络不通

    2,密码不正确

    3,Pos不对

    4,防火墙没关

    我这次遇到的就是防火墙没关,并且用service iptables stop还不好使,我是这样解决的

    先看提示得错误

    提示用/bin/systemctl stop iptables.service这样得方式去关闭,这里需要先安装iptables.services然后在关闭防火墙

    [root@DB2 data]# yum -y install iptables-services
    
    [root@DB2 ~]# systemctl stop iptables
    

    DB1:

    mysql> start slave;
    Query OK, 0 rows affected (0.01 sec)
    mysql> show slave statusG;
    

     

    到此主主同步配置完成,查看状态slave_io和slave_sql都是yes说明主主同步成功

    2.4、测试主主同步

    在DB1上创建一个数据库one,然后在DB2上查看是否同步成功

    注意:在创建之前最好再次重启一下MySQL数据库不然可能会同步不成功

    DB1:
    
    mysql> create database one;
    
    Query OK, 1 row affected (0.02 sec)
    
     
    
    mysql> show databases;
    
    +--------------------+
    
    | Database           |
    
    +--------------------+
    
    | information_schema |
    
    | mysql              |
    
    | one                |
    
    | performance_schema |
    
    | sys                |
    
    +--------------------+
    
    5 rows in set (0.00 sec)
    

     

    DB2:

    mysql> show databases;
    
    +--------------------+
    
    | Database           |
    
    +--------------------+
    
    | information_schema |
    
    | mysql              |
    
    | one                |
    
    | performance_schema |
    
    | sys                |
    
    +--------------------+
    
    5 rows in set (0.00 sec)
    
    在DB2把新建的数据库one删除掉,看看DB1上是否还存在
    
    mysql> drop database one;
    
    Query OK, 0 rows affected (0.01 sec)
    
     
    
    mysql> show databases;
    
    +--------------------+
    
    | Database           |
    
    +--------------------+
    
    | information_schema |
    
    | mysql              |
    
    | performance_schema |
    
    | sys                |
    
    +--------------------+
    
    4 rows in set (0.00 sec)
    

    DB1:

    mysql> show databases;
    
    +--------------------+
    
    | Database           |
    
    +--------------------+
    
    | information_schema |
    
    | mysql              |
    
    | performance_schema |
    
    | sys                |
    
    +--------------------+
    
    4 rows in set (0.00 sec)
    
     
    

    双向操作没问题,都可以同步成功,主主已经搭建成功

    2.5、配置slave从服务器

    DB1

    在DB1的数据库创建slave1的复制用户并授权

    mysql> grant replication slave on *.* to 'cproot'@'192.168.25.34' identified by 'cpwww.123';
    
    Query OK, 0 rows affected, 1 warning (0.01 sec)
    
     
    
    mysql> flush privileges;
    
    Query OK, 0 rows affected (0.01 sec)
    
     
    
    mysql> show master status;

    在slave里的数据库里把DB1设置为主服务器

    Slave1:

    mysql> change master to master_host='192.168.25.31',master_user='cproot',master_password='cpwww.123',master_log_file='mysql-bin.000003',master_log_pos=774;
    
    Query OK, 0 rows affected, 2 warnings (0.05 sec)
    
    mysql> start slave;
    
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> show slave statusG

    查看状态slave_io和slave_sql都是yes,这里主从就同步成功了

    测试在DB1数据库新建two

    DB1:

    mysql> create database two;
    
    Query OK, 1 row affected (0.02 sec)
    
     
    
    mysql> show databases;

    Slave1:

    在slave1上查看是否同步

    主从同步成功

    同步错误问题总结:如果slave_io不是yes多看看防火墙是否关闭,还有就是授权是输入得账号密码和pos是否输入正确了

    三、安装并配置keepalived

    3.1、两台都需要安装keepalived

    DB1、DB2:

    安装keepalived并将其配置成系统服务。DB1和DB2都要进行如下操作:

    [root@DB1 ~]# yum install -y openssl-devel
    
    [root@DB1 ~]# cd /usr/local/src/
    
    [root@DB1 src]# wget http://www.keepalived.org/software/keepalived-1.3.5.tar.gz
    
    [root@DB1 src]# tar -zxvf keepalived-1.3.5.tar.gz 
    
    [root@DB1 src]# cd keepalived-1.3.5
    
    [root@DB1 keepalived-1.3.5]# ./configure --prefix=/usr/local/keepalived
    

    执行这个后会发现在最后会报错configure: error: libnfnetlink headers missing(没有的话忽略)

    然后执行

    [root@DB1 keepalived-1.3.5]# yum -y install libnfnetlink-devel
    
    再重新执行./configure
    
    [root@DB1 keepalived-1.3.5]# ./configure --prefix=/usr/local/keepalived
    
    [root@DB1 keepalived-1.3.5]# make && make install
    

    在执行这一条的时候如果遇到这样的错误可能是没有依赖包

     

    解决方法:

    [root@DB2 keepalived-1.3.5]# yum -y install libnl libnl-devel libnfnetlink-devel openssl-devel

    (最好是在安装之前全部执行这条语句以防发生错误)

    [root@DB1 keepalived-1.3.5]# cp /usr/local/src/keepalived-1.3.5/keepalived/etc/init.d/keepalived /etc/rc.d/init.d/
    
    [root@DB1 keepalived-1.3.5]# cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
    
    [root@DB1 keepalived-1.3.5]# mkdir /etc/keepalived/
    
    [root@DB1 keepalived-1.3.5]# cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
    
    [root@DB1 keepalived-1.3.5]# cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
    
    [root@DB1 keepalived-1.3.5]# echo "/etc/init.d/keepalived start" >>/etc/rc.local 
    

     

    3.2、DB1上的keepalived.conf配置

    DB1:

    [root@DB1 ~]# cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
    
    [root@DB1 ~]# vim /etc/keepalived/keepalived.conf
    
    ! Configuration File for keepalived
    
    ​       
    
    global_defs {
    
    notification_email {
    
    ops@wangshibo.cn
    
    tech@wangshibo.cn
    
    }
    
    ​       
    
    notification_email_from ops@wangshibo.cn
    
    smtp_server 127.0.0.1 
    
    smtp_connect_timeout 30
    
    router_id MASTER-HA
    
    }
    
    ​       
    
    vrrp_script chk_mysql_port {     #检测mysql服务是否在运行。有很多方式,比如进程,用脚本检测等等
    
    ​    script "/opt/chk_mysql.sh"   #这里通过脚本监测
    
    ​    interval 2                   #脚本执行间隔,每2s检测一次
    
    ​    weight -5                    #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5
    
    ​    fall 2                    #检测连续2次失败才算确定是真失败。会用weight减少优先级(1-255之间)
    
    ​    rise 1                    #检测1次成功就算成功。但不修改优先级
    
    }
    
    ​       
    
    vrrp_instance VI_1 {
    
    ​    state BACKUP 
    
    ​    interface ens160      #指定虚拟ip的网卡接口
    
    ​    mcast_src_ip 192.168.25.31
    
    ​    virtual_router_id 79    #路由器标识,MASTER和BACKUP必须是一致的
    
    ​    priority 100            #定义优先级,数字越大,优先级越高,在同一个vrrp_instance下,MASTER的优先级必须大于BACKUP的优先级。这样MASTER故障恢复后,就可以将VIP资源再次抢回来 
    
      #  nopreempt
    
    ​    advert_int 1         
    
    ​    authentication {   
    
    ​        auth_type PASS 
    
    ​        auth_pass 1111     
    
    ​    }
    
    ​    virtual_ipaddress {    
    
    ​        192.168.25.200
    
    ​    }
    
    ​      
    
    track_script {               
    
       chk_mysql_port             
    
    }
    
    }
    

    编写切换脚本。KeepAlived做心跳检测,如果Master的MySQL服务挂了(3306端口挂了),那么它就会选择自杀。Slave的KeepAlived通过心跳检测发现这个情况,就会将VIP的请求接管

    [root@DB1 ~]# vim /opt/chk_mysql.sh
    
    #!/bin/bash
    
    counter=$(netstat -na|grep "LISTEN"|grep "3306"|wc -l)
    
    if [ "${counter}" -eq 0 ]; then
    
    ​	/etc/init.d/keepalived stop
    
    fi
    
    [root@DB1 ~]# chmod 755 /opt/chk_mysql.sh 
    
    [root@DB1 ~]# /etc/init.d/keepalived start
    

    3.2、DB2上配置keepalived,DB2服务器上的keepalived.conf文件只修改priority为99、nopreempt不设置

    DB2:

    [root@DB2 ~]# cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
    
    [root@DB2 ~]# >/etc/keepalived/keepalived.conf
    
    [root@DB2 ~]# vim /etc/keepalived/keepalived.conf
    
    ! Configuration File for keepalived
    
    ​       
    
    global_defs {
    
    notification_email {
    
    ops@qq.com
    
    tech@qq.com
    
    }
    
    ​       
    
    notification_email_from ops@wangshibo.cn
    
    smtp_server 127.0.0.1 
    
    smtp_connect_timeout 30
    
    router_id MASTER-HA
    
    }
    
    ​       
    
    vrrp_script chk_mysql_port {
    
    ​    script "/opt/chk_mysql.sh"
    
    ​    interval 2            
    
    ​    weight -5                 
    
    ​    fall 2                 
    
    ​    rise 1               
    
    }
    
    ​       
    
    vrrp_instance VI_1 {
    
    ​    state BACKUP
    
    ​    interface ens160 
    
    ​    mcast_src_ip 192.168.25.32
    
    ​    virtual_router_id 79    
    
    ​    priority 99          
    
    ​    advert_int 1         
    
    ​    authentication {   
    
    ​        auth_type PASS 
    
    ​        auth_pass 1111     
    
    ​    }
    
    ​    virtual_ipaddress {    
    
    ​       192.168.25.200
    
    ​    }
    
    ​      
    
    track_script {               
    
       chk_mysql_port             
    
    }
    
    }
    
    [root@DB2 ~]# cat /opt/chk_mysql.sh 
    
    #!/bin/bash
    
    counter=$(netstat -na|grep "LISTEN"|grep "3306"|wc -l)
    
    if [ "${counter}" -eq 0 ]; then
    
    ​    /etc/init.d/keepalived stop
    
    fi
    
    [root@DB2 ~]# chmod 755 /opt/chk_mysql.sh 
    
    [root@DB2 ~]# /etc/init.d/keepalived start
    

    ####常用的指令说明

    (1)notification_email:收件箱

    (2)notification_email_from:发件箱

    (3)vrrp_mcast_group4:VRRP多播地址,必须为D类地址,即可用IP范围为224.0.0.0~239.255.255.255

    (4)script:自定义检查脚本路径

    (5)interval:自定义检查脚本的执行时间间隔,单位为秒

    (6)vrrp_instance:配置虚拟路由器实例

    (7)state:MASTER或BACKUP,当前节点在此虚拟路由器上的初始状态,只能有一个为MASTER,其余的都应该为BACKUP,此处都需要配置为BACKUP

    (8)nopreempt:定义工作模式为非抢占模式,默认为抢占模式

    (9)preempt_delay:抢占模式下,节点上线后触发新选举操作的延迟时长,单位为秒

    (10)interface:绑定当前虚拟路由器使用的物理接口

    (11)virtual_router_id:当前虚拟路由器的唯一标识,取值范围为0~255,两个节点必须一致

    (12)priority:当前主机在此虚拟路由器中的优先级,取值范围为0~255

    (13)advert_int:VRRP通告心跳信息和优先级信息的时间间隔,单位为秒

    (14)auth_type:认证类型

    (15)auth_pass:认证密码,两个节点必须一致

    (16)virtual_ipaddress:VIP地址

    (17)可通过命令# man keepalived.conf查看keepalived.conf配置文件的详细帮助文档

     

    现在查看一下vip在那一台机器,在DB1上是正确的

    在DB1下是正确的

    3.3、测试:

    首先先测试vip能不能正常切换

    在DB1上操作关闭MySQL,看看能不能飘移到DB2上,然后在启动能不能正常飘移到DB1上

    DB1:

    [root@DB1 ~]# /etc/init.d/mysqld stop
    
    [root@DB1 ~]# ip addr
    

    查看得知,关闭msyql后vip已经没了

    DB2:

    [root@DB2 ~]# ip addr
    

    此时VIP已经飘移到DB2上

    启动DB1的MySQL和keepalived

    注意:先启动MySQL在启动keepalived,因为脚本里MySQL没有启动的话keepalived启动后会再次关闭的

    DB1:

    [root@DB1 ~]# /etc/init.d/mysqld start
    
    Starting MySQL. SUCCESS! 
    
    [root@DB1 ~]# /etc/init.d/keepalived start
    
    Starting keepalived (via systemctl):                       [  确定  ]
    
    [root@DB1 ~]# ip addr
    

    此时VIP已经成功飘移回DB1上

    3.4、故障转移高可用测试

    首先在DB1和DB2上都要授权允许root用户远程登录,用于在客户端登录测试!

    并在两台机器上设置IPtables防火墙规则

    DB1:

    授权:
    
    [root@DB1 ~]# mysql -uroot -pwww.123
    
    mysql> grant all on *.* to root@'192.168.25.%' identified by "www.123";
    
    Query OK, 0 rows affected, 1 warning (0.02 sec)
    
     
    
    mysql> flush privileges;
    
    Query OK, 0 rows affected (0.01 sec)
    
    添加防火墙规则:
    
    [root@DB1 ~]# vim /etc/sysconfig/iptables
    
    -A INPUT -s 192.168.0.0/24 -d 224.0.0.18 -j ACCEPT       #允许组播地址通信
    
    -A INPUT -s 192.168.0.0/24 -p vrrp -j ACCEPT             #允许VRRP(虚拟路由器冗余协)通信
    
    -A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT    #开放mysql的3306端口
    
    [root@DB1 ~]# systemctl start iptables
    

    DB2:

    [root@DB2 ~]# mysql -uroot -pwww.123
    
    mysql>  grant all on *.* to root@'192.168.25.%' identified by "www.123";
    
    Query OK, 0 rows affected, 1 warning (0.01 sec)
    
     
    
    mysql> flush privileges;
    
    Query OK, 0 rows affected (0.01 sec)
    
    [root@DB2 ~]# vim /etc/sysconfig/iptables
    
    -A INPUT -s 192.168.0.0/24 -d 224.0.0.18 -j ACCEPT       #允许组播地址通信
    
    -A INPUT -s 192.168.0.0/24 -p vrrp -j ACCEPT             #允许VRRP(虚拟路由器冗余协)通信
    
    -A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT    #开放mysql的3306端口
    
    [root@DB2 ~]# systemctl start iptables
    
    注意:如果在启动防火墙报错(没有文件或目录时在防火墙规则里加一条
    
    “IPTABLES -P INPUT ACCEPT”然后保存退出会生成/etc/sysconfig/下的iptables配置文件:使用service iptables save之后再重新启动iptables就可以了)
    

    Monitor:

    通过MySQL客户端通过VIP连接,看是否可以连接成功。(连接是需要提前在服务器端授权的)

    [root@monitor ~]# mysql -h 192.168.25.200 -uroot -pwww.123

    创建一个数据库,然后在库中创建一个表,并插入数据。

    mysql> show variables like "%hostname%";      (这条语句可查看当前VIP在那台服务器上)

    mysql> show databases;

    mysql> create database one;
    
    Query OK, 1 row affected (0.01 sec)
    
     
    
    mysql> use one;
    
    Database changed
    
    mysql> create table test_table(id int, name varchar(32));
    
    Query OK, 0 rows affected (0.08 sec)
    
     
    
    mysql> show tables;
    
    +----------------+
    
    | Tables_in_one |
    
    +----------------+
    
    | one_table     |
    
    +----------------+
    
    1 row in set (0.00 sec)
    
    mysql> insert into one_table(id,name) values(1,'glt');
    
    Query OK, 1 row affected (0.02 sec)
    

    验证数据:

    分别查看DB1和DB2的数据同步情况

    DB1:

    [root@DB1 ~]# mysql -uroot -pwww.123
    
    mysql> show databases;
    
    +--------------------+
    
    | Database           |
    
    +--------------------+
    
    | information_schema |
    
    | mysql              |
    
    | performance_schema |
    
    | sys                |
    
    | one               |
    
    +--------------------+
    
    5 rows in set (0.00 sec)
    
    mysql> use one;
    
    Database changed
    
    mysql> show tables;
    
    +----------------+
    
    | Tables_in_one |
    
    +----------------+
    
    | one_table     |
    
    +----------------+
    
    1 row in set (0.00 sec)
    
    mysql> select * from one_table;
    
    +------+------+
    
    | id   | name |
    
    +------+------+
    
    |    1 | glt  |
    
    +------+------+
    
    1 row in set (0.00 sec)
    

     

    DB2:

    mysql> show databases;
    
    +--------------------+
    
    | Database           |
    
    +--------------------+
    
    | information_schema |
    
    | mysql              |
    
    | one                |
    
    | performance_schema |
    
    | sys                |
    
    +--------------------+
    
    5 rows in set (0.00 sec)
    
    mysql> use one
    
    Database changed
    
    mysql> show tables;
    
    +---------------+
    
    | Tables_in_one |
    
    +---------------+
    
    | one_table     |
    
    +---------------+
    
    1 row in set (0.00 sec)
    
     
    
    mysql> select * from one_table
    
    ​    -> ;
    
    +------+------+
    
    | id   | name |
    
    +------+------+
    
    |    1 | glt  |
    
    +------+------+
    
    1 row in set (0.00 sec)
    

     

    3.5故障测试:

    停止DB1中的MySQL,通过VIP登录查看当前的在那一台服务器上并继续在one库上插入数据,然后在重启DB1看是否可以同步数据。

    DB1:

    [root@DB1 ~]# service mysqld stop
    
    Shutting down MySQL............ SUCCESS!
    

    Monitor:

    [root@monitor ~]# mysql -h 192.168.25.200 -uroot -pwww.123
    
    mysql> show variables like "%hostname%";
    
    +---------------+-------+
    
    | Variable_name | Value |
    
    +---------------+-------+
    
    | hostname      | DB2   |
    
    +---------------+-------+
    
    1 row in set (0.00 sec)
    

    当前连接的是DB2,故障自动切换成功。

    mysql> use one;
    
    Database changed
    
    mysql> insert into one_table(id,name)values(2,'hhh');
    
    Query OK, 1 row affected (0.03 sec)
    
     
    
    mysql> select * from one_table;
    
    +------+------+
    
    | id   | name |
    
    +------+------+
    
    |    1 | glt  |
    
    |    2 | hhh  |
    
    +------+------+
    
    2 rows in set (0.00 sec)
    

    启动DB1查看同步情况

    DB1:

    [root@DB1 ~]# /etc/init.d/mysqld start
    
    Starting MySQL. SUCCESS! 
    
    [root@DB1 ~]# mysql -uroot -pwww.123
    
    mysql> show databases;
    
    +--------------------+
    
    | Database           |
    
    +--------------------+
    
    | information_schema |
    
    | mysql              |
    
    | one                |
    
    | performance_schema |
    
    | sys                |
    
    +--------------------+
    
    5 rows in set (0.00 sec)
    
    mysql> use one;
    
    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> show tables;
    
    +---------------+
    
    | Tables_in_one |
    
    +---------------+
    
    | one_table     |
    
    +---------------+
    
    1 row in set (0.00 sec)
    
     
    
    mysql> select * from one_table
    
    ​    -> ;
    
    +------+------+
    
    | id   | name |
    
    +------+------+
    
    |    1 | glt  |
    
    |    2 | hhh  |
    
    +------+------+
    
    2 rows in set (0.00 sec)
    

    数据同步成功

    到此,双机热备全部完成

    四、增加读写分离配置**

    在之前的基础上改动以下环境;如下:

    192.168.25.31 MySQL+keepalived

    192.168.25.32 MySQL+keepalived

    写入VIP:192.168.25.200(31主,32从)

    读取VIP:192.168.25.100(32主,31从)

    4.1、MySQL配置文件增加一条配置(两台都要做)

    [root@DB1 ~]# cp /etc/my.cnf /etc/my.cnf.bak
    
    [root@DB1 ~]# vim /etc/my.cnf
    
    binlog_format=mixed
    

     

    4.2、配置keepalived

    DB1:

    [root@DB1 ~]# cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak2
    
    [root@DB1 ~]# vim /etc/keepalived/keepalived.conf
    
    修改如下
    
    ! Configuration File for keepalived
    
    ​       
    
    global_defs {
    
    notification_email {
    
    ops@wangshibo.cn
    
    tech@wangshibo.cn
    
    }
    
    ​       
    
    notification_email_from ops@wangshibo.cn
    
    smtp_server 127.0.0.1 
    
    smtp_connect_timeout 30
    
    router_id MASTER-HA
    
    }
    
    ​       
    
    vrrp_script chk_mysql_port {     #检测mysql服务是否在运行。有很多方式,比如进程,用脚本检测等等
    
    ​    script "/opt/chk_mysql.sh"   #这里通过脚本监测
    
    ​    interval 2                   #脚本执行间隔,每2s检测一次
    
    ​    weight -5                    #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5
    
    ​    fall 2                    #检测连续2次失败才算确定是真失败。会用weight减少优先级(1-255之间)
    
    ​    rise 1                    #检测1次成功就算成功。但不修改优先级
    
    }
    
    ​       
    
    vrrp_instance VI_1 {
    
    ​    state BACKUP 
    
    ​    interface ens160      #指定虚拟ip的网卡接口
    
    ​    mcast_src_ip 192.168.25.31
    
    ​    virtual_router_id 79    #路由器标识,MASTER和BACKUP必须是一致的
    
    ​    priority 100            #定义优先级,数字越大,优先级越高,在同一个vrrp_instance下,MASTER的优先级必须大于BACKUP的优先级。这样MASTER故障恢复后,就可以将VIP资源再次抢回来 
    
    ​    nopreempt #不主动抢占资源,只有在优先级高的机器上设置即可,优先级低的机器不设置
    
    ​    advert_int 1         
    
    ​    authentication {   
    
    ​        auth_type PASS 
    
    ​        auth_pass 1111     
    
    ​    }
    
    ​    virtual_ipaddress {    
    
    ​        192.168.25.200  #写入虚拟VIP
    
    ​    }
    
    }
    
    ​      
    
    track_script {               
    
       chk_mysql_port             
    
    vrrp_instance VI_2{
    
    ​	state BACKUP #另一台配置为MASTER
    
    ​	interface ens160
    
    ​	virtual_router_id 44 #注意id和上面的不同(另一台和这个ID一样)
    
    ​	priority 90 #优先级,另一台为100
    
    ​	advert_int 1
    
    ​	authentication {
    
    ​	auth_type pass
    
    ​	auth_pass 1111
    
    ​	}
    
    ​	virtual_ipaddress {
    
    ​	192.168.25.100 #读取虚拟VIP
    
    ​	}
    
    }
    
    }

    DB2:

    ##注意:在此次的环境中不知道为什么DB2的keepalived必须要在/usr/local/keepalived/var/run/这个路径下把keepalived.pid文件放进去,不然启动不了,并且每启动一次这个文件就会消失一次,需要再次拷贝过去,原keepalived.pid文件在/run/keepalived.pid

    [root@DB2 ~]# cp /run/keepalived.pid /usr/local/keepalived/var/run/**
    
     
    
    [root@DB2 ~]# cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak2
    
    [root@DB2 ~]# vim /etc/keepalived/keepalived.conf
    
    ! Configuration File for keepalived
    
    ​       
    
    global_defs {
    
    notification_email {
    
    ops@qq.com
    
    tech@qq.com
    
    }
    
    ​       
    
    notification_email_from ops@wangshibo.cn
    
    smtp_server 127.0.0.1 
    
    smtp_connect_timeout 30
    
    router_id MASTER-HA
    
    }
    
    ​       
    
    vrrp_script chk_mysql_port {
    
    ​    script "/opt/chk_mysql.sh"
    
    ​    interval 2            
    
    ​    weight -5                 
    
    ​    fall 2                 
    
    ​    rise 1               
    
    }
    
    ​       
    
    vrrp_instance VI_1 {
    
    ​    state BACKUP #两台此处都是BACKUP
    
    ​    interface ens160 #网卡接口
    
    ​    #mcast_src_ip 192.168.25.32
    
    ​    virtual_router_id 79    
    
    ​    priority 90          
    
    ​    advert_int 1         
    
    ​    authentication {   
    
    ​        auth_type PASS 
    
    ​        auth_pass 1111     
    
    ​    }
    
    ​    virtual_ipaddress {    
    
    ​       192.168.25.200  #写入虚拟VIP
    
    ​    }
    
    ​      
    
    track_script {               
    
       chk_mysql_port             
    
    }
    
    }
    
    vrrp_instance VI_2{
    
    ​	state MASTER #用于MySQL读
    
    ​	interface ens160 #网卡接口
    
    ​	virtual_router_id 44 #注意id和上面的不同(另一台和这个ID一样)
    
    ​	priority 100 #优先级,另一台为90
    
    ​	advert_int 1
    
    ​	authentication {
    
    ​	auth_type pass
    
    ​	auth_pass 1111
    
    ​	}
    
    ​	virtual_ipaddress {
    
    ​	192.168.25.100 #读取虚拟VIP
    
    ​	}
    
    }
    
    }

    4.3、查看当前ip是否做成了读写分离

    DB1和DB2重启keepalived查看此时的虚拟ip

    DB1:

    [root@DB1 ~]# ip addr
    
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    
    ​    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    
    ​    inet 127.0.0.1/8 scope host lo
    
    ​       valid_lft forever preferred_lft forever
    
    ​    inet6 ::1/128 scope host 
    
    ​       valid_lft forever preferred_lft forever
    
    2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    
    ​    link/ether 00:50:56:9d:45:0a brd ff:ff:ff:ff:ff:ff
    
    ​    inet 192.168.25.31/24 brd 192.168.25.255 scope global noprefixroute ens160
    
    ​       valid_lft forever preferred_lft forever
    
    ​    inet 192.168.25.200/32 scope global ens160
    
    ​       valid_lft forever preferred_lft forever
    
    ​    inet6 fe80::779a:c241:de68:1ca8/64 scope link noprefixroute 
    
    ​       valid_lft forever preferred_lft forever
    
    DB1的虚拟ip是写入ip没问题
    

     

    DB2:

    [root@DB2 ~]# ip addr
    
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    
    ​    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    
    ​    inet 127.0.0.1/8 scope host lo
    
    ​       valid_lft forever preferred_lft forever
    
    ​    inet6 ::1/128 scope host 
    
    ​       valid_lft forever preferred_lft forever
    
    2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    
    ​    link/ether 00:50:56:9d:54:61 brd ff:ff:ff:ff:ff:ff
    
    ​    inet 192.168.25.32/24 brd 192.168.25.255 scope global noprefixroute ens160
    
    ​       valid_lft forever preferred_lft forever
    
    ​    inet 192.168.25.100/32 scope global ens160
    
    ​       valid_lft forever preferred_lft forever
    
    ​    inet6 fe80::5a60:abe2:4734:487e/64 scope link noprefixroute 
    
    ​       valid_lft forever preferred_lft forever
    

    此时DB2的虚拟ip是读取ip没得问题

    4.4、故障处理 (测试)

    故障一:31(写)服务器或者网络故障,虚拟ip 200切换到32

     

    1、 31服务器恢复后,不要插上网线或者修改31的iP(防止数据自动同步,导致数据污染)

    2、 暂时关闭keepalive(默认开机不启动)

    3、 启动31的mysql并停掉slave,防止32数据同步到31,同时插上网线或者修改iP为31;

    4、 检查32的slave状态是有主键冲突,如果有主键冲突,导出31上的数据,并做删除;

    5、 重启32的slave,查看是否还有主键冲突,如果有继续上步操作,直到32的slave状态恢复正常;

    6、 开启31的slave并查看slave状态,正常情况下应该不会出现主键冲突,如果有主键冲突,导出数据并分析原因,(根据实际情况处理)

    7、 检查31与32服务器数据是否一致,如果数据一致,切换VIP 100(读虚拟IP)到31,修改步骤如下:

    a)修改32的keepalive配置vrrp_instance VI_2 中state状态为BACKUP、priority 修改为90

    b)重启32 keepalive(确保31的keepalive是关闭状态)

    c)修改31的keepalive配置vrrp_instance VI_2 中state状态为MASTER、priority 修改为180

    d)重启31的keepalive

    e)检查VIP 100(读虚拟IP)是否切到31上,并且VIP 200(写虚拟IP)应该保留在32上。

    8、 线上应用测试(读与写)

     

    故障修复后的状态应该是:

    1.192.168.25.31 mysql+keepalive

    2.192.168.25.32 mysql+keepalive

    3.写入VIP:192.168.25.200(32主,31从)

    4.读取VIP:192.168.25.100(31主,32从)

     

    故障二、32(读)数据库出现故障,VIP 100(读虚拟IP)切到31服务器

    1、修复32服务器之前应断开网线或者修改ip(防止读VIP自动切回)

    2、关闭keepalive 所以服务器上的keepalive 最好设计成开不会自动启动命令如下:chkconfig keepalived off

    3、检查32数据库的slave状态是否正常,数据库数据同步是否正常

    4、数据同步完成后启动keepalive,检查读取数据的虚拟IP 100应该切回本服务器,写数据的虚拟IP不变。

    5、应用测试读写数据是否正常

     

    故障三、两台数据库服务器同时故障

    1、 开启31和32数据库之前,先断网线

    2、 分别检查31和32服务器的mysql更新的最新时间

    3、 如果31数据比较新,先插上31的网线,使其对外提供服务。

    3.1检查读和写的虚拟iP是否都在31上

    3.2关闭32上的keepalive,并且开启32上msyql的salve,同步31上的数据

    3.3如果同步正常启动keepalive

    3.4测试读写数据是否正常

    4、如果32的数据比较新,就先插上32的网线,使其对外提供服务

    4.1 检查读和写的虚拟ip是否都在32上

    4.2 关闭31上的keepalive,并且开启31上mysql的save,开始同步32上的数据

    4.3如果同步正常,启动31的keepalive

    4.4测试读写数据是否正常

    4.5应用测试程序是否正常

  • 相关阅读:
    tuple 元组及字典dict
    day 49 css属性补充浮动 属性定位 抽屉作业
    day48 选择器(基本、层级 、属性) css属性
    day47 列表 表单 css初识
    day 46 http和html
    day 45索引
    day 44 练习题讲解 多表查询
    day 40 多表查询 子查询
    day39 表之间的关联关系、 补充 表操作总结 where 、group by、
    day38 数据类型 约束条件
  • 原文地址:https://www.cnblogs.com/clllum/p/11791913.html
Copyright © 2011-2022 走看看