在Linux基于Keepalived搭建LVS实现高可用负载均衡

发布时间 2023-04-05 18:26:44作者: 我有八千部下

前言

参考这篇CSDN - 在Linux配置LVS实现负载均衡可以搭建LVS(Linux Virtual Server)实现负载均衡。但是它有下列主要缺陷:

  • 没有备机,LVS故障时将不能提供服务。就算准备了备机,也需要人为监控LVS状态,在故障的时候修复或者用备机顶替
  • 不能监控RS(Real Server)存活状态,如果有RS故障,将会有部分请求分发到这些机器,导致请求无法处理

Keepalived出现就是为了解决这些问题,它可以带来以下好处:

  • 根据Keepalived配置设置,自动配置LVS
  • 搭建主备负载均衡服务器(LVS),监控存活状态,在主机宕机后及时选出新主提供服务
  • 检测RS(Real Server)存活状态,及时剔除无效的RS,避免将请求转发到无效的RS上,也会将恢复的RS重新加入负载列表

这一篇搭建步骤其实很简单,安装配置下Keepalived就可以了,只不过在测试部分写的比较详细,篇幅相对较长一点。

搭建步骤

搭建RS的步骤和上面那篇文章是一样的,我们现在需要做的是准备2台及以上的负载均衡服务器DS(Director Server)作主备。在主备上都配置Keepalived。在这里我们用4台主机:

  • node1(DS主):IP为192.168.252.131
  • node2(RS):IP为192.168.252.132
  • node3(RS):IP为192.168.252.133
  • node4(DS备):IP为192.168.252.134

image-20211123175633407

建议先关掉防火墙。

echo "停止、关闭防火墙" > /dev/null
systemctl stop firewalld
systemctl disable firewalld

配置真实服务器(RS)

这一步和CSDN - 在Linux配置LVS实现负载均衡中的步骤一样。

要注意的是,要先改ARP配置,再配置VIP,不然有可能会在配置ARP之前暴露VIP地址。

  • 修改内核地址解析协议(Address Resolution Protocol,ARP)内核参数映射文件让其他网卡不暴露VIP,保/证VIP对内(本机)可见,对外隐藏
  • 对虚拟环回网卡配置子接口,绑定VIP,并设置掩码为255.255.255.255,让RS能处理请求并能直接返回
echo "给ens33网卡接口配置" > /dev/null
echo 1 > /proc/sys/net/ipv4/conf/ens33/arp_ignore 
echo 2 > /proc/sys/net/ipv4/conf/ens33/arp_announce 

echo "为了方便,给所有网卡接口配置" > /dev/null
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore 
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

echo "对虚拟环回网卡配置子接口" > /dev/null
ifconfig lo:2 192.168.252.100 netmask 255.255.255.255

配置负载均衡服务器(DS主)

echo "安装keepalived和ipvs管理工具" > /dev/null
yum install keepalived ipvsadm -y

echo "备份keepalived配置文件" > /dev/null
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak

echo "将配置覆盖到keepalived配置文件" > /dev/null
echo '! Configuration File for keepalived
vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.252.100/24 dev ens33 label  ens33:2
    }
}

virtual_server 192.168.252.100 80 {
    delay_loop 6
    lb_algo rr
    lb_kind DR
    nat_mask 255.255.255.0    
    persistence_timeout 0
    protocol TCP

    real_server 192.168.252.132 80 {
        weight 1
        HTTP_GET {
            url {
              path /
              status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 192.168.252.133 80 {
        weight 1
        HTTP_GET {
            url {
              path /
              status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}' > /etc/keepalived/keepalived.conf

echo "启动keepalived" > /dev/null
service keepalived start

下面是配置中每个参数的解释。如果安装了Linux/Unix环境下命令与函数的帮助文档(Manual page)可以执行man 5 keepalived.conf查看相关配置文档。也可以访问Keepalived官网的Keepalived Configuration Manual Page

vrrp_instance VI_1 { # 虚拟路由冗余协议(Virtual Router Redundancy Protocol,VRRP),监控LVS主和RS存活状态走这个协议
    state MASTER # 这台机器初始状态,MASTER|BACKUP
    interface ens33 # VRRP使用的网卡接口
    virtual_router_id 51 # Keepalived可以配置多套LVS,同一套LVS使用相同的虚拟路由ID
    priority 100 # 优先级,按优先级选主,一般服务器性能好的优先级配高点
    advert_int 1 # VRRP通告间隔(秒)
    authentication {
        auth_type PASS # 鉴权类型,PASS|AH,官网推荐的是PASS简单密码验证
        auth_pass 1111 # 密码
    }
    virtual_ipaddress { # 配置VIP
        192.168.252.100/24 dev ens33 label ens33:2 # 使用ens33创建(dev)子接口命名(label)为ens33:2,VIP为192.168.252.100,子网掩码为255.255.255.0(/24)
    }
}

virtual_server 192.168.252.100 80 { # 配置LVS虚拟服务指定IP和端口号
    delay_loop 6 # 健康监测时间间隔(秒)
    lb_algo rr # 负载均衡算法为轮询(rr)
    lb_kind DR # 类型为直接路由(DR)
    nat_mask 255.255.255.0 # 子网掩码
    persistence_timeout 0 # 保证在这个时间内(秒)同一客户端的请求发送到相同的RS,避免每次请求跟不同RS建立连接。LVS会记录TCP握手数据包所以是知道之前哪个IP转发到了哪台RS,我们为了测试能实时看到切换效果设置成0
    protocol TCP # TCP协议

    real_server 192.168.252.132 80 { # RS配置,指定IP和监听的端口
        weight 1 # 权重
        HTTP_GET { # 健康检查,HTTP_GET|SSL_GET
            url {
              path / # 请求路径
              status_code 200 # 返回状态码为这个视作正常
            }
            connect_timeout 3 # 超时时间(秒)
            nb_get_retry 3 # 重试次数
            delay_before_retry 3 # 重试时间间隔(秒)
        }
    }
}

配置负载均衡服务器(DS备)

备机配置和主机几乎一样,只需要将Keepalived配置中初始状态(state)改成BACKUP,优先级(priority)设置比主低一点。

测试

查看DS主备配置

  • 查看DS(主)配置
echo "查看网卡接口" > /dev/null
ifconfig

echo "查看ipvs路由规则" > /dev/null
ipvsadm -ln

可以看到Keepalived根据我们的配置生成了VIP网卡接口(ens33:2)和IPVS路由表规则。客户端可以通过VIP来访问。

image-20211124103334580

image-20211124103350966

  • 查看DS(备)配置

使用相同的方式在备机只能看到IPVS路由表配置,但是看不到配置VIP的网卡接口。没有VIP,客户端无法通过VIP访问,IPVS就算配置了也不会生效,因为是备机,主机正常的情况下不生效是对的。

image-20211124103503551

image-20211124103628130

这一步我们验证的出了主备之间差异就在于只有主有VIP,有VIP才能对外提供服务。

访问VIP验证负载均衡

给两台RS(node2、node3)都安装httpd,并分别指定不同的httpd主页内容,测试时好区分。

echo "安装" > /dev/null
yum -y install httpd

echo "启动" > /dev/null
service httpd start

echo "覆盖指定httpd主页内容" > /dev/null
echo 'node2' > /var/www/html/index.html

我们通过命令行或者浏览器(浏览器可能有GET缓存,不切换等几秒缓存过期)访问VIP(192.168.252.100)可以看从返回结果看到在两个RS间轮询切换。

image-20211124095541330

我们可以在DS(主)上看到IPVS连接记录。

ipvsadm -lcn

image-20211124104303498

但是在DS(备)上就看不到了,因为没有VIP,是无法提供服务的。

image-20211124104617992

这一步我们验证出主机成功实现了负载均衡,而备机啥也没干。

查看虚拟路由冗余协议(VRRP)数据包

echo "安装tcpdump" > /dev/null
yum install tcpdump -y

echo "查看ens33网卡接口数据" > /dev/null
tcpdump -i ens33 vrrp -n

在主备执行,都可以看到主节点向VRRP组播地址(224.0.0.18)发送报文,报文内容包我们在Keepalived配置的信息,如:含虚拟路由ID(vrid 51)、优先级(prio 100)、简单密码验证(authtype simple)等等。

image-20211124105356037

image-20211124105440990

验证主备切换

将DS(主)关机,或者宕掉VIP和VRRP网卡。

ifconfig ens33 down

我们还是可以继续访问VIP,查看备机网卡配置可以发现新增了VIP。

image-20211124110500251

查看备机IPVS连接记录,可以看到请求都到达了备机上。

image-20211124112546667

而对于客户端来说,整个切换过程无感知,也不知道备机的存在。

恢复DS(主)

重启主节点或者,重新启动网卡。会看到主节点重新配置了VIP、IPVS路由表规则,再次成为了主对外提供服务。而备机VIP配置被清除,不能再对外提供服务。对客户端而言,这个过程同样是透明的。

ifconfig ens33 up

验证监控RS

我们宕掉一台RS,或者停掉RS的httpd。

service httpd stop

等待IPVS一段时间重试之后,查看主(node1)备(node4)的IPVS路由条目可以看到,路由条目中宕掉的node2(192.168.252.132)已被剔除。

image-20211124133922401

image-20211124133940795

客户端访问VIP也只会转发到健康的node3(192.168.252.133)上。

image-20211124134225487

如果恢复宕掉的node2,将会看到IPVS路由条目中会恢复,访问VIP也会看到有请求负载到node2。

到这一步,我们验证了IPVS监控RS,及时剔除和恢复负载。

查看Keepalived进程

ps -ef | grep keepalived

从主备都可以看到有3个相关进程,①是进程ID,②是进程的父进程ID。

主进程(12138)通告自己健康状态;两个子进程(12139、12140)分别连接两个RS,检查它们的存活状态。

image-20211124142016261

其他问题

DS(主)Keepalived进程异常退出

如果我们让DS(主)的Keepalived进程异常退出(如:kill -9),它就无法清除IPVS配置,主机仍然有VIP和IPVS路由规则,且能对外提供服务。

image-20211124141929134

然后DS(备)没收到DS(主)的健康报文,顶替成为主,添加VIP,也能对外提供服务。

image-20211124140742555

这样就导致了网络中有两个VIP存在,那就就可能一个TCP握手中,客户端两次发送的包分别给了不同的VIP,导致连接失败。所以Keepalived在这种情况下还是有缺陷。

下面这段是我测试客户端在这种情况下访问结果,纯粹好奇,作用不大。

但是我查看客户端的ARP缓存发现,出现上面这种情况后,缓存中VIP对应的MAC地址由指向DS(主)的更新成了指向DS(备)的。

arp -an

image-20211124142847507

image-20211124142922290

客户端能正常访问VIP。

image-20211124143110140

请求都到了备机的VIP上。

image-20211124143148424

清空客户端的ARP缓存,又会发现VIP地址重新指向了DS(主机),然后请求又重新到了DS主上。

虽然不是很正常,但用起来居然没出问题,也许是都在同一局域网,网络关系简单,但是同时存在多个VIP这种情况还是不要出现。

防火墙导致多个VIP

问题是主机启动Keepalived后,自动添加了VIP,然后备机也启动,也直接绑定了VIP。原因是备机的防火墙限制VRRP协议导致没收到主机报文,备机认为主机故障,自己直接顶替成了主机。

解决办法是让防火墙允许接收VRRP。细节可以参考CSDN - keepalived出现主备机同时绑定vip的解决方法

echo "设置防火墙允许接收VRRP" > /dev/null
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT

echo "刷新防火墙" > /dev/null
firewall-cmd --reload

或者将防火墙关掉。

参考链接

Keepalived Configuration Manual Page

Keepalived官网

CSDN - keepalived出现主备机同时绑定vip的解决方法