LVS+Keepalived+Nginx实现服务高可用

摩森特沃 2021年09月19日 1,988次浏览

声明:本文多处直接引用了文末的参考链接中的内容,如有侵权,请联系删除

服务高可用方案

方案一:使用Nginx

通过Nginx进行反向代理到多个真实服务器,在此方案中当Nginx挂掉后,服务会停止

8irCqT

方案二:使用Keepalived结合Nginx实现双机主备

该方案是在每台Nginx服务器上使用Keepalived配置虚拟ip的方式,将多台提供相同功能的服务器组成一个路由器组,在路由器组中指定一个或多个虚拟ip对外提供服务,在此种方式下实现了Nginx主节点挂掉后,从节点的Nginx会启用,从而实现了双机主备

Y1WryD

Keepalived节点配置

  • 主节点配置
global_defs {
    # 路由id:当前安装keepalived节点主机的表示符,全局唯一	
    router_id keep_88
}
# 脚本配置,此处配置的脚本用于在nginx宕机后自动重启nginx
vrrp_script check_nginx_alive {
    script "/etc/keepalived/check_nginx_alive_or_not.sh"
    interval 2 # 每隔两秒运行上一行脚本
    weight 10 # 如果脚本运行成功,则升级权重+10
    # weight -10 # 如果脚本运行失败,则升级权重-10
}
# 基于vrrp协议的实例,是一个服务器节点
vrrp_instance VI_1 {
    # 表示的状态,当前的LVS_DEVEL为nginx的主节点,MASTER/BACKUP
    state MASTER
    # 当前实例绑定的网卡,可通过ip addr查看
    interface ens33
    # 虚拟路由id,在一个路由器组中需要保证主备节点一致
    virtual_router_id 51
    # 优先级/权重,谁的优先级高,在MASTER宕机以后就能成为MASTER
    priority 100
    # 主备之间同步检查的时间间隔,默认为1,单位为秒
    advert_int 1
    # 认证授权的密码,防止非法节点的进入,所有主备节点需保持一致
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 虚拟出来的ip(vip),可以有多个
    virtual_ipaddress {
	# 注意:需要保证主备两台的vip都是一样的,绑定到同一个vip
	# 同时虚拟ip的网段需要与组内的其他路由的网段相同
        192.168.31.88
    }
    # 追踪 nginx 脚本
    track_script {
        check_nginx_alive   
    }
}
  • 备用节点配置
global_defs {
   router_id keep_88
}
# 脚本配置,此处配置的脚本用于在nginx宕机后自动重启nginx
vrrp_script check_nginx_alive {
    script "/etc/keepalived/check_nginx_alive_or_not.sh"
    interval 2 # 每隔两秒运行上一行脚本
    weight 10 # 如果脚本运行成功,则升级权重+10
    # weight -10 # 如果脚本运行失败,则升级权重-10
}
# 基于vrrp协议的实例,是一个服务器节点
vrrp_instance VI_1 {
    # 表示的状态,当前的LVS_DEVEL为nginx的主节点,MASTER/BACKUP
    state BACKUP
    # 当前实例绑定的网卡,可通过ip addr查看
    interface ens33
    # 虚拟路由id,在一个路由器组中需要保证主备节点一致
    virtual_router_id 51
    # 优先级/权重,谁的优先级高,在MASTER宕机以后就能成为MASTER,官网推荐主备节点的优先级只差需要至少为50
    priority 40
    # 主备之间同步检查的时间间隔,默认为1,单位为秒
    advert_int 1
    # 认证授权的密码,防止非法节点的进入,所有主备节点需保持一致
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 虚拟出来的ip(vip),可以有多个
    virtual_ipaddress {
        192.168.31.88
    }
    # 追踪 nginx 脚本
    track_script {
        check_nginx_alive   
    }
}
  • Nginx重启脚本
# 路径:/etc/keepalived/check_nginx_alive_or_not.sh
#!/bin/bash
A=`ps -C nginx --no-header |wc -l`
# 判断nginx是否宕机,如果宕机了,尝试重启
if [ $A -eq 0 ];then
    /usr/local/nginx/sbin/nginx
    # 等待一小会再次检查nginx,如果没有启动成功,则停止keepalived,使其启动备用机
    sleep 3
    if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
        killall keepalived
    fi
fi

在此方案中,由于备用Keepalived只会在主Keepalived宕机时才会发挥作用,而且备用服务器由于也需要支持相同的用户访问,往往其配置与性能需要与主服务器相同或者相差不大,因此在这种方案中备用服务器的存在会造成资源的巨大浪费

方案三:使用Keepalived结合Nginx实现双主热备

双主热备的硬件要求与双机主备完全相同,但需要在Keepalived的配置文件中增加额外的配置,使得多台Keepalived服务器互为主备,同时为保证备用服务器也能正常提供服务,在同一个Keepalived中,在作为主节点和备用节点的时候,需要设置为不同的虚拟ip,同时设置域名访问时通过dns轮询的方式解析到所有的虚拟ip上,其网络架构图如下

eMRhlx

Keepalived节点配置

  • 主节点配置
global_defs {
   router_id keep_101
}

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.31.88
    }
}

vrrp_instance VI_2 {
    state BACKUP
    interface ens33
    # 注意,此处定义的是另外一组路由,因此不能再使用51
    virtual_router_id 52
    priority 40
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.31.89
    }
}
  • 备用节点配置
global_defs {
   router_id keep_93
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 51
    priority 40
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.31.88
    }
}

vrrp_instance VI_2 {
    state MASTER
    interface ens33
    # 注意,此处定义的是另外一组路由,因此不能再使用51
    virtual_router_id 52
    # 由于是主节点,此处将优先级设置为100
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
	# 设置新的虚拟ip
        192.168.31.89
    }
}

在以上配置文件中,互为主备的Keepalived分别对应了182.168.31.88和192.168.31.89两个虚拟ip,在配置域名解析时,只需要将域名轮询解析到2个ip即可

注意,不管是阿里云或者腾讯云的云服务主机,如果需要配置虚拟ip,需要购买额外的付费服务

此方案虽然解决了服务器资源浪费的问题,但是由于Nginx是七层负载均衡,因此并不足以支持高并发的用户访问,无论有多少从节点,还是会有挂掉的风险,从而演进第四种方案

方案四:LVS + Keepalived + Nginx服务高可用方案

通过LVS+Keepalived+Nginx,搭建了Nginx集群,对于LVS使用DR模式,将请求请求转发到各个真实服务器,同时真实服务器的响应不通过LVS,而是直接通过Nginx响应给用户,这样LVS负载就更高了,从而提高性能

029qnc

LVS

LVS 简介

LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统。LVS项在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。LVS具有以下特点个

  • LVS基于四层负载均衡,工作效率更高
  • LVS可以充当Nginx集群的调度者,用来解决单个Nginx抗压能力不强的问题
  • LVS可以只接受请求不响应,即只处理请求转发,由于具有这样的特性,其支持的并发比Nginx更高

LVS 与 Nginx 网络拓扑图对比

Nginx网络拓扑图

LVS网络拓扑图

LVS 工作模式

  • NAT

mDLVCx

NAT工作模式下与Nginx类似,不适用于超大并发的场景,通常LVS位于公网,真实的服务器位于企业内网中,用户不能直接访问真实服务器

  • TUN(隧道)

n0f8xN

TUN是一种IP隧道模式,要求所有的计算机节点必须具有网卡用于建立隧道,也即是所有的真实服务器也需要暴露在公网中,在这种模式下用户所有的响应不会经过LVS,可以提高并发和吞吐量

  • DR(直接路由)

CNxzC8

DR是使用一个虚拟路由来统一处理用户响应的一种模式,可以避免将真实服务器暴露在公网中

LVS + Keepalived + Nginx高可用服务实现

服务器准备

准备4台虚拟机(CentOS 7),用于测试使用

主机IP作用
主机1192.168.31.169Nginx1
主机2192.168.31.190Nginx2
主机3192.168.31.101Keepalived主节点
主机4192.168.31.93Keepalived备用节点
192.168.31.89虚拟IP(VIP)

准备工作

关闭网络配置管理器

开发阶段准备工作:关闭网络配置管理器,在开发阶段,由于采用的时虚拟机的方式,在这种方式下如果不关闭可能会引起网络接口冲突

systemctl stop NetworkManager
systemctl disable NetworkManager

安装集群管理工具

使用以下命令安装集群管理工具(ipvsadm),ipvs是LVS的管理工具,用于提供集群配置管理的功能

yum install -y ipvsadm

ipvsadmin常用命令

  • 查看帮助文档:ipvsadm -h 或者 man ipvsadm
  • 查看集群列表:ipvsadm -Ln
  • 查看集群状态:ipvsadm -Ln --stats
  • 重启ipvsadm,重启后需要重新配置:service ipvsadm restart
  • 查看持久化连接:ipvsadm -Ln --persistent-conn
  • 查看连接请求过期时间以及请求源ip和目标ip:ipvsadm -Lnc
  • 设置tcp tcpfin upd的过期时间(一般保持默认):ipvsadm --set 1 1 1
  • 查看过期时间:ipvsadm -Ln --timeout

搭建步骤

安装Nginx和Keepalived

  • 在主机1和主机2上安装Nginx,安装步骤可参考这篇博文
  • 在主机3和主机4上安装Keepalived,安装步骤可参考这篇博文

构建虚拟网络接口子接口

分别在主机1和主机2上构建虚拟网络接口子接口

  • 进入到/etc/sysconfig/network-scripts:cd /etc/sysconfig/network-scripts
  • 复制配置文件:cp ifcfg-lo ifcfg-lo:1
  • 修改配置文件,将配置文件改为如下内容
# 名称需要与配置文件的名称保持一致
DEVICE=lo:1
# 构建的虚拟ip
IPADDR=192.168.31.89
NETMASK=255.255.255.255
NETWORK=127.0.0.0
# If you're having problems with gated making 127.0.0.0/8 a martian,
# you can change this to something else (255.255.255.255, for example)
BROADCAST=127.255.255.255
ONBOOT=yes
NAME=loopback
  • 重启网络:service network restart或者ifup lo,使用ip addr查看网络信息,出现新配置的网卡对应的虚拟ip即表示虚拟ip构建成功

配置ARP(Address Resolution Protocal,地址解析协议)

  • 修改 /etc/sysctl.conf 配置文件,增加以下内容
# 配置所有网卡,默认网卡以及虚拟网卡的arp响应级别和通告行为,分别对应:all,default,lo
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
  • 使用sysctl -p进行刷新
  • 添加host路由用于接收数据报文,接收报文后交给本机的lo:1处理,配置命令为:route add -host 192.168.31.89 dev lo:1
  • 查看host路由配置结果:route -n
  • 以上添加host路由的方式在服务器重启后会失效,因此需要将配置加入到开机自启动文件中,添加方式:echo "route add -host 192.168.31.89 dev lo:1" >> /etc/rc.local

ARP配置参数说明

  • arp_ignore:ARP响应级别(处理请求)
  • 0:只要本机配置了ip,就能响应请求
  • 1:请求的目标地址达到对应的网络接口,才会响应请求
  • arp_announce:ARP通告行为(返回响应)
  • 0:本机上任何网络接口都可以向外通告,所有的网卡都能接收到通告
  • 1:尽可能避免本网卡与不匹配的目标进行通告
  • 2:只在本网卡通告

配置Keepalived节点

  • 配置Keepalived主节点,配置文件路径为:/etc/keepalived/keepalived.conf,配置内容如下
global_defs {
   router_id keep_101
}

vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 41
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.31.89
    }
}
# 配置集群地址访问的ip + 端口,端口和nginx保存一致,都是80
virtual_server 192.168.31.89 80 {
    # 健康检查的时间,单位:秒
    delay_loop 6
    # 配置负载均衡的算法,默认是轮询
    lb_algo rr
    # 设置LVS的工作模式:NAT|TUN|DR
    lb_kind DR
    # 设置会话持久化的时间,单位:秒
    persistence_timeout 5
    # 协议 -t
    protocol TCP
    
    # 负载均衡的真实服务器,也就是nginx节点的具体的真实ip地址
    real_server 192.168.31.169 80 {
        # 轮询的默认权重配比设置为1
        weight 1
        # 设置健康检查
        TCP_CHECK {
            # 检查80端口
            connect_port 80
            # 超时时间 2s
            connect_timeout 2
            # 重试次数
            nb_get_retry 2
            # 间隔时间 3s
            delay_before_retry 3
        }
    }
    real_server 192.168.31.190 80 {
        weight 1
        TCP_CHECK {
            # 检查80端口
            connect_port 80
            # 超时时间 2s
            connect_timeout 2
            # 重试次数
            nb_get_retry 2
            # 间隔时间 3s
            delay_before_retry 3
        }
    }
}
  • 清除主节点已有的负载均衡规则:ipvsadm -C
  • 重启主节点keepalived:service keepalived restart
  • 查看主节点集群配置结果:ipvsadm -Ln
  • 使用ip addr查看主节点的网络信息如下,可以看到192.168.31.89已经出现在网卡ip地址中

yY9hrF

  • 配置Keepalived备用节点,配置文件路径为:/etc/keepalived/keepalived.conf,配置内容如下
global_defs {
   router_id keep_93
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 41
    priority 40
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.31.89
    }
}
# 配置集群地址访问的ip + 端口,端口和nginx保存一致,都是80
virtual_server 192.168.31.89 80 {
    # 健康检查的时间,单位:秒
    delay_loop 6
    # 配置负载均衡的算法,默认是轮询
    lb_algo rr
    # 设置LVS的工作模式:NAT|TUN|DR
    lb_kind DR
    # 设置会话持久化的时间
    persistence_timeout 5
    # 协议 -t
    protocol TCP
    
    # 负载均衡的真实服务器,也就是nginx节点的具体的真实ip地址
    real_server 192.168.31.169 80 {
        # 轮询的默认权重配比设置为1
        weight 1
        # 设置健康检查
        TCP_CHECK {
            # 检查80端口
            connect_port 80
            # 超时时间 2s
            connect_timeout 2
            # 重试次数
            nb_get_retry 2
            # 间隔时间 3s
            delay_before_retry 3
        }
    }
    real_server 192.168.31.190 80 {
        weight 1
        TCP_CHECK {
            # 检查80端口
            connect_port 80
            # 超时时间 2s
            connect_timeout 2
            # 重试次数
            nb_get_retry 2
            # 间隔时间 3s
            delay_before_retry 3
        }
    }
}
  • 清除备用节点已有的负载均衡规则:ipvsadm -C
  • 重启备用节点keepalived:service keepalived restart
  • 查看备用节点集群配置结果:ipvsadm -Ln
  • 使用ip addr查看主节点的网络信息如下,可以看到192.168.31.89已经出现在网卡ip地址中

tO3qmT

测试

rsHtcC

P8a25n

扩展内容

LVS 负载均衡算法

静态算法

静态算法是根据LVS本身自由的固定的算法分发用户请求,静态算法主要有以下几种

  • 轮询(Round Robin 简写’rr’):轮询算法假设所有的服务器处理请求的能力都一样的,调度器会把所有的请求平均分配给每个真实服务器。(同Nginx的轮询)
  • 加权轮询(Weight Round Robin 简写’wrr’):安装权重比例分配用户请求。权重越高,被分配到处理的请求越多。(同Nginx的权重)
  • 源地址散列(Source Hash 简写’sh’):同一个用户ip的请求,会由同一个RS来处理。(同Nginx的ip_hash)
  • 目标地址散列(Destination Hash 简写’dh’):根据url的不同,请求到不同的RS。(同Nginx的url_hash)

动态算法

动态算法是根据流量的不同,或者服务器的压力不同来分配用户请求,动态算法主要有以下几种

  • 最小连接数(Least Connections 简写’lc’):把新的连接请求分配到当前连接数最小的服务器
  • 加权最少连接数(Weight Least Connections 简写’wlc’):服务器的处理性能用数值来代表,权重越大处理的请求越多。Real Server 有可能会存在性能上的差异,此时会动态获取不同服务器的负载状况,把请求分发到性能好并且比较空闲的服务器
  • 最短期望延迟(Shortest Expected Delay 简写’sed’):特殊的wlc算法。举例阐述,假设有ABC三台服务器,权重分别为1、2、3 。如果使用wlc算法的策略,当请求进来,它可能会分给ABC中的任意一个。使用sed算法后会进行如下运算:
  • A:(1+1)/1=2
  • B:(1+2)/2=3/2
  • C:(1+3)/3=4/3
    最终结果,会把这个请求交给得出运算结果最小的服务器
  • 最少队列调度(Never Queue 简写’nq’):永不使用队列。如果有Real Server的连接数等于0,则直接把这个请求分配过去,不需要在排队等待运算了

常见问题

为什么LVS设置了轮询,浏览器测试还是不能轮询?

这关系到两个地方的配置:

  • /etc/keepalived/keepalived.conf的persistence_timeout会话保持时间配置,测试轮询时设置为0
  • ipvsadm默认超时时间

查看ipvsmadm默认超时时间:ipvsadm -L --timeout
Timeout (tcp tcpfin udp): 900 120 300
900 120 300 这三个数值分别是TCP TCPFIN UDP的时间,也就是说一条tcp的连接经过lvs后,lvs会把这台记录保存15分钟,就是因为这个时间过长,导致轮询现象并没有发生,可使用以下命令设置默认的超时时间:

ipvsadm --set 1 2 1

再次测试轮询效果,就可以了!而实际配置中还是按照默认配置,那么在大量IP访问VIP时,就有轮询效果?有待验证

引用参考