简单介绍
先简单说下MySQL主从复制与keepalived模式和MySQL共享存储与Keepalived模式
MySQL共享存储主备模式不同于MySQL主主复制模式,MySQL主主是利用MySQL自带的replication复制技术实现两台或多台MySQL服务器之间互为拉取二进制日志,处于BACKUP的服务器从MASTER获取二进制日志,并将日志解析成相应的SQL语句,然后在从服务器上重新执行一遍主服务器的操作,从而保证主从数据的一致性。MySQL的复制是实时的异步复制过程,能够保持多台数据库之间数据的一致性,利用MySQL复制可以实现多种方式的主从复制备份,如一主一从、一主多从、双主、双主多从,其优点是显而易见的,因此现实环境中不少的企业都使用MySQL复制技术与keepalived、heartbeat、MySQL Proxy、实现MySQL的高可用集群架构。
当然,MySQL复制技术并非百分百能够保证数据的完成一致性,同时由于开启了二进制日志功能,多少会增加一点I/O,因此在性能上会有一定损耗。简单的主主复制与keepalived模式,在正常情况下两台机器同时提供服务,并且只允许其中一台对外提供写入功能,另外一台提供读功能或只作为备机,当主down之后立即替换为主保证来服务的稳定不中断运行。(当然如果配置auto_increment_offset和auto_incremen_increment参数,可以解决主主同步写入问题)当主故障发生后,keepalived检测到之后将服务切换到从服务器上,在这个过程当中可以看到,keepalived的切换时间是非常迅速的,但此时必须及时修复故障的服务器并继续加入到主从列表中才能保证服务的相对稳定性。一旦有数据异常造成主从不同步都会影响故障的修复效率。
结合MySQL系统架构的灵活性,那么我在这里简单写一篇关于《MySQL共享存储主备模式利用Keepalived实现双机高可用》的教程,以供大家参考。
本篇的MySQL共享存储与keepalived的实现方式类似于DRBD+heartbeat模式。DRBD是一个基于软件实现的服务器存储镜像块设备复制的方案,用于实现实时的、透明的数据同步。可以提供大多数HA系统双机热备的方案。由于DRBD是基于软件的,那么其磁盘的性能必然不如物理磁盘。而共享存储在实际环境中是使用比较多的存储方案,一般是由磁盘阵列提供。如SAN、NAS存储。因此由共享存储提供的HA服务有很多,比如,WEB服务器使磁阵替代NFS存储;MySQL HA的共享存储;Oracle RAC的ASM的共享存储。MySQL HA使用共享存储与keepalived的模式并不能两台MySQL都同时提供服务,正常情况下,只有一台提供服务,另外一台完成处于备用的角色,结合keepalived灵活的脚本检测功能,当主服务器down机时,keepalived可以完成做到自动切换,保障服务的稳定运行。那么这种情况下更适用于对业务要求高稳定性的场景中。
Keepalived的脚本检测功能相当灵活,并且也相对简单。Keepalived的主备角色选举策略由state的状态决定,例如主节点配置为MASTER,备节点配置为BACKUP时,当启动keepalived集群时,处于MASTER状态的节点接管VIP和MySQL服务,而BACKUP状态的节点就处于备用的节点,只有集群发生异常时,keepalived才会根据priority值重新选举MASTER和BACKUP角色,priority值大的节点成为MASTER。在这个角色切换的过程中,如果定义了检测脚本,并且设置了脚本的weight值,当集群异常时,keepalived选举MASTER角色由priority值和weight值之和决定,因此,此时priority+weight就是新的priority值,priority值大的节点被选举为MASTER节点,并且接管集群当中的MySQL服务。
图为MySQL HA与Keepalived实现高可用的模型
那么在这个HA环境中,要注意的一个问题是,正常情况下只有MASTER角色的节点提供MySQL服务,并且也只有MASTER角色的节点挂载共享存储。在keepalived启动时,keepalived会检测各个节点的MySQL服务,只有检测到是正常状态,才被加入到keepalived集群当中(选举为MASTER和BACKUP),如果检测到异常,如MySQL并未启动,此时keepalived并不会把这个节点选举为BACKUP节点,而是被标识为FAULT状态,而当为FAULT状态时,如果MASTER节点down机时,keepalived并不会进行切换,那么此时糟糕的事情是,主备就都不能用了。为了解决这一个问题,应该在检测脚本中自定义为自己想要的状态。如在脚本中定义检测MySQL时,当这台服务器上没有挂载存储,没有VIP,也没有运行MySQL,同时满足这三个条件时,这个节点应该也被视为正常的节点,即BACKUP节点。当MASTER节点down时,才会将服务转移至BACKUP节点当中。定义了灵活的脚本之后,keepalived才能为HA服务提供高可用性。
实验环境
主机 |
IP |
系统 |
角色 |
Server1 |
192.168.6.174 |
CentOS6.8 |
MASTER |
Server2 |
192.168.6.175 |
CentOS6.8 |
BACKUP |
VIP |
192.168.6.176 |
||
共享存储 |
/dev/sdb1 |
实验步骤
一、MySQL安装配置
Server1和Server2安装MySQL,安装版本保持一致,包括MySQL用户UID、安装目录、数据文件目录都要完成相同。
1
2
3
4
5
6
7
8
9
|
[root@Server1 ~]
# id mysql
uid=498(mysql) gid=500(mysql)
groups
=500(mysql)
[root@Server1 ~]
# ls /usr/local/mysql/
bin COPYING data docs include lib
man
mysql-
test
README scripts share sql-bench support-files
[root@Server2 ~]
# id mysql
uid=498(mysql) gid=500(mysql)
groups
=500(mysql)
[root@Server2 ~]
# ls /usr/local/mysql/
bin COPYING data docs include lib
man
mysql-
test
README scripts share sql-bench support-files
|
只需在主节点执行安装系统数据库的脚本$basedir/scripts/mysql_install_db
1
2
3
|
[root@Server1 ~]
# mount /dev/sdb1 /data/
[root@Server1 ~]
# cd /usr/local/mysql/scripts/
[root@Server1 scripts]
# ./mysql_install_db --user=mysql --data=/data/mysql/mysql --basedir=/usr/local/mysql --no-defaults
|
二、Keepalived安装和配置
1、安装keepalived (Server1和Server2节点)
1
2
3
4
|
[root@Server1 ~]
# yum install pcre-devel openssl-devel popt-devel libnl-devel libnfnetlink libnfnetlink-devel
[root@Server1 keepalived-1.3.2]
# ./configure --prefix=/usr/local/keepalived --sysconf=/etc --with-kernel-dir=/usr/src/kernels/2.6.32-642.el6.x86_64
[root@Server1 keepalived-1.3.2]
# make && make install
[root@Server1 keepalived-1.3.2]
# ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/
|
2、配置keepalived.conf
Server1节点(MASTER)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
! Configuration File
for
keepalived
global_defs {
notification_email {
mail@huangming.org
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id MySQL_HA_DEVEL
vrrp_skip_check_adv_addr
}
vrrp_sync_group MySQL_HA_G1 {
group {
MySQL_HA_1
}
}
vrrp_script chk_mysql {
script
"/etc/keepalived/scripts/check_mysql.sh"
interval 6
fall 2
rise 1
weight 20
}
vrrp_script chage_status {
script
"/etc/keepalived/scripts/chage_status.sh"
interval 20
}
vrrp_instance MySQL_HA_1 {
state BACKUP
interface eth1
virtual_router_id 176
priority 100
advert_int 2
nopreempt
authentication {
auth_type PASS
auth_pass v262aR1dqH5jTykUbwTo
}
virtual_ipaddress {
192.168.6.176
/24
dev eth1
}
track_script {
chk_mysql
chage_status
}
track_interface {
eth1
}
notify_master
"/etc/keepalived/scripts/notify.sh master"
notify_backup
"/etc/keepalived/scripts/notify.sh backup"
notify_fault
"/etc/keepalived/scripts/notify.sh fault"
notify_stop
"/etc/keepalived/scripts/notify.sh stop"
}
|
Server2节点(BACKUP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
! Configuration File
for
keepalived
global_defs {
notification_email {
mail@huangming.org
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id MySQL_HA_DEVEL
vrrp_skip_check_adv_addr
}
vrrp_sync_group MySQL_HA_G1 {
group {
MySQL_HA_1
}
}
vrrp_script chk_mysql {
script
"/etc/keepalived/scripts/check_mysql.sh"
interval 6
fall 2
rise 1
weight 20
}
vrrp_script chage_status {
script
"/etc/keepalived/scripts/chage_status.sh"
interval 20
}
vrrp_instance MySQL_HA_1 {
state BACKUP
interface eth1
virtual_router_id 176
priority 90
advert_int 2
authentication {
auth_type PASS
auth_pass v262aR1dqH5jTykUbwTo
}
virtual_ipaddress {
192.168.6.176
/24
dev eth1
}
track_script {
chk_mysql
chage_status
}
track_interface {
eth1
}
notify_master
"/etc/keepalived/scripts/notify.sh master"
notify_backup
"/etc/keepalived/scripts/notify.sh backup"
notify_fault
"/etc/keepalived/scripts/notify.sh fault"
notify_stop
"/etc/keepalived/scripts/notify.sh stop"
}
|
3、Keepalived notify脚本
notify脚本是keepalived集群管理脚本,当keepalived角色state状态发生变化时都会执行这个脚本
1
2
3
4
|
notify_master:当节点进入MASTER时执行该脚本
notify_backup:当节点进入BACKUP时执行该脚本
notify_fault: 当节点进入FAULT时执行该脚本
notify_stop: 当节点进入STOP时执行该脚本
|
Server1和Server2的notify脚本定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
#!/bin/bash
# Author: hm Email: mail@huangming.org
LOGDIR=
/usr/local/keepalived/logs
LOGFILE=
"/usr/local/keepalived/logs/notify_scripts.log"
IPADDR=`
ifconfig
eth1 |
awk
-F
"[: ]+"
'/inet addr/{print $4}'
`
VIP=
"192.168.6.176"
[ -d $LOGDIR ] ||
mkdir
$LOGDIR
#MASTER
master() {
if
[ `
df
-h |
grep
"/dev/sdb1"
|
wc
-l` -
eq
0 ];
then
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: mount /dev/sdb1 /data ..."
mount
/dev/sdb1
/data
&&
sleep
1
else
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: /data is mounted on /data"
fi
killall -0 mysqld &>
/dev/null
if
[ $? -
ne
0 ];
then
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: /etc/init.d/mysqld start..."
/etc/init
.d
/mysqld
start &>
/dev/null
else
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: Mysqld is Running..."
fi
exit
0
}
#BACKUP
backup() {
killall -0 mysqld &>
/dev/null
if
[ $? -
eq
0 ];
then
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: /etc/init.d/mysqld stop..."
/etc/init
.d
/mysqld
stop &>
/dev/null
else
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: Mysql Server is Not Running..."
fi
if
[ `
df
-h |
grep
"/dev/sdb1"
|
wc
-l` -
ne
0 ];
then
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: umount /data..."
umount
/data
&&
sleep
1
else
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: /data is not mount"
fi
}
notify_master() {
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: Transition to $1 STATE"
;
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: Setup the VIP on eth1 for $VIP"
;
}
notify_backup() {
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: Transition to $1 STATE"
;
echo
"`date '+%b %d %T %a'` $HOSTNAME [keepalived_notify_script]: removing the VIP on eth1 for $VIP"
;
}
case
$1
in
master)
notify_master MASTER >>$LOGFILE
master >>$LOGFILE
exit
0
;;
backup)
notify_backup BACKUP >>$LOGFILE
backup >>$LOGFILE
exit
0
;;
fault)
notify_backup FAULT >>$LOGFILE
backup >>$LOGFILE
exit
0
;;
stop)
notify_backup STOP >>$LOGFILE
backup >>$LOGFILE
#/etc/init.d/keepalived restart &>/dev/null #这一项仅在Server2节点上配置
exit
0
;;
*)
echo
"Usage: `basename $0` {master|backup|fault|stop}"
exit
1
;;
esac
|
4、keepalived资源检测脚本
MySQL服务检测脚本check_mysql.sh
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bash
# 检测共享磁盘是否正常挂载,如果没有挂载,则脚本返回状态码1
if
[ `
df
-h |
grep
"/dev/sdb1"
|
wc
-l` -
eq
0 ];
then
exit
1
#检测MySQL服务是否正常运行,如果不正常,则返回状态码1
elif
! killall -0 mysqld &>
/dev/null
;
then
exit
1
else
exit
0
Fi
# 如果共享磁盘和MySQL服务都正常,那么就返回0,进入keepalived集群的MASTER或BAKUP角色
|
MySQL更改状态脚本chage_status.sh(MASTER)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#!/bin/bash
# in MASTER
#改变MySQL服务的检测脚本,keepalived刚启动时,Server1节点接管MySQL服务,成为MASTER,该节
#点的检测mysql服务脚本为正常检测,即当共享磁盘和MySQL服务均正常,则正常返回状态码0;
#而Server2节点,在启动keepalived时,检测脚本则改为当共享磁盘和MySQL服务均没有运行时,
#同样返回状态码0,因此进入BACKUP角色。改变检测脚本的前提条件为是否存在VIP,当Server2节点
#同时满足这三个条件才会改变脚本的检测状态
CHK_VIP=`ip addr|
awk
-F
"[ :]+"
'/192.168.6.176/{print $3}'
`
if
[
"$CHK_VIP"
==
""
];
then
cat
>
/etc/keepalived/scripts/check_mysql
.sh << EOF
#!/bin/bash
if
[ \`
df
-h |
grep
"/dev/sdb1"
|
wc
-l\` -
eq
0 ];
then
exit
0
elif
! killall -0 mysqld &>
/dev/null
;
then
exit
0
else
exit
0
fi
EOF
else
cat
>
/etc/keepalived/scripts/check_mysql
.sh << EOF
#!/bin/bash
if
[ \`
df
-h |
grep
"/dev/sdb1"
|
wc
-l\` -
eq
0 ];
then
exit
1
elif
! killall -0 mysqld &>
/dev/null
;
then
exit
1
else
exit
0
fi
EOF
Fi
|
MySQL更改状态脚本chage_status.sh(BACKUP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#!/bin/bash
# in BACKUP
CHK_VIP=`ip addr|
awk
-F
"[ :]+"
'/192.168.6.176/{print $3}'
`
if
[
"$CHK_VIP"
==
""
];
then
cat
>
/etc/keepalived/scripts/check_mysql
.sh << EOF
#!/bin/bash
if
[ \`
df
-h |
grep
"/dev/sdb1"
|
wc
-l\` -
eq
0 ];
then
exit
0
elif
! killall -0 mysqld &>
/dev/null
;
then
exit
0
else
exit
0
fi
EOF
else
cat
>
/etc/keepalived/scripts/check_mysql
.sh << EOF
#!/bin/bash
if
[ \`
df
-h |
grep
"/dev/sdb1"
|
wc
-l\` -
eq
0 ];
then
exit
1
elif
! killall -0 mysqld &>
/dev/null
;
then
pkill keepalived &&
exit
1
else
exit
0
fi
EOF
fi
|