需求

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系列