一.前言
在mysql的实际生产环境中,配置了mysql双机多实例+主从复制,并且准备设置为双机多实例+双master,以增加mysql实例的高可用性。经过研究,仅keepalived无法实现多实例上的高可用,于是采用lvs+keepalived以实现mysql多实例+双master上的高可用.
LVS和Keepalived介绍:
LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统。采用IP负载均衡技术和基于内容请求分发技术。调度器具有很好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故障,从而将一组服务器构成一个高性能的、高可用的虚拟服务器。整个服务器集群的结构对客户是透明的,而且无需修改客户端和服务器端的程序.
keepalived是一个类似于layer3, 4 & 5交换机制的软件,也就是我们平时说的第3层、第4层和第5层交换。Keepalived的作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的web服务器从系统中剔除,当web服务器工作正常后Keepalived自动将web服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的web服务器。
简单来说
LVS主要提供负载均衡.
Keepalived在这里主要用作RealServer的健康状态检查以及LoadBalance主机和BackUP主机之间failover的实现.
借张图展示一下:
二.环境描述
现有环境:
mysql服务器A: 192.168.67.253:3306 192.168.67.253:3308 mysql服务器B: 192.168.67.254:3306 192.168.67.254:3308 两台服务器上的3306端口互为master,3308端口互为master
实现后的架构:
负载均衡器: MASTER: 接口ip:192.168.66.6 VIP:192.168.66.251 所需软件:ipvsadm,keepalived BACKUP: 接口ip:192.168.66.12 VIP:192.168.66.251 所需软件:ipvsadm,keepalived 真实服务器: mysql服务器A: 接口ip及端口: 192.168.67.253:3306 192.168.67.253:3308 VIP:192.168.66.251 所需软件:lvs客户端配置脚本 mysql服务器B: 192.168.67.254:3306 192.168.67.254:3308 VIP:192.168.66.251 所需软件:lvs客户端配置脚本
三.部署过程
1.安装ipvs及keepalived
在两台准备做负载均衡器的服务器上分别安装ipvs和keepalived,详细安装过程可参照SA team中相关文档,在此不再赘述。
1.1 安装lvs客户端
Lvs的客户端指负载均衡其/转发器(director)后面提供服务的真实机器。也即是我们的mysql服务器。在mysql服务器上增加如下配置文件
[root@localhost ~]# more /usr/local/bin/lvs_real #!/bin/bash #description : start realserver VIP=192.168.66.251 /etc/rc.d/init.d/functions case "$1" in start) echo " start LVS of REALServer" /sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce ;; stop) /sbin/ifconfig lo:0 down echo "close LVS Directorserver" echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce ;; *) echo "Usage: $0 {start|stop}" exit 1 esac
这里对配置文件里重要的一些项进行说明:
1、 vip(virtual ip)。直接路由模式的vip必须跟服务器对外提供服务的ip地址在同一个网段, 并且lvs 负载均衡器和其他所有提供相同功能的服务器都使用这个vip.
2、 vip被绑定在环回接口lo0:0 上,其广播地址是其本身,子网掩码是255.255.255.255。这 与标准的网络地址设置有很大的不同。采用这种可变长掩码方式把网段划分成只含一个 主机地址的目的是避免ip地址冲突。
3、 echo “1”,echo “2” 这段的作用是抑制arp广播。如果不做arp抑制,将会有众多的机器 向其他宣称:“嗨!我是奥巴马,我在这里呢!”,这样就乱套了。
1.2 lvs客户端验证
执行命令 /usr/local/bin/lvs_real start ,接着我们来检查网络的状态:
[root@localhost ~]# ip addr 1: lo: mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet 192.168.66.251/32 brd 192.168.66.251 scope global lo:0 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000 link/ether 54:04:a6:b7:9c:4c brd ff:ff:ff:ff:ff:ff inet 192.168.66.253/24 brd 192.168.66.255 scope global eth0 inet6 fe80::5604:a6ff:feb7:9c4c/64 scope link valid_lft forever preferred_lft forever
发现在lo接口上绑定VIP成功。可以通过/usr/local/bin/lvs_real stop卸载VIP
1.3 keepalived.conf
请注意,在安装ipvs及keepalived过程中,只有keepalived.conf这个配置文件是与SA team相关文档中不同
MASTER的配置文件/etc/keepalived/keepalived.conf
root># cat /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { router_id lvs50 } vrrp_sync_group VG1 { group { INT } } vrrp_instance INT { state MASTER #备份服务器上将MASTER改为BACKUP interface eth0 lvs_sync_daemon_interface eth0 virtual_router_id 200 #相同的VRID为一个组,他将决定多播的MAC地址;在局域网应唯一(即假如一个局域网内有多套LVS,则这里的设置不冲突即可) priority 100 #备份服务上将100改为比100小,最好主备的值差大于50 advert_int 1 authentication { auth_type PASS auth_pass lvs50test } virtual_ipaddress { 192.168.66.251 #设置Vip } } virtual_server 192.168.66.251 3306 { delay_loop 20 lb_algo wrr #lb_algo rr|wrr|lc|wlc|lblc|sh|dh #LVS调度算法 lb_kind DR #lb_kind NAT|DR|TUN #LVS模式 persistence_timeout 120 protocol TCP #virtualhost www.no300.com #检查客户端的域名,这里用TCP去检测,可不用设置 sorry_server 192.168.66.254 3306 #在real_server失败的时候跳转到的ip和port real_server 192.168.66.253 3306 { #真实服务器IP和Port weight 1 TCP_CHECK { #用TCP协议检测 connect_timeout 5 nb_get_retry 3 delay_before_retry 3 connect_port 3306 } } } virtual_server 192.168.66.251 3308 { delay_loop 20 lb_algo wrr #lb_algo rr|wrr|lc|wlc|lblc|sh|dh #LVS调度算法 lb_kind DR #lb_kind NAT|DR|TUN #LVS模式 persistence_timeout 120 protocol TCP #virtualhost www.no300.com #检查客户端的域名,这里用TCP去检测,可不用设置 sorry_server 192.168.66.254 3308 #在real_server失败的时候跳转到的ip和port real_server 192.168.66.253 3308 { #真实服务器IP和Port weight 1 TCP_CHECK { #用TCP协议检测 connect_timeout 5 nb_get_retry 3 delay_before_retry 3 connect_port 3308 } } }
BACKUP配置文件/etc/keepalived/keepalived.conf
root># cat /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { router_id lvs50 } vrrp_sync_group VG1 { group { INT } } vrrp_instance INT { state BACKUP #备份服务器上将MASTER改为BACKUP interface eth0 lvs_sync_daemon_interface eth0 virtual_router_id 200 #相同的VRID为一个组,他将决定多播的MAC地址;在局域网应唯一 priority 90 # 备份服务上将100改为99 advert_int 1 authentication { auth_type PASS auth_pass lvs50test } virtual_ipaddress { 192.168.66.251 } } virtual_server 192.168.66.251 3306 { delay_loop 20 lb_algo wrr #lb_algo rr|wrr|lc|wlc|lblc|sh|dh #LVS调度算法 lb_kind DR #lb_kind NAT|DR|TUN #LVS模式 persistence_timeout 120 protocol TCP #virtualhost www.no300.com sorry_server 192.168.66.254 3306 real_server 192.168.66.253 3306 { weight 1 TCP_CHECK { connect_timeout 5 nb_get_retry 3 delay_before_retry 3 connect_port 3306 } } } virtual_server 192.168.66.251 3308 { delay_loop 20 lb_algo wrr #lb_algo rr|wrr|lc|wlc|lblc|sh|dh #LVS调度算法 lb_kind DR #lb_kind NAT|DR|TUN #LVS模式 persistence_timeout 120 protocol TCP #virtualhost www.no300.com sorry_server 192.168.66.254 3308 real_server 192.168.66.253 3308 { weight 1 TCP_CHECK { connect_timeout 5 nb_get_retry 3 delay_before_retry 3 connect_port 3308 } } }
keepalived realserver列表只配置一台mysql主机,sorry server配置另一台主机。
这样在realserver正常情况下,sorry server不会被切换,只充当备机,只有realserver出故障时才切换到sorry server,keepalived的sorry server天生具有这个特性。
2.lvs+keepalived服务的启用和验证
2.1 启动lvs客户端
在两台mysql服务器上分别执行/usr/local/bin/lvs_real start,然后执行命令ip addr检验是否启动成功
2.2 启动keepalived
在两台负载均衡服务器上分别执行命令service keepalived start ,然后我们查看系统进程,看是否是3个keepalived进程
root># ps -ef |grep keepalived root 15595 1 0 14:50 ? 00:00:00 keepalived -D root 15596 15595 0 14:50 ? 00:00:00 keepalived -D root 15597 15595 0 14:50 ? 00:00:00 keepalived -D root 15600 15597 0 14:50 ? 00:00:00 [keepalived] root 15603 15537 0 14:50 pts/0 00:00:00 grep --color=auto keepalived
查看/var/log/messages中keepalived段的输出,看是否有异常。
执行命令ip addr,看VIP是否已正确绑定到MASTER
MASTER的输出:
root># ip addr 1: lo: mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo 2: eth0: mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 50:59:00:e2:b7:8a brd ff:ff:ff:ff:ff:ff inet 192.168.66.6/24 brd 192.168.66.255 scope global eth0 inet 192.168.66.251/32 scope global eth0
BACKUP的输出:
root># ip addr 1: lo: mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo 2: eth0: mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 50:56:00:e2:b7:8a brd ff:ff:ff:ff:ff:ff inet 192.168.66.12/23 brd 192.168.67.255 scope global eth0
四.功能测试
4.1 测试前准备
保证所有服务器的网络服务正常。ping所有ip及vip来检查
4.2 转发功能测试
1.在本地机器执行命令 telnet 192.168.66.251 3306,检查访问是否正常。然后测试3308端口
2.登录主负载均衡器,察看转发情况。
root># ipvsadm IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.66.251:mysql wrr persistent 120 -> 192.168.66.253:mysql Route 1 0 0 TCP 192.168.66.251:tns-server wrr persistent 120 -> 192.168.66.253:tns-server Route 1 0 0
4.3 健康检查功能(故障隔离)测试
通过手工的方法,使真实服务器提供的服务失效,然后再从客户端发起访问请求,检验lvs提供的服务是否可用。
两种方式:1.停止某个真实服务器的服务 2.关闭网络服务。
4.3.1 关闭真实服务器192.168.66.253:3306上的mysql
在本地telnet 192.168.66.253 3306,不能访问为正常。
telnet 192.168.66.251 3306.如访问正常,再检查keepalived日志,发现主负载均衡器上有如下输出,BACKUP无日志输出
Jul 19 15:47:22 6 Keepalived_healthcheckers: TCP connection to [192.168.66.253]:3306 failed !!! Jul 19 15:47:22 6 Keepalived_healthcheckers: Removing service [192.168.66.253]:3306 from VS [192.168.66.251]:3306 Jul 19 15:47:22 6 Keepalived_healthcheckers: Lost quorum 1-0=1 > 0 for VS [192.168.66.251]:3306 Jul 19 15:47:22 6 Keepalived_healthcheckers: Adding sorry server [192.168.66.254]:3306 to VS [192.168.66.251]:3306 Jul 19 15:47:22 6 Keepalived_healthcheckers: Removing alive servers from the pool for VS [192.168.66.251]:3306
telnet 192.168.66.254 3306,发现访问正常,证明lvs已将请求转发至sorr_server指定的192.168.66.254:3306.
4.3.2 关闭lvs 的客户端配置脚本/usr/local/bin/lvs_real
这个测试不会成功,关闭真实机器的vip以后,负载均衡器依然会把用户请求转发过来,但tcp连接不成功,用户的访问会失败。因此在部署和运维lvs环境时,要特别注意这一点。
关闭192.168.66.253上的lvs_real脚本,此时telnet 192.168.66.253 3306访问正常,telnet 192.168.66.251 3306访问失败。
在keepalived检测时间超时后,依然未看到有错误日志输出。因此要特别注意此脚本
五.失败切换(FailOver)测试
关闭主负载均衡器(MASTER)的keepalived进程,然后从客户端访问vip地址及真实服务器地址
正常情况下,主负载均衡器(MASTER)失效时,备份负载均衡器(BACKUP)能立即接替转发任务(接替时间由keepalived.conf文件的advert_int 指定)。
在确认主负载均衡器(MASTER)的keepalived进程关闭后,我们来看看备份负载均衡器的运行情况。这里我们观察两个地方:ipvsadm 的输出及系统日志的输出。
5.1 ipvsadm 输出变化
MASTER上keepalived未关闭时的输出:
root># ipvsadm IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.66.251:mysql wrr persistent 120 -> 192.168.66.253:mysql Route 1 0 0 TCP 192.168.66.251:tns-server wrr persistent 120 -> 192.168.66.253:tns-server Route 1 0 0
MASTER上keepalived关闭后的输出:
root># ipvsadm IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn
BACKUP上ipvsadm输出未变化,原因尚不清楚
5.2 系统日志输出变化
MASTER:
Jul 19 16:58:14 6 Keepalived: Terminating on signal Jul 19 16:58:14 6 Keepalived: Stopping Keepalived v1.2.2 (04/12,2012) Jul 19 16:58:14 6 Keepalived_vrrp: Terminating VRRP child process on signal Jul 19 16:58:14 6 Keepalived_healthcheckers: Terminating Healthchecker child process on signal Jul 19 16:58:14 6 Keepalived_vrrp: VRRP_Instance(INT) removing protocol VIPs. Jul 19 16:58:14 6 kernel: IPVS: stopping sync thread 15679 ... Jul 19 16:58:15 6 kernel: IPVS: sync thread stopped!
BACKUP:
Jul 19 16:58:19 12 Keepalived_vrrp: VRRP_Instance(INT) Transition to MASTER STATE Jul 19 16:58:19 12 Keepalived_vrrp: VRRP_Group(VG1) Syncing instances to MASTER state Jul 19 16:58:20 12 Keepalived_vrrp: VRRP_Instance(INT) Entering MASTER STATE Jul 19 16:58:20 12 Keepalived_vrrp: VRRP_Instance(INT) setting protocol VIPs. Jul 19 16:58:20 12 Keepalived_vrrp: VRRP_Instance(INT) Sending gratuitous ARPs on eth0 for 192.168.66.251 Jul 19 16:58:20 12 kernel: IPVS: stopping sync thread 23765 ... Jul 19 16:58:20 12 Keepalived_healthcheckers: Netlink reflector reports IP 192.168.66.251 added Jul 19 16:58:20 12 kernel: IPVS: sync thread stopped! Jul 19 16:58:20 12 Keepalived_vrrp: Netlink reflector reports IP 192.168.66.251 added Jul 19 16:58:20 12 kernel: IPVS: sync thread started: state = MASTER, mcast_ifn = eth0, syncid = 200 Jul 19 16:58:25 12 Keepalived_vrrp: VRRP_Instance(INT) Sending gratuitous ARPs on eth0 for 192.168.66.251
可以看到备份负载均衡器已接管服务
现在再回来启动MASTER上的keepalived服务,接着观察BACKUP上的系统日志
BACKUP:
Jul 19 17:14:35 12 Keepalived_vrrp: VRRP_Instance(INT) Received higher prio advert Jul 19 17:14:35 12 kernel: IPVS: stopping sync thread 23772 ... Jul 19 17:14:35 12 kernel: IPVS: sync thread stopped! Jul 19 17:14:35 12 Keepalived_vrrp: VRRP_Instance(INT) Entering BACKUP STATE Jul 19 17:14:35 12 Keepalived_vrrp: VRRP_Instance(INT) removing protocol VIPs. Jul 19 17:14:35 12 Keepalived_healthcheckers: Netlink reflector reports IP 192.168.66.251 removed Jul 19 17:14:35 12 Keepalived_vrrp: VRRP_Group(VG1) Syncing instances to BACKUP state Jul 19 17:14:35 12 Keepalived_vrrp: Netlink reflector reports IP 192.168.66.251 removed Jul 19 17:14:35 12 kernel: IPVS: sync thread started: state = BACKUP, mcast_ifn = eth0, syncid = 200
输出显示BACKUP已把控制权移交给MASTER
六.模拟生产环境测试
6.1 环境准备
请开发人员设计一个java程序,每隔1秒往mysql的表中插入一行数据,模拟mysql实例失败及keepalived失败切换的场景。
mysql环境:
模拟两读一写的模式,即只往192.168.66.253:3306写数据,253和254两台机器的3306实例均可读取数据。待253:3306失败后才写254:3306.
表结构:
CREATE TABLE `vip_wealth_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `account` varchar(40) NOT NULL, `cert_no` varchar(40) DEFAULT NULL COMMENT '用户身份证号', `name` varchar(40) DEFAULT NULL COMMENT '用户姓名', PRIMARY KEY (`id`), KEY `vip_user_wealth_index` (`cert_no`,`name`) ) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='记录会员的财富值流水信息'
6.2 模拟mysql实例失败
6.2.1 测试Innodb存储引擎
启动java程序,开始往mysql中插入数据,查看数据写入情况,192.168.66.253:3306停止前查询到的结果如下:
mysql> select * from vip_wealth_log; +----+---------+---------+------+ | id | account | cert_no | name | +----+---------+---------+------+ | 2 | test | demo | test | | 4 | test | demo | test | | 6 | test | demo | test | | 8 | test | demo | test | | 10 | test | demo | test | | 12 | test | demo | test | | 14 | test | demo | test | | 16 | test | demo | test | | 18 | test | demo | test | +----+---------+---------+------+ 9 rows in set (0.00 sec)
可以看到mysql已依照设定值,将自增段做了奇偶处理。
停止192.168.66.253:3306,java程序抛出异常,连接中止。查询192.168.66.254:3306的数据结果如下:
mysql> select * from vip_wealth_log; +----+---------+---------+------+ | id | account | cert_no | name | +----+---------+---------+------+ | 2 | test | demo | test | | 4 | test | demo | test | | 6 | test | demo | test | | 8 | test | demo | test | | 10 | test | demo | test | | 12 | test | demo | test | | 14 | test | demo | test | | 16 | test | demo | test | | 18 | test | demo | test | | 20 | test | demo | test | | 22 | test | demo | test | | 24 | test | demo | test | | 26 | test | demo | test | | 28 | test | demo | test | +----+---------+---------+------+ 14 rows in set (0.00 sec)
重新启动192.168.66.253:3306服务后查询结果也一样。
在192.168.66.253:3306关闭的情况下,重新启动java程序,此时服务已切换至192.168.66.254:3306,查看自增列为单数,验证双master架构成功。不再截图。
继续切换,恢复192.168.66.253:3306服务,此时查看keepalived日志,服务切换回192.168.66.253:3306,java程序抛出异常,并停止往192.168.66.254:3306写数据。
但因192.168.66.254:3306服务并未中止,所以java程序的连接仍在,过了大概5-10分钟连接才消失。
6.2.2 测试MyISAM存储引擎
更改表存储引擎为MyISAM,同上述步骤重新测试,得到测试结果同上,不再赘述。
但因5.1版本的mysql同步仍为异步同步,不排除192.168.66.253:3306实例崩溃时丢失数据,以及崩溃时数据未及时和192.168.66.254:3306同步而导致两台机器数据不一致的可能(可能性极大)。
6.3 崩溃测试
执行命令ps -ef |grep mysql,kill掉3306或3308端口任意实例,观察对其他实例是否有影响。
kill掉某个实例后,在两台mysql服务器上执行命令mysqld_multi report,发现均未影响到其他实例的运行,检查日志也未抛出异常。测试成功
七.测试总结
1.在停止192.168.66.253:3306实例后再打开,发现192.168.66.254:3306并未马上连接至192.168.66.2533:3306.
修改master_connect_retry=1;修正此问题。
2.由于mysql5.1版本复制为异步复制,存在一定延迟,在两台master切换或某实例崩溃,特别是某进程执行更新MyISAM表中大批数据崩溃的情况下,会造成两台master数据不一致的情况。
因此建议使用双master架构的应用应允许小部分数据量不一致,或者表存储引擎为Innodb且有自增主键的mysql服务器采用此架构。
八.状态监控
使用zabbix监控以下服务的运行:
1.负载均衡器及真实服务器的存活检查。只有这些服务器运行正常,才可能有其他依赖服务。
2.Vip的存活检查。特别是lvs客户端上lo端口绑定VIP的检查。一般情况下,启用了lvs环境后,是可以用ping的方式检查vip的。
3.真实服务器服务状态检查。
4.Vip对应的服务状态检查。一般通过check_tcp加端口号的形式实现。
九.参考文献
1.SA team中lvs及keepalived相关文档
2.《互联网运营智慧》 第6章 负载均衡及服务器集群(LVS) 作者:田逸