首页 > 代码库 > MySQL高可用之——keepalivd+互为主从

MySQL高可用之——keepalivd+互为主从

目标:配置一个keepalived双机热备架构,并配置主从复制


规划:
master1     zlm177     192.168.17.177
master2     zlm188     192.168.17.188
vip                             192.168.17.166


环境: Red Hat Enterprise Linux 6.4
            Percona Server 5.6.15


一、软件安装


可以去官网http://www.keepalived.org/software/下载最新版本的keepalived,目前最新的是1.2.13版,如下:
keepalived-1.2.13.tar


cp keepalived-1.2.13.tar /usr/local/src
cd /usr/local/src
tar zxvf keepalived-1.2.13.tar -C /opt/
cd /opt/keepalived-1.2.13
./configure --prefix=/usr/local/keepalived
make;makeinstall 或 make && makeinstall


注意,在编译过程中会提示缺少gcc和openssl包,用yum install装一下就可以了
RHEL6.4也可以配置CentOS的yum,具体方法这里就不讲了
yum install gcc
yum install openssl openssl-devel
还会提示xxx依赖包也需要安装,一并装上,用yum的好处就是安装方便,让系统自动判断需要哪些包,自动下载并安装,完成编译以后,软件安装就结束了


二、配置软件参数(VRRP)


装完软件后,默认会配置文件的路径为:
/usr/local/keepalived/etc/keepalived/keepalived.conf


在主端打开该配置文件,把原有内容清空,再添加以下内容:


! Configuration File for keepalived


global_defs { --全局配置
   notification_email {
     aaron8219@xxx.xxx --接收通知的邮箱
   }
   router_id aaron8219 --可以用字母,也可以使数字,可以一致,也可以不一致,只是一个标识
}


vrrp_instance my_177 {
    state BACKUP --BACKUP从端模式
    interface eth0
    virtual_router_id 88 --默认为51,取值范围在1~255的整数,主从两端必须一致,才表示是同一个组
    priority 90
    advert_int 1 --检查间隔,默认1s
    nopreempt --设置非抢占模式,
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress { --指定vip,
        192.168.17.166
    }
}


##关于vip的说明:vip随着state的变化而增加删除,当state为master的时候就添加,当state为backup的时候删除,主要是由优先级来决定的,和state设置的值没有多大关系(state相同的情况下),至于vip到底在主端还是从端,还和nopreempt有关,这里vip可以设置多个IP地址


##关于nopreempt的说明:只能设置在state为backup的节点上,且这个节点的优先级必须比另外的高


virtual_server 192.168.17.166 3306 { --虚拟服务器ip和端口
    delay_loop 2
    lb_algo wrr --带有权重的轮询
    lb_kind DR
    persistence_timeout 60
    protocol TCP


    real_server 192.168.17.177 3306 { --真实服务器ip和端口
        weight 3 --权重为3
        notify_down /opt/mysql/mysql.sh  --指定自杀脚本的路径
        TCP_CHECK {
            connect_timeout 10
            nb_get_retry 3
            delay_before_retry 3
            connect_port 3306
        }
    }
}


从端的配置文件大同小异,只要把IP和实例名改成自己的就可以了,并且设置从端的priority为90,而主端为100
有一点要注意的是,主从两端的state,都配置成了backup,因为使用了nopreempt,即非抢占模式


举个例子,当主端先启动mysql实例和keepalived后,如果此时从端也启动了mysql实例和keepalived,那么vip不会跳到从端上去,即使它的优先级为100,要大于主端的90
而如果不设置nopreempt,那么这个时候,又分2种情况:


1.state相同,即都是master或都是backup
优先级高的,会占有vip,和角色无关


2.state不同,即master->backup或backup->master
优先级高的,会占有vip,和角色无关


前提不同,结果都是一样的,即优先级是主导,谁的优先级高,vip就漂到谁那里


创建一个自杀脚本来判断mysql进程是否启动
touch /opt/mysql/mysql.sh
添加以下内容:
#!/bin.sh
pkill keepalived  --表示kill掉keepalived进程


三、运行测试


/usr/local/keepalived/sbin/keepalived -f /usr/local/keepalived/etc/keepalived/keepalived.conf -D


-f 指定keepalived的参数文件
-D 表示在操作系统日志里显示详细记录


判断keepalived进程是否正常启动,只要查看/var/log/messages里的日志就可以了
tail -30f /var/log/message
注意,如果没有启动mysql而先启动了keepalived,那么之前notify_down参数中指定的脚本就会被执行,表示没有找到mysql进程,把keeplied自己的进程给kill掉。


Jul 25 02:51:22 zlm188 Keepalived[3440]: Starting Keepalived v1.2.13 (07/22,2014)
Jul 25 02:51:22 zlm188 Keepalived[3441]: Starting Healthcheck child process, pid=3442
Jul 25 02:51:22 zlm188 Keepalived[3441]: Starting VRRP child process, pid=3443
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Netlink reflector reports IP 192.168.17.188 added
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Netlink reflector reports IP 192.168.17.188 added
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Netlink reflector reports IP fe80::a00:27ff:fe71:6b7b added
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Registering Kernel netlink reflector
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Netlink reflector reports IP fe80::a00:27ff:fe71:6b7b added
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Registering Kernel netlink command channel
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Registering Kernel netlink reflector
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Registering Kernel netlink command channel
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Registering gratuitous ARP shared channel
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Opening file ‘/usr/local/keepalived/etc/keepalived/keepalived.conf‘.
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Opening file ‘/usr/local/keepalived/etc/keepalived/keepalived.conf‘.
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Configuration is using : 11566 Bytes
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Configuration is using : 62964 Bytes
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: Using LinkWatch kernel netlink reflector...
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: VRRP_Instance(my_178) Entering BACKUP STATE
Jul 25 02:51:22 zlm188 Keepalived_vrrp[3443]: VRRP sockpool: [ifindex(2), proto(112), unicast(0), fd(10,11)]
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Using LinkWatch kernel netlink reflector...
Jul 25 02:51:22 zlm188 Keepalived_healthcheckers[3442]: Activating healthchecker for service [192.168.17.188]:3306
Jul 25 02:51:25 zlm188 Keepalived_healthcheckers[3442]: TCP connection to [192.168.17.188]:3306 failed !!!
Jul 25 02:51:25 zlm188 Keepalived_healthcheckers[3442]: Removing service [192.168.17.188]:3306 from VS [192.168.17.166]:3306
Jul 25 02:51:25 zlm188 Keepalived_healthcheckers[3442]: Executing [/opt/mysql/mysql.sh] for service [192.168.17.188]:3306 in VS [192.168.17.166]:3306
Jul 25 02:51:25 zlm188 Keepalived_healthcheckers[3442]: Lost quorum 1-0=1 > 0 for VS [192.168.17.166]:3306
Jul 25 02:51:25 zlm188 Keepalived[3441]: Stopping Keepalived v1.2.13 (07/22,2014)


在从端启动keepalived,跟踪日志文件可以发现,跑了一遍以后自动stopping了,这也说明,之前的配置是ok的了,否则就要检查一下,哪里配置有误,尤其要注意virtual_route_id必须保持一致,而route_id则不强行要求一致,实例名也不要重复


1.检验vip的情况
#ip address show或ip a show


2.用vip登录mysql数据库(前提是已开启了mysqld和keepalived进程)
#mysql -h192.168.17.166 -uaaron8219 -pzlm


3.关闭某一端网卡后,测试vip的去向,以及是否能通过vip正常登陆
#ifdown eth0
#ip a show
#mysql -h192.168.17.166 -uaaron8219 -pzlm


4.重启某一端(主机模拟主机故障),测试vip的去向,以及是否能通过vip正常登陆
#init 6
#ip a show
#mysql -h192.168.17.166 -uaaron8219 -pzlm


5.直接kill掉keepalived进程,测试vip的去向,以及是否能通过vip正常登陆
#pkill keepalived
#ip a show
#mysql -h192.168.17.166 -uaaron8219 -pzlm


四、配置数据库同步


安装完keepalived,只是保证了mysql数据库的高可用性,但是要真正做到互为主从,还需要配置MySQL主从复制模式,使数据库可以达到一致性状态


1.两端配置同步所需参数
确保server-id与slave不一致,通常server-id的格式可以设置成ip末尾2-3位+端口号
比如我的环境master的ip是192.168.17.177,端口是3306
那么server-id可以设置成1773306,相应地,slave就设置成1883306
以下参数都是在/etc/my.cnf文件中配置
server-id=1773306
log-bin=percona-bin --启用binlog
set-variable=binlog-ignore-db=mysql --不记录数据库mysql的更新日志,避免了Master上的权限设置等被同步到Slave上


2.两端添加复制用户
mysql> grant repliecation slave on *.* to ‘rep‘@‘192.168.17.%‘ identified by ‘rep‘;


如果想要在Slave上有权限执行 "LOAD TABLE FROM MASTER" 或 "LOAD DATA FROM MASTER" 语句的话,必须授予全局的 FILE 和 Select 权限:
mysql> GRANT FILE,Select,REPLICATION SLAVE ON *.* TO ‘rep‘@‘%‘ IDENTIFIED BY ‘rep‘;


3.设置同步
如果是新库,两边直接重置master的binlog
mysql> reset master;


(否则,需要把master的库用mysqldump导出(或直接打包压缩),再复制到从库主机,大致步骤如下:

①mysql> flush tables with read lock;



②mysql> mysqldump -uroot -p --all-databases -l -F >full_db.sql
scp full_db.sql root@192.168.17.188:/data/mysql/percona_3306/data

②cd /data/mysql/percona_3306
tar zcvf data.tar.gz ./data
scp data.tar.gz root@192.168.17.188


③mysql> unlock tables;
从库导入主库的数据库
mysql> mysql -uroot -p </data/mysql/percona_3306/data/full_db.sql

mysql> source /data/mysql/percona_3306/data/full_db.sql
)


4.主库查询日志状态
mysql> show master status\G


5.从库根据主库的binlog位置和position来执行同步

mysql> change master to master_host=‘192.168.17.177‘,master_user=‘rep‘,master_password=‘rep‘,

master_log_file=‘percona-bin.000001‘,master_log_pos=‘120‘;



6.启动slave
mysql> start slave;


启动后报错
Slave I/O: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work. Error_code: 1593


因为从库是直接通过虚拟机拷贝镜像的方式创建的,所以UUID重复了,UUID是存放在
/data/mysql/percona_3306/data/auto.cnf文件中的

可以把这个文件直接删除,或者编辑该文件,修改里面的UUID和主库不同即可,正常以后,应该是以下的状态:


(testing)root@localhost [(none)]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.17.177
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: percona-bin.000011
          Read_Master_Log_Pos: 540
               Relay_Log_File: node78-relay-bin.000018
                Relay_Log_Pos: 285
        Relay_Master_Log_File: percona-bin.000011
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 540
              Relay_Log_Space: 459
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 773306
                  Master_UUID: 917ecbfc-10dc-11e4-b624-080027267b03
             Master_Info_File: /data/mysql/percona_3306/data/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0


7.测试
主库测试数据库zlm的tb_zlm表中执行插入一行数据:


(testing)root@localhost [(none)]> select * from zlm.tb_zlm;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | aaron8219 |
|    2 | zlm       |
|    3 | abc       |
+------+-----------+
3 rows in set (0.00 sec)


(testing)root@localhost [(none)]> insert into zlm.tb_zlm values(4,‘def‘);
Query OK, 1 row affected (0.03 sec)


从库查询zlm.tb_zlm表:


(testing)root@localhost [(none)]> select * from zlm.tb_zlm;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | aaron8219 |
|    2 | zlm       |
|    3 | abc       |
|    4 | def       |
+------+-----------+
4 rows in set (0.00 sec)


从库上也进行同样的配置,即可完成互为主从,只要从相应的master的binlog的pos位置开始change maseter就可以了


结论:只要配置的VRRP组里面有一台机器开启了mysqld和keepalived进程,任何通过vip实现的数据库连接访问,都是正常的,这样无论是哪个节点down掉了,都不会影响mysql数据库的可用性,是一个最简单的mysql高可用架构。自此,通过keepalived来实现互为主从的双机热备架构就完成了,如果再复杂一点,安装lvpsadm来实现虚拟服务器的配置,那么就是一个经典的keepalived+lvs架构