keepalived+双主实践HA

    工做不怎么忙,搞点儿开发吧差点儿事,就想着弄点儿架构的事儿。正好前段时间看过关于keepalived+双主实现高可用的文章,也刚好身边的朋友所在的公司也部分用这个架构。没什么事儿就搞搞吧,正好对比下MMM、MHA、keepalived+双主三种架构的优劣和DB维护的体验感。简单讲讲本身的用户体验感,就搭建难易程度讲MMM的安装包封装好的,修改的配置文件较MHA少一些,比keepalived+双主要稍微麻烦点儿。本着省事,维护起来省事仍是以为MMM真的便利,黑盒操做适合我这种懒人加小白类型。mysql

    某位大佬讲过,若是你的公司还在用MMM和MHA,那么你能够考虑跳槽了。我以为这句话颇有道理,其实并非让咱们真的去跳槽,毕竟每一个人工做的目的,环境不同,有些架构上的事儿咱们决定不了。无法随性而行,但不能中止探索的脚步,本过程从搭建调研/搭建过程/搭建测试/搭建总结四个方面讲述我对双主+keepalived的理解和用户体验感。程序员

 

1、搭建调研sql

    传统的高可用架构如MHA、MMM存在一些不成熟的问题,如脑裂。引入keepalived和双主复制模式,实现高可用架构,但keepalived自己是在机器宕机时才会实现漂移功能,咱们的目标是要MySQL实例宕机后要实现故障切换,还须要辅助的脚原本帮助keepalived来实现更灵活的漂移。shell

keepalived简介数据库

    keepalived是集群管理中保证集群高可用的一个软件解决方案,其功能相似于heartbeat,用来防止单点故障,这里的做用我理解其实就是保证VIP的顺利漂移。虚拟路由冗余协议,能够认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组,这个组里面有一个master和多个backup,master上面有一个对外提供服务的vip,master会发组播(组播地址为224.0.0.18),当backup收不到vrrp包时就认为master宕掉了,这时就须要根据VRRP的优先级来选举一个backup当master,这样的话就能够保证路由器的高可用了。bash

keepalived配置说明服务器

    keepalived只有一个配置文件keepalived.conf,里面主要包括如下几个配置区域,分别是global_defs、vrrp_instance和virtual_server。多线程

  • global_defs:主要是配置故障发生时的通知对象以及机器标识;
  • vrrp_instance:用来定义对外提供服务的VIP区域及其相关属性;
  • virtual_server:虚拟服务器定义。

 

2、搭建过程架构

搭建环境(服务器配置忽略)并发

  master1:172.16.3.190/22 3309 VIP:172.16.3.123/22

  master2:172.16.3.189/22 3309
 
一、搭建双主复制集(忽略)
二、master1和master2上安装keepalived服务,并修改配置文件,以下配置
 1 #master1配置keepalived
 2 yum install keepalived.x86_64 
 3 [root@172-16-3-190 we_ops_admin]# cat /etc/keepalived/keepalived.conf 
 4 ! Configuration File for keepalived
 5 
 6 global_defs {
 7    router_id lvs_master1
 8 }
 9 
10 vrrp_instance VI_1 {
11     state BACKUP
12     interface eth0
13     virtual_router_id 172
14     priority 100
15     advert_int 1
16     nopreempt
17     authentication {
18         auth_type PASS
19         auth_pass 1111
20     }
21     virtual_ipaddress {
22         172.16.3.123/22
23     }
24 }
25 
26 virtual_server 172.16.3.123 3309 {
27     delay_loop 6
28     lb_algo rr
29     lb_kind NAT
30     nat_mask 255.255.255.0
31     persistence_timeout 50
32     protocol TCP
33 
34     real_server 172.16.3.190 3309 {
35         weight 3
36         notify_down /opt/shells/keepalived_mysql.sh
37         TCP_CHECK {
38             connect_timeout 3
39             nb_get_retry 3
40             delay_before_retry 3
41             connect_port 3309
42        }
43     }
44 }
45 
46 #master2上安装keepalived
47 yum install keepalived.x86_64 
48 [root@172-16-3-189 we_ops_admin]# cat /etc/keepalived/keepalived.conf 
49 ! Configuration File for keepalived
50 
51 global_defs {
52    router_id lvs_master2
53 }
54 
55 vrrp_instance VI_1 {
56     state BACKUP
57     interface eth0
58     virtual_router_id 172
59     priority 50
60     advert_int 1
61 # nopreempt
62     authentication {
63         auth_type PASS
64         auth_pass 1111
65     }
66     virtual_ipaddress {
67         172.16.3.123/22
68     }
69 }
70 
71 virtual_server 172.16.3.123 3309 {
72     delay_loop 6
73     lb_algo rr
74     lb_kind NAT
75     nat_mask 255.255.255.0
76     persistence_timeout 50
77     protocol TCP
78 
79     real_server 172.16.3.189 3309 {
80         weight 3
81         notify_down /opt/shells/keepalived_mysql.sh
82         TCP_CHECK {
83             connect_timeout 3
84             nb_get_retry 3
85             delay_before_retry 3
86             connect_port 3309
87        }
88     }
89 }

  上述配置中咱们能够保证keepalived服务对VIP:172.16.3.123/22的控制权,默认是keepalived服务关闭,那么会触发VIP的漂移。正常运行的服务不会发生异常中止的现象,若是系统发生宕机会触发全部的服务中止,这里系统宕机是触发VIP漂移的导火索。只是这里咱们想让keepalived服务于MySQL复制集,那么这里的导火索天然而然是MySQL服务的状态。若是服务状态不可用,那么咱们但愿这个应用VIP能够漂移到复制集的另外一台机器上;若是服务状态可用,咱们但愿VIP不要漂移。要想实现这个目的,咱们还须要一个服务脚原本帮助咱们去帮助keepalived发现MySQL服务宕机后的动做,脚本以下配置。

1 [root@172-16-3-190 we_ops_admin]# cat /opt/shells/keepalived_mysql.sh 
2 #!/bin/bash
3 pkill keepalived
4 /sbin/ifdown eth0 && /sbin/ifup eth0
5 #授予可执行权限
6 [root@172-16-3-190 we_ops_admin]# ls -lh /opt/shells/keepalived_mysql.sh 
7 -rwxr-xr-x 1 root root 66 Sep 27 19:29 /opt/shells/keepalived_mysql.sh

  经过步骤1·2的配置,启动MySQL服务,启动keepalived服务,这里的master1和master2基本就能够实现高可用,保证了master1服务不可用时,master2还能继续提供数据库的支持。

 

3、搭建测试(Bash脚本模拟高并发)

一、master1的MySQL服务宕机,VIP会从master1上摘除漂移落盘到master2上,且master1上的keepalived服务也会中止。应用链接VIP,master2继续为整个集群提供数据库支持。

 1 #中止master1上的MySQL服务
 2 [root@172-16-3-190 we_ops_admin]# /etc/init.d/mysql_3309 stop
 3 Shutting down MySQL (Percona Server).. SUCCESS! 
 4 
 5 #keepalived服务也中止了,且VIP已经被从master1上摘除
 6 [root@172-16-3-190 we_ops_admin]# /etc/init.d/keepalived status
 7 keepalived dead but subsys locked
 8 [root@172-16-3-190 we_ops_admin]# ip add
 9 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
10     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
11     inet 127.0.0.1/8 scope host lo
12     inet6 ::1/128 scope host 
13        valid_lft forever preferred_lft forever
14 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
15     link/ether 52:54:00:f4:ec:b2 brd ff:ff:ff:ff:ff:ff
16     inet 172.16.3.190/22 brd 172.16.3.255 scope global eth0
17     inet6 fe80::5054:ff:fef4:ecb2/64 scope link 
18        valid_lft forever preferred_lft forever
19 #VIP漂移到master2上
20 [root@172-16-3-189 we_ops_admin]# ip add
21 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
22     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
23     inet 127.0.0.1/8 scope host lo
24     inet6 ::1/128 scope host 
25        valid_lft forever preferred_lft forever
26 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
27     link/ether 52:54:00:2d:96:5c brd ff:ff:ff:ff:ff:ff
28     inet 172.16.3.189/22 brd 172.16.3.255 scope global eth0
29     inet 172.16.3.123/22 scope global secondary eth0
30     inet6 fe80::5054:ff:fe2d:965c/64 scope link 
31        valid_lft forever preferred_lft forever

二、master1从新加入集群,VIP不会从新漂移回来,形成二次波动或者脑裂现象

 1 #重启master1上的MySQL服务
 2 [root@172-16-3-190 we_ops_admin]# /etc/init.d/mysql_3309 start
 3 Starting MySQL (Percona Server)............... SUCCESS! 
 4 #重启master1上的keepalived服务
 5 [root@172-16-3-190 we_ops_admin]# /etc/init.d/keepalived start
 6 Starting keepalived: [ OK ]
 7 #VIP仍是在master2上,且master1上并无VIP,由于master1上设置非抢占模式,即便优先级更高
 8 [root@172-16-3-190 we_ops_admin]# ip add  #master1
 9 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
10     link/ether 52:54:00:f4:ec:b2 brd ff:ff:ff:ff:ff:ff
11     inet 172.16.3.190/22 brd 172.16.3.255 scope global eth0
12     inet6 fe80::5054:ff:fef4:ecb2/64 scope link 
13        valid_lft forever preferred_lft forever
14 
15 [root@172-16-3-189 we_ops_admin]# ip add  master2
16 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
17     link/ether 52:54:00:2d:96:5c brd ff:ff:ff:ff:ff:ff
18     inet 172.16.3.189/22 brd 172.16.3.255 scope global eth0
19     inet 172.16.3.123/22 scope global secondary eth0
20     inet6 fe80::5054:ff:fe2d:965c/64 scope link 
21        valid_lft forever preferred_lft forever
三、master2服务宕机(若是想让VIP从新漂移回master1上,通常状况下生成环境不容许也不建议进行二次切换)
 1 #关闭master2实例
 2 [root@172-16-3-189 we_ops_admin]# /etc/init.d/mysql_3309 stop
 3 Shutting down MySQL (Percona Server).. SUCCESS! 
 4 [root@172-16-3-189 we_ops_admin]# /etc/init.d/keepalived status
 5 keepalived dead but subsys locked
 6 #VIP已经从master2上飘走了
 7 [root@172-16-3-189 we_ops_admin]# ip add
 8 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
 9     link/ether 52:54:00:2d:96:5c brd ff:ff:ff:ff:ff:ff
10     inet 172.16.3.189/22 brd 172.16.3.255 scope global eth0
11     inet6 fe80::5054:ff:fe2d:965c/64 scope link 
12        valid_lft forever preferred_lft forever
13 
14 #VIP已经落盘到master1上
15 [root@172-16-3-190 we_ops_admin]# ip add
16 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
17     link/ether 52:54:00:f4:ec:b2 brd ff:ff:ff:ff:ff:ff
18     inet 172.16.3.190/22 brd 172.16.3.255 scope global eth0
19     inet 172.16.3.123/22 scope global secondary eth0
20     inet6 fe80::5054:ff:fef4:ecb2/64 scope link 
21        valid_lft forever preferred_lft forever
22 #server-id能够证实链接到master1实例
23 [root@172-16-3-190 we_ops_admin]# /opt/app/mysql_3309/bin/mysql -urepl -prepl --socket=/opt/app/mysql_3309/tmp/mysql.sock --port=3309 --host=172.16.3.123
24 Warning: Using a password on the command line interface can be insecure.
25 Welcome to the MySQL monitor.  Commands end with ; or \g.
26 Your MySQL connection id is 33
27 Server version: 5.6.20-68.0-log Percona Server (GPL), Release 68.0, Revision 656
28 
29 Copyright (c) 2009-2014 Percona LLC and/or its affiliates
30 Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
31 
32 Oracle is a registered trademark of Oracle Corporation and/or its
33 affiliates. Other names may be trademarks of their respective
34 owners.
35 
36 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
37 
38 mysql> show global variables like '%server_id%';
39 +----------------+---------+
40 | Variable_name  | Value   |
41 +----------------+---------+
42 | server_id      | 1903309 |
43 | server_id_bits | 32      |
44 +----------------+---------+
45 2 rows in set (0.01 sec)
    上述三个测试操做,实践了VIP从master1到master2,最后再从新漂移回master1。这个切换过程当中没有任何的其余问题,说明keepalived+双主的MySQL架构的健壮性仍是比较强大的,且实现了服务的高可用。
    经过一系列的测试发现,在切换过程当中也存在相似与MMM和MHA的一个短暂的10s丢失数据库链接的错误,这个VIP的漂移过程当中都会出现一些链接没法正常链接到应用数据库,出现一些数据丢失,影响业务的现象出现。但这个时间很短,通常对业务数据的影响不会太大,这里我模拟的是高并发,不停的向数据库写入表数据。
1 Warning: Using a password on the command line interface can be insecure. #这个错误这里测试大概会报10条
2 Warning: Using a password on the command line interface can be insecure.
3 ERROR 2003 (HY000): Can't connect to MySQL server on '172.16.3.123' (111)
4 Warning: Using a password on the command line interface can be insecure.
5 ERROR 2003 (HY000): Can't connect to MySQL server on '172.16.3.123' (111)

 

4、搭建总结
    本次测试是想换一种架构,寻找一种捷径解决MHA脑裂的问题,一般状况下,上联交换机的波动容易形成集群中主与备主对VIP的争抢,形成应均可以链接两个数据库实例的现象发生。MHA对于VIP的漂移是通过两个步骤来完成,一个是对VIP的摘除,另外一个是VIP的落盘,即一般意义的VIP删除,另外一个机器上添加VIP。但很遗憾的是本次测试并无解决或者替代VIP脑裂的现象,反而也容易出现脑裂这个问题,由于自己keepalived对于VIP的管理也是通过了两个步骤,即VIP的删除和添加,这两个步骤是分开的,若是不加以对其中一台机器锁定,就很容易出现脑裂的现象。
    可是值得庆幸的是,即便发生了VIP的脑裂,两台机器上都有VIP,可是应用链接的只是其中一台机器,写入也是其中一台,所以并非真正意义上的脑裂。这种状况在反复中止MySQL实例,VIP来回漂移时会出现,咱们能够手动删除没有真正意义落盘的那台机器上的VIP。
 
上述配置存在的问题
一、脑裂(VIP的脑裂,这里并非真正意义上的脑裂,能够根据server_id来判断应用只是链接了其中一台机器)
  因为master1设置了不抢占VIP,master2注释了不抢占VIP模式。master1宕机从新加入集群后不会抢夺VIP,可是master2宕机后从新加入集群后会抢占VIP,此时VIP会出如今master1和master2上。
  经过innotop工具实时并不能抓到应用链接,但经过表的数据增加判断应用链接到master1上,而master2的数据没有增加(同步中止,已经被迫中断了)。即其实此时的脑裂并非双写,而是写到了mater1上。
#VIP在master2上,master1从新加入集群,准备将VIP从master2上切回master1
[root@172-16-3-189 we_ops_admin]#/etc/init.d/mysql_3309 stop #master1上中止实例
Shutting down MySQL (Percona Server).. SUCCESS!
[root@172-16-3-189 we_ops_admin]#/etc/init.d/keepalived status
keepalived dead but subsys locked
[root@172-16-3-189 we_ops_admin]#ip add   #vip竟然还在master2上
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
    link/ether 52:54:00:2d:96:5c brd ff:ff:ff:ff:ff:ff
    inet 172.16.3.189/22 brd 172.16.3.255 scope global eth0
    inet 172.16.3.123/22 scope global secondary eth0
    inet6 fe80::5054:ff:fe2d:965c/64 scope link
       valid_lft forever preferred_lft forever
[root@172-16-3-190 we_ops_admin]#ip add #VIP也漂移到master1上,应用链接到master1上写
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc htb state UP qlen 1000
    link/ether 52:54:00:f4:ec:b2 brd ff:ff:ff:ff:ff:ff
    inet 172.16.3.190/22 brd 172.16.3.255 scope global eth0
    inet 172.16.3.123/22 scope global secondary eth0
    inet6 fe80::5054:ff:fef4:ecb2/64 scope link
       valid_lft forever preferred_lft forever
      
#master2上有VIP,但应用没有链接到master2上且表的行数不增加
mysql> select max(id) from test_keepalived;
+---------+
| max(id) |
+---------+
|     168 |
+---------+
1 row in set (0.00 sec)
mysql> select max(id) from test_keepalived;
+---------+
| max(id) |
+---------+
|     168 |
+---------+
1 row in set (0.00 sec)
#VIP也在master1上应用链接到master1且表行数在增加
mysql> select max(id) from test_keepalived;
+---------+
| max(id) |
+---------+
|     387 |
+---------+
1 row in set (0.00 sec)
mysql> select max(id) from test_keepalived;
+---------+
| max(id) |
+---------+
|     388 |
+---------+
1 row in set (0.00 sec)

二、master2同步被中断的问题,没有等待同步完成的机制。(VIP在maste2上时,由于master2上已经写入了数据但没来得及同步到master1上;master2实例中止后,VIP也漂移到master1,应用链接master1进行写入,但由于表设计为主键自增加,会出现ID为25已写入master2而没有同步到master1,应用链接master1写入到数据库同步到master2时报主键重复)

 1 mysql> show slave status \G;
 2 *************************** 1. row ***************************
 3                Slave_IO_State: Waiting for master to send event
 4                   Master_Host: 172.16.3.190
 5                   Master_User: repl
 6                   Master_Port: 3309
 7                 Connect_Retry: 30
 8               Master_Log_File: binlog.000036
 9           Read_Master_Log_Pos: 103620
10                Relay_Log_File: relay_bin.000038
11                 Relay_Log_Pos: 280
12         Relay_Master_Log_File: binlog.000036
13              Slave_IO_Running: Yes
14             Slave_SQL_Running: No
15               Replicate_Do_DB: 
16           Replicate_Ignore_DB: 
17            Replicate_Do_Table: 
18        Replicate_Ignore_Table: 
19       Replicate_Wild_Do_Table: 
20   Replicate_Wild_Ignore_Table: 
21                    Last_Errno: 1062
22                    Last_Error: Error 'Duplicate entry '25' for key 'PRIMARY'' on query. Default database: 'practice'. Query: 'insert into test_keepalived values(null,1,4)'
23                  Skip_Counter: 0
24           Exec_Master_Log_Pos: 120
25               Relay_Log_Space: 104434
26               Until_Condition: None
27                Until_Log_File: 
28                 Until_Log_Pos: 0
29            Master_SSL_Allowed: No
30            Master_SSL_CA_File: 
31            Master_SSL_CA_Path: 
32               Master_SSL_Cert: 
33             Master_SSL_Cipher: 
34                Master_SSL_Key: 
35         Seconds_Behind_Master: NULL
36 Master_SSL_Verify_Server_Cert: No
37                 Last_IO_Errno: 0
38                 Last_IO_Error: 
39                Last_SQL_Errno: 1062
40                Last_SQL_Error: Error 'Duplicate entry '25' for key 'PRIMARY'' on query. Default database: 'practice'. Query: 'insert into test_keepalived values(null,1,4)'
41   Replicate_Ignore_Server_Ids: 
42              Master_Server_Id: 1903309
43                   Master_UUID: 1b589d80-f450-11e7-9150-525400f4ecb2
44              Master_Info_File: /opt/app/mysql_3309/logs/master.info
45                     SQL_Delay: 0
46           SQL_Remaining_Delay: NULL
47       Slave_SQL_Running_State: 
48            Master_Retry_Count: 86400
49                   Master_Bind: 
50       Last_IO_Error_Timestamp: 
51      Last_SQL_Error_Timestamp: 180929 17:43:30
52                Master_SSL_Crl: 
53            Master_SSL_Crlpath: 
54            Retrieved_Gtid_Set: 
55             Executed_Gtid_Set: 
56                 Auto_Position: 0
57 1 row in set (0.00 sec)

 

Keepalived+双主架构总结 
    中小型规模采用这种架构省事,master发生故障宕机后,利用keepalived的高可用实现VIP的快速漂移。
一、采用keepalived做为高可用,两个节点上最好都设置为backup模式,避免意外状况下(好比脑裂)相互抢占致使往两个节点写入相同数据而引起冲突;
二、把两个节点的auto_increment_increment(自增步长)和auto_increment_offset(自增起始值)设成不一样值。其目的是为了不master节点意外宕机时,可能会有部分binlog未能及时复制到slave上被应用,从而会致使slave新写入数据的自增值和原先master上冲突了(原master从新恢复后),形成同步状态不正常。所以一开始就使其错开,若是有合适的容错机制能解决主从自增ID冲突的话,也能够不这么作;
3.slave节点服务器配置不要太差,不然更容易致使复制延迟。做为热备节点的slave服务器,硬件配置不能低于master节点;
4.若是对延迟问题很敏感的话,可考虑使用MariaDB分支版本,或者直接上线MySQL 5.7最新版本,利用多线程复制的方式能够很大程度下降复制延迟;
    本次测试中遇到以下的问题1能够经过对keepalived配置调整进行解决脑裂问题(两个keepalived服务对于VIP设置都不抢占);
    对于问题2中发生的主键冲突这个问题能够经过主键的自增加起始值和步长提到的方法进行解决,可是这样作不符合业务的开发习惯,或者时程序员的开发规范。通过一次对于表自增加主键的疑问,发现如今所在公司的开发在作业务开发的时候,一般会让表的主键进行自增,且他们会偷懒的把业务写入时主键不进行写入,而是让数据库本身去作这个事儿,于是主键必定是自增的。虽然这种作法不敢苟同,但确实下降了开发对于主键的考虑的成本,主键出现写入错误的可能性,同时这种不显性指定主键的插入值,也常常会致使这种主键重复的冲突。
    对于3中提到的,若是是主备模式的两台机器,配置应该保持一致,避免延迟带来的业务延迟。
    对于4提到的,请各位自行测试,并行复制确实是能够下降延迟,且5.7的并行复制是真正的并行复制。
相关文章
相关标签/搜索