一、LVS
1.1 基础知识
ipvs: 工作在内核空间, 实现集群服务的”调度”, 借鉴了iptables的实现方式
ipvsadm: 工作在用户空间, 负责为ipvs内核框架编写规则. 定义谁是集群服务, 谁是后端服务器, 数据包如何调度, 调度到哪个节点

| 名称简写 |
详细名称 |
描述 |
| DS |
Director Server |
目标服务器, 即负载均衡器LVS |
| RS |
Real Server |
真实应用服务器, 即后端服务器 |
| CIP |
Client IP |
客户端请求IP |
| VIP |
Virtual IP |
虚拟IP, 直接面向用户的IP地址, 通常为公网IP |
| DIP |
Director Server IP |
用于与后端RIP通讯的IP地址 |
| RIP |
Real Server IP |
后端真实服务器端IP地址 |
1.2 LVS常见模型
LVS负载均衡模型有NAT, DR, TUN, FULL-NA, 较为常见的模型有NAT, DR, 使用最为广泛的模型是DR
1.2.1 NAT模式
NAT模型原理: 通过修改请求报文的目标IP地址, 然后根据算法挑出某台RS进行转发.
请求进入负载均衡器LVS时叫做DNAT, 后端返回数据报文出负载均衡器LVS时叫做SNAT
NAT模型访问流程
1、当用户请求到达 Director Server ,此时请求的数据报文会先到内核空间 的 PREROUTING 链。 此时报文的 源IP为CIP , 目标IP为VIP
2、 PREROUTING 检查发现数据包的目标 IP 是本机,将数据包送至 INPUT 链。
3、 IPVS 比对数据包请求的服务是否为集群服务,若是,通过调度算法挑选一 台后端 RS 服务器,并修改数据包的 目标IP 为 RS的IP ,然后将数据包发至 POSTROUTING 链。 此时报文的 源IP为CIP , 目标IP为RIP
4、 POSTROUTING 链通过选路,将数据包通过 Director Server 的 DIP 发送 给 RS
5、 RS 发现目标为自己的 IP ,则交给应用程序处理,然后构建响应报文发回给 Director Server 。 此时报文的 源IP为RIP , 目标IP为CIP
6、 Director Server 在响应客户端前,会将源 IP 地址修改为 VIP 地址,然 后响应给客户端。此时报文的 源IP为VIP , 目标IP为CIP
NAT模型特性
1、 RS 必须使用私有地址,并需要将网关指向 DS
2、 RIP 和 DIP 必须为同一网段内。
3、 NAT 模型支持端口映射。
4、 RS 可以使用任意操作系统。例如 Linux、Windows 等。
5、请求和响应报文都要经过 DS ,高负载场景中, DS 易称为瓶颈。
1.2.2 DR模式
DR模型原理: 通过修改请求报文的目标MAC地址, 然后根据算法挑出某台RS进行转发
请求进入负载均衡器LVS时叫做MAC地址转换, 后端返回数据报文不经过负载均衡, 所有无需做转换
DR模型访问流程
1、当用户请求到达 DS节点 ,此时请求的数据报文会先到内核空间的 PREROUTING 链。 此时报文的 源IP为CIP , 目标IP为VIP 。
2、 PREROUTING 检查发现数据包的 目标IP 是本机,将数据包送至 INPUT 链。
3、 IPVS 比对数据包请求的服务是否为集群服务,是则将请求报文中的 源MAC 修 改为 DMAC ,将 目标MAC 修改 RMAC ,然后将数据包通过 POSTROUTING 链发出。 此时的 源IP 和 目的IP 均未修改,仅将 源MAC 修改为 DMAC , 目标MAC 修改为 RMAC
4、由于 DS 和 RS 在同一个网络中,所以是通过二层来传输。 POSTROUTING 链检 查 目标MAC 为 RIP的MAC 地址,那么此时数据包将通过 DIP 发送 RS 节点
5、 RS 拆解数据报文发现请求的 IP 地址是本机,则会接收该数据报文,而后构 建响应报文向外发出,此时的 源IP 是 VIP , 目标IP 是 CIP
6、响应报文最终送达至客户端
DR 模型特性
1、请求报文必须由 DS 节点转发,但响应报文必须不经过 DS 节点
2、 RS 不能将网关指向 DS 节点的 DIP
3、 DS 和 RS 节点必须位于同一物理网络中
4、 DR 模型不支持地址转换,也不支持端口映射
5、 RS 可以是常见的操作系统 Windows、Linux、MacOS 6、 RS 在 lo 接口上配置 VIP
DR模式配置
集群规划
| 服务 |
网络接口 |
IP地址 |
网关 |
| DS |
eth1 |
172.16.1.3 |
172.16.1.1 |
|
eth1:1 |
172.16.1.100 |
|
| RS1 |
eth1 |
172.16.1.5 |
172.16.1.1 |
|
lo:0 |
172.16.1.100 |
|
| RS2 |
eth1 |
172.16.1.6 |
172.16.1.1 |
|
lo:0 |
172.16.1.100 |
|
| VIP |
|
172.16.1.100 |
|
RealServer添加VIP地址, 需要做arp抑制(简单来说就是路由器广播VMAC时所有RS不应答, 所有RS都不对外宣称自己的VIP),配置如下两个参数
- arp_ignore: 忽略外部arp获取本机VIP地址的应答
- 0: 默认值; 将本机所有接口的所有信息像每个连接的网络进行通告
- 1: 只应答本地主机访问网络接口(eth0–>lo), 才给予应答
- arp_annouce: 不主动对外宣告本机VIP地址
- 0: 默认值; 将本机所有接口的所有信息像每个连接的网络进行通告
- 1: “尽量避免”将接口信息向非直接连接网络进行通告
- 2: “必须避免”将接口信息向非本地网络进行通告
RS服务器
sysctl.conf配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore echo "1" >/proc/sys/net/ipv4/conf/default/arp_ignore echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce echo "2" >/proc/sys/net/ipv4/conf/default/arp_announce echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
或者 cat > /etc/sysctl.cof << 'EOF'
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 EOF sysctl -p
|
网卡配置
1 2 3 4 5 6 7 8 9
| cat > /etc/sysconfig/network-scripts/ifcfg-lo:0 << EOF DEVICE=lo:0 IPADDR=172.16.1.100 NETMASK=255.255.0.0 ONBOOT=yes NAME=loopback EOF
ifdown lo:0 && ifup lo:0
|
DS服务器
sysctl.conf配置
1 2
| # 启用FORWARD转发功能,实现路由功能 net.ipv4.ip_forward = 1
|
网卡配置
1 2 3 4 5 6 7 8 9 10 11
| cat > /etc/sysconfig/network-scripts/ifcfg-eth1:1 << EOF TYPE=Ethernet BOOTPROTO=none DEFROUTE=yes NAME=eth1:1 DEVICE=eth1:1 ONBOOT=yes IPADDR=172.16.1.100 PREFIX=24 EOF ifdown eth1:1 && ifup eth1:1
|
ipvsadm添加规则
1 2 3 4 5 6 7 8 9 10 11 12
| ipvsadm -C
ipvsadm -A -t 172.16.1.100:80 -s rr
ipvsadm -a -t 172.16.1.100:80 -r 172.16.1.5:80 -g ipvsadm -a -t 172.16.1.100:80 -r 172.16.1.6:80 -g
ipvsadm -L -n
|
172.16.1.100为VIP地址
1.3 LVS持久化连接
DS节点修改集群配置
1 2 3 4 5
| ipvsadm -E -t 172.16.1.100:80 -p 30
-E 修改集群 -p 持久连接保持秒数
|
1.4 LVS集群命令
- ipvsadm用法大概分为两类
- 管理集群服务(定义负载均衡配置)
- 管理后端RS(定义负载均衡后端节点增删改查)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ipvsadm - Linux Virtual Server administration
-A ,--add-service -E ,--edit-service -D ,--delete-service -C ,--clear -R ,--restore -S ,--save -L|-l,--list -Z ,--zero -n
-a,--add-server -e,--edit-server -d,--delete-server -t,service-address host[:port],tcp协议 -u,service-address host[:port],udp协议 -r,--real-server -w,--weight -m,--masquerading -g,--gatewaying -i,--ipip -s,--scheduler -p,--persistent -f,--fwmark-service -c,--connection
|
二、Keepalived
2.1 Keepalived基础
Keepalived特性
1 2 3 4 5
| keepalived软基是C语言编写的一个开源软件项目, 其本质是一个路由软件 keepalived基于ipvs功能进行二次整合实现负载均衡功能 keepalived基于VRRP协议进行二次整合实现高可用功能 keepalived借助于大量的功能脚本实现高质量的状态检查功能 keepalived框架可以单独使用, 也可以和其它软件进行整合使用
|
官方文档
https://www.keepalived.org/doc/
软件架构

2.2 Keepalived + LVS 高可用
集群规划
| 服务 |
网络接口 |
IP地址 |
| DS1 |
eth0 |
172.16.1.5 |
| DS2 |
eth0 |
172.16.1.6 |
| RS1 |
eth0 |
172.16.1.7 |
|
lo:0 |
172.16.1.100 |
| RS2 |
eth0 |
172.16.1.8 |
|
lo:0 |
172.16.1.100 |
| VIP |
|
172.16.1.100 |
2.2.1 DS节点配置
keepalived配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| global_defs { router_id lb01 } vrrp_instance VI_1 { state MASTER priority 100 interface eth1 virtual_router_id 50 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 172.16.1.3 label eth1:0 } } # 配置集群地址访问的IP+Port virtual_server 172.16.1.100 80 { # 健康检查的时间,单位:秒 delay_loop 6 # 配置负载均衡的算法 wlc|nq|lblc|lblcr lb_algo wlc # 设置LVS的模式 NAT|TUN|DR lb_kind DR # 设置会话持久化的时间 perssisstence_timeout 5 # 设置协议 protocol TCP # 负载均衡后端的真实服务节点RS-1 real_server 172.16.1.7 80 { # 权重配比设置 weight -30 # 设置健康检查 TCP_CHECK { # 检测后端80端口 connect_port 80 # 超时时间 connect_timeout 3 # 重试次数2次 nb_get_retry 2 # 间隔时间3s delay_beefore_retry 3 } }
# 负载均衡后端的真实服务节点RS-2 real_server 172.16.1.8 80 { # 权重配比设置 weight -30 # 设置健康检查 TCP_CHECK { # 检测后端80端口 connect_port 80 # 超时时间 connect_timeout 3 # 重试次数2次 nb_get_retry 2 # 间隔时间3s delay_beefore_retry 3 } } }
|
关于priority和weight
1 2 3 4 5 6 7
| priority: 为默认权重值,一般master要大于back,权重值还和weight有关,当检测失败时候,priority会和weight相加或者相减,得到一个新的权重值 weight: 绝对值要大于两台priority的差值
vrrp_script中weight: 如果weight值为正: 切换机制为,当mater检测失败,master的priority值不变,back的权重值为priority+weight,master的权重小于back的权重,进行切换
如果weight值为负: 切换机制为,当master检测失败,master的权重值为priority-weight的值,back的权重值不变,master的权重值小于back,进行切换
|
主从参数:
| 参数 |
master节点 |
backup节点 |
| router_id |
lb-01 |
lb-02 |
| state |
MASTER |
BACKUP |
| priority |
100 |
90 |
sysctl.conf配置
1 2
| # 启用FORWARD转发功能,实现路由功能 net.ipv4.ip_forward = 1
|
2.2.2 RS节点配置
sysctl.conf配置
1 2 3 4 5 6 7 8 9 10 11
| cat > /etc/sysctl.cof << 'EOF'
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 EOF sysctl -p
|
网卡配置
1 2 3 4 5 6 7 8 9
| cat > /etc/sysconfig/network-scripts/ifcfg-lo:0 << EOF DEVICE=lo:0 IPADDR=172.16.1.100 NETMASK=255.255.0.0 ONBOOT=yes NAME=loopback EOF
ifdown lo:0 && ifup lo:0
|
2.3 Keepalived + NGINX 高可用
2.3.1 nginx配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| cat >> /etc/nginx/nginx.conf << "EOF"
stream { log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent'; access_log /var/log/nginx/upstream-access.log main; upstream www { ip_hash; server 192.168.2.101:8001; server 192.168.2.102:8001; }
server { listen 8001; proxy_pass www; } } EOF
|
2.3.2 Keepalived配置
主
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| cat > /etc/keepalived/keepalived.conf << "EOF" global_defs { notification_email { www.localhost.com } notification_email_from www.localhost.com router_id master }
vrrp_script check_http { script "</dev/tcp/127.0.0.1/8001" #修改为自己需要监听的端口,理论上可以监听远程端口 interval 2 #检查脚本的频率,单位(秒) weight -30 #端口检查失败,优先级减少30,weight的绝对值要大于两台priority的差值 }
vrrp_instance VI_1 { state MASTER interface ens33 # 修改为实际网卡名 virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的 priority 100 # 优先级,备服务器设置 90 advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒 authentication { auth_type PASS auth_pass 123456 } # VIP virtual_ipaddress { 192.168.2.100/24 label ens33:0 } track_script { check_http } } EOF
|
备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| cat > /etc/keepalived/keepalived.conf << EOF global_defs { notification_email { www.localhost.com } notification_email_from www.localhost.com router_id backup }
vrrp_script check_http { script "</dev/tcp/127.0.0.1/8001" #修改为自己需要监听的端口,理论上可以监听远程端口 interval 2 #检查脚本的频率,单位(秒) weight -30 #端口检查失败,优先级减少30,weight的绝对值要大于两台priority的差值 }
vrrp_instance VI_1 { state BACKUP interface ens33 # 修改为实际网卡名 virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的 priority 90 # 优先级,备服务器设置 90 advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒 authentication { auth_type PASS auth_pass 123456 } # VIP virtual_ipaddress { 192.168.2.100/24 label ens33:0 } track_script { check_http } } EOF
|
两个重要的值: priority和weight
1 2 3 4 5 6 7
| priority: 为默认权重值,一般master要大于back,权重值还和weight有关,当检测失败时候,priority会和weight相加或者相减,得到一个新的权重值 weight: 绝对值要大于两台priority的差值
vrrp_script中weight: 如果weight值为正: 切换机制为,当mater检测失败,master的priority值不变,back的权重值为priority+weight,master的权重小于back的权重,进行切换
如果weight值为负: 切换机制为,当master检测失败,master的权重值为priority-weight的值,back的权重值不变,master的权重值小于back,进行切换
|
2.3.3 防火墙配置
开启防火墙端口112, 协议vrrp
1 2
| iptables -A INPUT -p 112 -j ACCEPT iptables -A INPUT -p vrrp -jACCEPT //这里不开启vrrp协议的端口,会造成backup服务器检测不到master服务器的是否正常而自动启动backup的应用服务
|
2.4 Keepalived检测机制
状态检测
- 通过脚本实现
- 主要针对本机服务本身(比如Keepalived服务, NGINX负载均衡服务等)
- 常用于Keepalived+NGINX
VRRP script配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| # 定义NGINX服务检测脚本 vrrp_script check_nginx { script "/bin/bash /data/scripts/check_nginx.sh" # cheaper than pidof interval 2 # check every 2 seconds # weight -2 # default prio: -4 if KO # fall 2 # require 2 failures for KO # rise 2 # require 2 successes for OK }
# 使用 vrrp_instance VI_1 { ... track_script { check_nginx } } 注意: 检测命令的<SCRIPT_NAME>是VRRP专用的, 一定要保证在VRRP场景下是唯一的 script属性要求尽量使用脚本格式, 不包含特殊字符和表达是的简单命令也可以, 如果命令里包含特殊字符, 就不能执行
|
模版文件: keepalived.conf.vrrp.localcheck
脚本示例
1 2 3 4 5 6
| cat /data/scripts/check_nginx.sh
nginx=`netstat -tnlp | grep 80 | grep nginx | wc -l` if [ "$nginx" -eq 0 ];then weight -30 fi
|
健康检测
- 通过默认检测方式检测
- 主要针对后端服务(如web服务)
- 适用于Keepalived+LVS
模版文件: keepalived.conf.HTTP_GET.port keepalived.conf.status_code等
主机检测属性(常用)
1 2 3 4 5 6
| weight 设定真是主机的权重, 默认是1 HTTP_GET 以HTTP方式来检查后端主机 TCP_CHECK 以TCP方式来检查后端主机 SMTP_CHECK 以SMTP方式来检查后端主机 DNS_CHECK 以DNS方式来检查后端主机 MISC_CHECK 以MISC方式来检查后端主机
|
2.5 Keepalived双主模式
做两个vrrp_instance, 交叉主备