Linux运维架构之LVS+Keepalived 实现高可用负载均衡

keepalived介绍

keepalived软件起初是专为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点状态,后来又加入了可以实现高可用的VRRP功能.此,keepalived除了能够管理LVS软件外,还可以作为其他服务(例如:Nginx,Haproxy,MySQL等)的高可用解决方案软件。

VRRP(Virtual Router Redundancy Protocol)虚拟路由器冗余协议,是一种容错的主备模式的协议,保证当主机的下一跳路由出现故障时,由另一台路由器来代替出现故障的路由器进行工作,通过VRRP可以在网络发生故障时透明的进行设备切换而不影响主机之间的数据通信。

Keepalived软件主要是通过VRRP协议实现高可用功能,在安装keepalived的服务器主机上会在配置文件中设置一个虚拟IP,当该keepalived节点为主节点且正常运行时,设置的虚拟Ip就会在该节点生效且绑定在该主机的网卡上,而其他备用主机设置的虚拟IP就不会生效。当测到主keepalived节点出现故障时,备用keepalived节点检会进行抢占提供服务,抢占成功的keepalived节点就会将配置的虚拟IP绑定在自己的网卡上,这样对外部用户来说虚拟IP提供的服务是一直可用的,当故障服务器被修复后可以正常工作时Keepalived会自动的将该服务器加入到服务器群中。在整个过程中,故障检测、故障服务器剔除以及修复后的服务器重新上线这些操作都是由keepalived自动完成,运维人员只需要关注故障服务器的修复。

安装keepalived环境说明

1
2
3
[root@lb01 ~]# yum install keepalived -y
[root@lb01 ~]# rpm -qa keepalived
keepalived-1.3.5-8.el7_6.x86_64

keepalived配置

keepalived配置文件一般在/etc/keepalived/keepalived.conf下

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# 全局配置
global_defs {
# 邮件通知信息
notification_email {
# 定义收件人
acassen@firewall.loc
}
# 定义发件人
notification_email_from Alexandre.Cassen@firewall.loc
# SMTP服务器地址
smtp_server 192.168.200.1
smtp_connect_timeout 30
# 路由器标识,一般不用改,也可以写成每个主机自己的主机名
router_id LVS_DEVEL
# VRRP的ipv4和ipv6的广播地址,配置了VIP的网卡向这个地址广播来宣告自己的配置信息,下面是默认值
vrrp_mcast_group4 224.0.0.18
vrrp_mcast_group6 ff02::12
}

# 定义用于实例执行的脚本内容,比如可以在线降低优先级,用于强制切换
vrrp_script SCRIPT_NAME {

}

# 一个vrrp_instance就是定义一个虚拟路由器的,实例名称
vrrp_instance VI_1 {
# 定义初始状态,可以是MASTER或者BACKUP
state MASTER
# 工作接口,通告选举使用哪个接口进行
interface ens33
# 虚拟路由ID,如果是一组虚拟路由就定义一个ID,如果是多组就要定义多个,而且这个虚拟
# ID还是虚拟MAC最后一段地址的信息,取值范围0-255
virtual_router_id 51
# 使用哪个虚拟MAC地址
use_vmac XX:XX:XX:XX:XX
# 监控本机上的哪个网卡,网卡一旦故障则需要把VIP转移出去
track_interface {
eth0
ens33
}
# 如果你上面定义了MASTER,这里的优先级就需要定义的比其他的高
priority 100
# 通告频率,单位为秒
advert_int 1
# 通信认证机制,这里是明文认证还有一种是加密认证
authentication {
auth_type PASS
auth_pass 1111
}
# 设置虚拟VIP地址,一般就设置一个,在LVS中这个就是为LVS主机设置VIP的,这样你就不用自己手动设置了
virtual_ipaddress {
# IP/掩码 dev 配置在哪个网卡
192.168.200.16/24 dev eth1
# IP/掩码 dev 配置在哪个网卡的哪个别名上
192.168.200.17/24 dev label eth1:1
}
# 虚拟路由,在需要的情况下可以设置lvs主机 数据包在哪个网卡进来从哪个网卡出去
virtual_routes {
192.168.110.0/24 dev eth2
}
# 工作模式,nopreempt表示工作在非抢占模式,默认是抢占模式 preempt
nopreempt|preempt
# 如果是抢占默认则可以设置等多久再抢占,默认5分钟
preempt delay 300
# 追踪脚本,通常用于去执行上面的vrrp_script定义的脚本内容
track_script {

}
# 三个指令,如果主机状态变成Master|Backup|Fault之后会去执行的通知脚本,脚本要自己写
notify_master ""
notify_backup ""
notify_fault ""
}

# 定义LVS集群服务,可以是IP+PORT;也可以是fwmark 数字,也就是防火墙规则
# 所以通过这里就可以看出来keepalive天生就是为ipvs而设计的
virtual_server 10.10.10.2 1358 {
delay_loop 6
# 算法
lb_algo rr|wrr|lc|wlc|lblc|sh|dh
# LVS的模式
lb_kind NAT|DR|TUN
# 子网掩码,这个掩码是VIP的掩码
net_mask 255.255.255.0
# 持久连接超时时间
persistence_timeout 50
# 定义协议
protocol TCP
# 如果后端应用服务器都不可用,就会定向到那个服务器上
sorry_server 192.168.200.200 1358

# 后端应用服务器 IP PORT
real_server 192.168.200.2 1358 {
# 权重
weight 1
# 应用服务器UP或者DOWN,就执行那个脚本
notify_up "这里写的是路径,如果脚本后有参数,整体路径+参数引起来"
notify_down "/PATH/SCRIPTS.sh 参数"

# MSIC_CHECK|SMTP_CHEKC|TCP_CHECK|SSL_GET|HTTP_GET这些都是
# 针对应用服务器做健康检查的方法
MISC_CHECK {}
# 用于检查SMTP服务器的
SMTP_CHEKC {}

# 如果应用服务器不是WEB服务器,就用TCP_CHECK检查
TCP_CHECK {
# 向哪一个端口检查,如果不指定默认使用上面定义的端口
connect_port <PORT>
# 向哪一个IP检测,如果不指定默认使用上面定义的IP地址
bindto <IP>
# 连接超时时间
connect_timeout 3
}

# 如果对方是HTTPS服务器就用SSL_GET方法去检查,里面配置的内容和HTTP_GET一样
SSL_GET {}

# 使用HTTP_GET方法去检查
HTTP_GET {
# 检测URL
url {
# 具体检测哪一个URL
path /testurl/test.jsp
# 检测内容的哈希值,也就是网页的md5值
digest 640205b7b0fc66c1ea91c463fac6334d
# 除了检测哈希值还可以检测状态码,比如HTTP的200 表示正常,两种方法二选一即可
status_code 200
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
# 向哪一个端口检查,如果不指定默认使用上面定义的端口
connect_port <PORT>
# 向哪一个IP检测,如果不指定默认使用上面定义的IP地址
bindto <IP>
# 连接超时时间
connect_timeout 3
# 尝试次数
nb_get_retry 3
# 每次尝试之间间隔几秒
delay_before_retry 3
}
}

real_server 192.168.200.3 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
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
! Configuration File for keepalived
global_defs {
# 定义故障服务报警的Email地址,作用是服务发生切换或RS节点等有故障时,需要发送的Email地址,可以有多个,每行一个
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# 制定发送邮件的发送人,即发送人地址,也是可选配置
notification_email_from Alexandre.Cassen@firewall.loc
# 指定发送邮件的smtp服务器
smtp_server 192.168.200.1
# 连接smtp的超时时间,也是可选配置
smtp_connect_timeout 30
#路由id,全局唯一,表示当前keepalived节点的唯一性
router_id lb01
}
# 定义一个vrrp_instance实例,名字为VI_1
vrrp_instance VI_1 {
#设置当前实例状态为MASTER。MASTER代表是主实例,BACKUP代表是备用实例
state MASTER
#当前实例绑定的网卡
interface eth0
#当前实例的虚拟路由id,一组主备的实例的路由id是相同的
virtual_router_id 51
#当前实例的优先级
priority 150
#主备之间同步检查时间间隔
advert_int 1
#一组主备实例的认证密码,方式非法节点进入路由组
authentication {
auth_type PASS
auth_pass 1111
}
#设置当前实例的虚拟IP
virtual_ipaddress {
10.1.1.50/24
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
! Configuration File for keepalived
global_defs {
#由于是全局唯一Id,所有需要与master保持不同
router_id lb02
}

vrrp_instance VI_1 {
#备用实例状态应设置为BACKUP
state BACKUP
interface eth0
virtual_router_id 51
#设置备用实例的优先级低于主实例,这样可保证在主实例故障修复后可以再次将主节点抢占回来
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.1.1.50/24
}
}

启动并检查

1
2
3
4
systemctl start keepalived
systemctl enable keepalived

ip addr|grep 10.1.1.50

lvs简介

LVS,全称Linux Virtual Server,是国人章文嵩发起的一个开源项目。
在社区具有很大的热度,是一个基于四层、具有强大性能的反向代理服务器。
早期使用lvs需要修改内核才能使用,但是由于性能优异,现在已经被收入内核。

通用体系结构

LVS的一些相关术语:

LVS的模型中有两个角色:
调度器: Director,又称为Dispatcher,Balancer
调度器主要用于接受用户请求。
**真实主机:**Real Server,简称为RS。
用于真正处理用户的请求。

而为了更好地理解,我们将所在角色的IP地址分为以下三种:
**Director Virtual IP:**调度器用于与客户端通信的IP地址,简称为VIP
Director IP:调度器用于与RealServer通信的IP地址,简称为DIP。
Real Server : 后端主机的用于与调度器通信的IP地址,简称为RIP。

img

LVS的三种调度模式

LVS-NAT模式

​ NAT模式称为全称Virtualserver via Network address translation(VS/NAT),是通过网络地址转换的方法来实现调度的。首先调度器(Director)接收到客户的请求数据包时(请求的目的IP为VIP),根据调度算法决定将请求发送给哪个后端的真实服务器(RS)。然后调度就把客户端发送的请求数据包的目标IP地址及端口改成后端真实服务器的IP地址(RIP),这样真实服务器(RS)就能够接收到客户的请求数据包了。真实服务器响应完请求后,查看默认路由(NAT模式下我们需要把RS的默认路由设置为DS服务器。)把响应后的数据包发送给DS,DS再接收到响应包后,把包的源地址改成虚拟地址(VIP)然后发送回给客户端。

具体工作流程:

LVS-NAT

原理:

基于ip伪装MASQUERADES,原理是多目标DNAT。
所以请求和响应都经由Director调度器。

LVS-NAT的优点与缺点

优点:

  • 支持端口映射
  • RS可以使用任意操作系统
  • 节省公有IP地址。
    RIP和DIP都应该使用同一网段私有地址,而且RS的网关要指向DIP。
    使用nat另外一个好处就是后端的主机相对比较安全。

缺点:

  • 请求和响应报文都要经过Director转发;极高负载时,Director可能成为系统瓶颈。
    就是效率低的意思。

LVS-TUN(IP隧道)

在LVS(NAT)模式的集群环境中,由于所有的数据请求及响应的数据包都需要经过LVS调度器转发,如果后端服务器的数量大于10台,则调度器就会成为整个集群环境的瓶颈。我们知道,数据请求包往往远小于响应数据包的大小。因为响应数据包中包含有客户需要的具体数据,所以LVS(TUN)的思路就是将请求与响应数据分离,让调度器仅处理数据请求,而让真实服务器响应数据包直接返回给客户端。LVS/TUN工作模式拓扑结构如图所示。其中,IP隧道(IP tunning)是一种数据包封装技术,它可以将原始数据包封装并添加新的包头(内容包括新的源地址及端口、目标地址及端口),从而实现将一个目标为调度器的VIP地址的数据包封装,通过隧道转发给后端的真实服务器(Real Server),通过将客户端发往调度器的原始数据包封装,并在其基础上添加新的数据包头(修改目标地址为调度器选择出来的真实服务器的IP地址及对应端口),LVS(TUN)模式要求真实服务器可以直接与外部网络连接,真实服务器在收到请求数据包后直接给客户端主机响应数据。

TUN

原理

基于隧道封装技术。在IP报文的外面再包一层IP报文。
当Director接收到请求的时候,选举出调度的RealServer
当接受到从Director而来的请求时,RealServer则会使用lo接口上的VIP直接响应CIP。
这样CIP请求VIP的资源,收到的也是VIP响应。

LVS-TUN的优点与缺点

优点:
  • RIP,VIP,DIP都应该使用公网地址,且RS网关不指向DIP;
    只接受进站请求,解决了LVS-NAT时的问题,减少负载。
    请求报文经由Director调度,但是响应报文不需经由Director。
缺点:
  • 不指向Director所以不支持端口映射。
  • RS的OS必须支持隧道功能。
  • 隧道技术会额外花费性能,增大开销。

LVS-DR模式

全称:Virtual Server via Direct Routing(VS-DR),也叫直接路由模式,用直接路由技术实现虚拟服务器。当参与集群的计算机和作为控制管理的计算机在同一个网段时可以用此方法,控制管理的计算机接收到请求包时直接送到参与集群的节点。直接路由模式比较特别,很难说和什么方面相似,前种模式基本上都是工作在网络层上(三层),而直接路由模式则应该是工作在数据链路层上(二层)。

img

原理

当Director接收到请求之后,通过调度方法选举出RealServer。
讲目标地址的MAC地址改为RealServer的MAC地址。
RealServer接受到转发而来的请求,发现目标地址是VIP。RealServer配置在lo接口上。
处理请求之后则使用lo接口上的VIP响应CIP。

LVS-DR的优点与缺点

优点:
  • RIP可以使用私有地址,也可以使用公网地址。
    只要求DIP和RIP的地址在同一个网段内。
  • 请求报文经由Director调度,但是响应报文不经由Director。
  • RS可以使用大多数OS
缺点:
  • 不支持端口映射。
  • 不能跨局域网。

总结

三种模型虽然各有利弊,但是由于追求性能和便捷,DR是目前用得最多的LVS模型。

LVS的八种调度方法

静态方法:仅依据算法本身进行轮询调度

  • RR:Round Robin,轮询调度
    一个接一个,自上而下
  • WRR:Weighted RR,加权轮询调度
    加权,手动让能者多劳。
  • SH:SourceIP Hash 源地址散列调度
    来自同一个IP地址的请求都将调度到同一个RealServer
  • DH:Destination Hash 目标地址散列调度
    不管IP,请求特定的东西,都定义到同一个RS上。

动态方法:根据算法及RS的当前负载状态进行调度

  • LC:least connections(最小链接数)
    链接最少,也就是Overhead最小就调度给谁。
    假如都一样,就根据配置的RS自上而下调度。

  • WLC:Weighted Least Connection (加权最小连接数)
    各个服务器相应的权值表示其处理性能。服务器的缺省权值为1,系统管理员可以动态地设置服务器的权值

  • SED:Shortest Expection Delay(最小期望延迟)
    WLC算法的改进。

  • NQ:Never Queue 最少队列调度
    SED算法的改进,无需队列。如果有realserver的连接数等于0就直接分配过去

  • LBLC:Locality-Based Least-Connection,基于局部的的LC算法

    算法是针对请求报文的目标IP地址的 负载均衡调度,目前主要用于Cache集群系统,因为在Cache集群客户请求报文的目标IP地址是变化的。这里假设任何后端服务器都可以处理任一请求,算法的设计目标是在服务器的负载基本平衡情况下,将相同目标IP地址的请求调度到同一台服务器,来提高各台服务器的访问局部性和Cache命中率,从而提升整个集群系统的处理能力。LBLC调度算法先根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则使用’最少连接’的原则选出一个可用的服务器,将请求发送到服务器。

  • LBLCR:Locality-Based Least-Connection with Replication(带复制的lblc算法)

    算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统,它与LBLC算法不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。按’最小连接’原则从该服务器组中选出一一台服务器,若服务器没有超载,将请求发送到该服务器;若服务器超载,则按’最小连接’原则从整个集群中选出一台服务器,将该服务器加入到这个服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。

keepalived配合LVS高可用

配置LVS-DR

主机名主机地址角色
lb0110.1.1.11 ,VIP:10.1.1.50LVS+keepalived主(Director)
lb0210.1.1.12 ,VIP:10.1.1.50LVS+keepalived备(Director)
node110.1.1.15Nginx(RealServer)
node210.1.1.16Nginx(RealServer)

设置后端服务器

在RealServer中修改ARP内核参数

由于LVS服务器和后端服务器的网卡上都配置了VIP,那么当客户端联系VIP的时候肯定是和LVS服务器的VIP进行通信,然后由LVS服务器基于规则进行调度,我们知道2层通信是基于MAC地址的,那么首次通信时客户端可能并不知道LVS服务器的MAC地址,那么就需要进行ARP广播来解析出VIP所在的服务器的MAC地址,那么显然对客户端进行ARP应答的只能是LVS服务器不能是后端服务器,所以我们就要在后端上修改内核参数来禁止ARP应答和宣告。那么有2个内核参数表示这两个设置:

arp_ignore:表示接收到ARP广播时的响应级别,默认值为0

  • 0 默认值,表示响应所有,只要对方查询的IP配置在我自己这台主机上且无论ARP请求从哪个网卡进来,该主机都会响应
  • 1 表示收到该ARP请求的网卡IP与ARP请求的IP一致,该主机才响应

arp_announce:定义将自己的地址向外通告的级别,默认是0

  • 0 表示将本机所有的MAC地址都向外通告
  • 1 表示多网卡主机且都配置了IP地址,那么该主机接入到网络时,无论哪个网卡接入到网络,该网卡都会向外宣告自己所有的MAC地址,所以1表示如果IP不在这个接口上,就避免向外通告,但是不保证一定不会下外通告。
  • 2 表示仅向网卡IP直连的网络进行通告

为什么会有这些级别呢?因为主机可以有多个网卡,每个网卡都对应一个网段,默认情况下这个多网卡主机只要接入网络它就会把自己所在的所有网络地址都向外进行通告。

所以对于后端服务器,也就是本例子中的Nginx,我们应该在lo上配置子接口,且设置arp_ignore为1,arp_announce为2。

1
2
3
4
5
echo "1" > /proc/sys/net/ipv4/ip_forward
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce

Keepalive配置