• 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应用测试程序是否正常

  • 相关阅读:
    Android 下拉刷新之ScrollView--PullToRefreshScrollView
    Android 将Openfire中的MUC改造成类似QQ群一样的永久群
    Android多行文本折叠展开效果
    Android关于实现EditText中加多行下划线的的一种方法
    Android 官方下拉刷新组件SwipeRefreshLayout
    listview滑动顶部停靠(stickyListHeadersListView)
    Hadoop HBase概念学习系列之优秀行键设计(十六)
    Hadoop HBase概念学习系列之HBase里的长表VS宽表VS窄表(十五)
    Hadoop HBase概念学习系列之HBase里的客户端和HBase集群建立连接(详细)(十四)
    Hadoop HBase概念学习系列之HBase表的一些设置(强烈推荐好好领悟)(十三)
  • 原文地址:https://www.cnblogs.com/clllum/p/11791913.html
Copyright © 2020-2023  润新知