使用lvs+keepalived为mysql提供高可靠的负载分担功能
by 伊布
需求
1 安装软件
基本所有的Linux版本内核都包含了LVS,不需要再安装。 安装ipvsadm,用来控制内核lvs表项; keepalived,用来控制虚IP迁移; ldirectord,现在还没有用到。可以用来检测real server是否可用。 我用的是centos,直接yum安装即可。
2 组网
使用了4台虚拟机,本机连接到其中虚拟机里的mysql服务。 组网图如下。
3 配置keepalived
需要在DLVS1、DLVS2两台服务器上配置keepalived。keepalived需要配置2个VRRP实例: VRRP实例1:供外部用户访问,DLVS故障恢复不影响用户访问,对应虚IP1; VRRP实例2:供mysql服务器访问。由于在本例中lvs配置成nat模式,mysql集群上的各个机器需要配置网关为DLVS的内部虚IP,否则DLVS迁移后,mysql上报文回不去。对应虚IP2,即Real Server(RS)的网关地址。 其中,DLVS1的priority均配置为101,DLVS2的priority均配置为100。DLVS1、DLVS2均正常时,DLVS1优先级更高,所以虚IP落在DLVS1上;若DLVS1故障,VRRP迁移,虚IP改落在DLVS2上;DLVS1故障恢复后,会抢占回虚IP。
由于两台服务器配置基本是一致的,为了避免发生过多的虚IP迁移,这里我们把VRRP配置为不抢占模式。 具体到配置上,两台设备均配置VRRP state为BACKUP(当然这样会有一个影响,因为现在没有MASTER,启动以后要稍等一会才会抢占虚IP);计划为主的设备,VRRPpriority配置更大,并且添加nopreempt。备设备不需要再加preempt。
/etc/keepalived/keepalived.conf:
! Configuration File for keepalived
global_defs {
#不做修改
}
vrrp_instance VI_1 {
state BACKUP
interface eth2
virtual_router_id 51
priority 101
nopreempt
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.80.111
}
}
vrrp_instance VI_2 {
state BACKUP
interface eth1
virtual_router_id 52
priority 101
nopreempt
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.80.1.243
}
}
这里我没有检查LVS服务是否可靠。DLVS进程起来以后,keepalived需要脚本检查DLVS进程是否正常,如果故障了需要切换。怎么设置参考我之前的文章。
4 配置RS
RS上主要配置MySQL和网络: 1、安装及配置MySQL。安装不再赘述,需要配置MySQL远程访问及root密码:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
FLUSH PRIVILEGES;
2、配置网络
centos的配置文件在/etc/sysconfig/network-scripts/ifcfg-ethx
DEVICE="eth0"
BOOTPROTO="static"
IPV6INIT="yes"
NM_CONTROLLED="yes"
IPADDR=192.168.80.136
NETMASK=255.255.255.0
GATEWAY=192.168.80.111
ONBOOT="yes"
TYPE="Ethernet"
5 配置LVS
LVS主要配置virtual server和real server,以及开启IP转发。
ipvsadm的配置就不再多说,直接看man手册即可。
为了方便以后用,把ipvsadm命令组织到service脚本中,可以service dlvs start/stop
。由于ipvsadm的配置不会保存,如果设备故障重启了就没了,需要把service start加到系统启动过程中。
脚本:/etc/init.d/dlvs
#!/bin/sh
VIP=10.80.1.243
RIP1=192.168.80.167
RIP2=192.168.80.136
SERVPORT=3306
. /etc/rc.d/init.d/functions
case "$1" in
start)
echo " start DLVS of Director Server"
echo "1" >/proc/sys/net/ipv4/ip_forward
/sbin/ipvsadm -C
/sbin/ipvsadm -A -t $VIP:$SERVPORT -s rr
/sbin/ipvsadm -a -t $VIP:$SERVPORT -r $RIP1:$SERVPORT -m
/sbin/ipvsadm -a -t $VIP:$SERVPORT -r $RIP2:$SERVPORT -m
service iptables stop
;;
stop)
echo "close DLVS Director Server"
echo "0" >/proc/sys/net/ipv4/ip_forward
/sbin/ipvsadm -C
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
将脚本启动加到系统启动过程中。在centos里,需要把用户自己启动的命令加到/etc/rc.local中,即在这个文件中添加一行:service dlvs start
。
6 测试
DLVS1、DLVS2、RS1、RS2正常启动后,虚IP1、虚IP2均落在DLVS1上(使用ip addr命令)。DLVS1、DLVS2上看lvs内核表项均为:
# ipvsadm -l
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.80.1.243:mysql rr
-> 192.168.80.136:mysql Masq 1 0 0
-> master:mysql Masq 1 1 0
从客户端PC访问虚IP1(10.80.1.243),DLVS1将请求NAT到mysql服务器中的某一台,在DLVS1上可以看到ipvs连接信息:
# ipvsadm -l -c
IPVS connection entries
pro expire state source virtual destination
TCP 14:53 ESTABLISHED 10.80.0.243:50640 10.80.1.243:mysql master:mysql
将DLVS1整机重启,虚IP1、虚IP2漂移到DLVS2上,客户端再访问mysql服务,会重建连接,在DLVS2上ipvsadm可以看到新建立的connection;DLVS1重启完毕后,连接会再建立到DLVS1上,前面已有描述,略。
7 待扩展
7.1 内核connection同步
从前面的例子我们可以看到,虚IP漂移后,DLVS2接手,但是客户端连接需要重新建立,但其实真实的mysql服务器还是正常工作的,对于用户来说连接断开的体验较差。 LVS可以通过配置,在内核提供一个同步线程,将当前提供服务的设备上的表项,组播报文同步到其他服务器上。配置如下:
[@DLVS1]$: ipvsadm --start-daemon master - --mcast-interface ethX
[@DLVS2]$: ipvsadm --start-daemon backup - --mcast-interface ethY
虚IP切换过以后,内核连接信息都在,就可以保证用户连接不断。 但这里还有个问题,在本方案里,所有的LVS其实均为主,而组播线程其实是有主、备身份的,备切过去以后就不能再同步表项了,当主设备回切,连接还是会断。还没有想到办法解决。
7.2 iptables
细心的同学会发现前面我粗暴的把iptables服务给整个关闭了,但这其实是很不安全的,正确的做法是添加一条规则。 关闭的原因?在实测过程中,发现从mysql返回的syn+ack报文,被DLVS设备的防火墙丢弃并返回了”Destination unreachable (Host administratively prohibited)”。 等我知道该怎么添加规则的时候,我就改。
7.3 ldirectord
现在的方案里,如果是RS级别的故障,LVS可以做到切换,不会将服务NAT到故障的机器;但如果只是mysql服务的故障,LVS还做不到检查,会影响用户访问失败。所以,需要一个工具能够告诉LVS,RS上的服务故障了,不要再转过去了。 ldrectord可以搞定这件事情。
大量参考: Linux负载均衡软件LVS系列
Subscribe via RSS