LVS目前除了本身的NAT、DR和TUN模式,还有淘宝开源的fullnat模式,个人了解(待确认)LVS在各大公司的使用情况是:
百度 – BVS(现淘宝的 普空 之前在百度搞得类似fullnat项目,未开源) 结构是fullnat模式+ospf等价多路径
阿里 – LVS(fullnat模式,已开源)结构是fullnat模式+ospf等价多路径,通过交换机ospf的一直性hash来避免session不一致的情况
腾讯 – TWG(也是类似于fullnat的项目,未开源)结构是fullnat模式+ospf等价多路径,通过LVS集群定期同步来实现session一致
LVS在小米的业务前端已经使用几年时间,从最开始的DR模式,到现在部分使用fullnat模式,整体上还是不错的:
DR模式下:CPU E3-1230 V2 @ 3.30GHz + 32G + Intel 82580 Gb网卡 + sata盘:单台极限pps能跑到接近200W,应对电商的抢购活动完全没有压力
但最近也现一些问题:抢购时入站流量将Gb网卡跑满,导致丢包;在HA模式下,主机宕机之后需要advert_int 秒(keepalived 配置项)来切换至备机,也就是说在切换的过程中,服务是不可用的;而且现有结构下,无法线性横向扩展(一个VIP只能由一台服务来提供服务),只能通过提升机器配置来应对流量的上涨
为了解决上面这些问题,所以我们开始尝试LVS(DR)通过ospfd,做lvs集群,实现一个VIP,多台LVS同时工作提供服务,不存在热备机器,如图:
用户请求(VIP:42.xx.xx.100)到达三层交换机之后,通过对原地址、端口和目的地址、端口的hash,将链接分配到集群中的某一台LVS上,LVS通过内网(10.101.10.x)向后端转发请求,后端再将数据返回给用户,整个会话完成
Cluser模式的最大优势就在于:
- LVS调度机自由伸缩,横向线性扩展(最多机器数受限于三层设备允许的等价路由数目 maximum load-balancing );
- LVS机器同时工作,不存在备机,提高利用率;
- 做到了真正的高可用,某台LVS机器宕机后,不会影响服务(但因为华3设备ospfd调度算法的问题,一台宕机会使所有的长连接的断开重连,目前还无法解决;思科的设备已经支持一至性哈希算法,不会出现这个问题)。
部署过程:
1. 配置三层设备的ospf(这里以华3的设备为例):
交换机与LVS机器互连的端口号分别为2/9/0/19 2/9/0/20 2/9/0/21
1
2
3
4
5
6
7
8
9
10
11
12
13
|
interface
GigabitEthernet2
/
9
/
0
/
19
//交换机与LVS机器连接的端口
port
link
-
mode
route
//路由接口
ip
address
10.21.21.1
255.255.255.252
ospf
timer
hello
1
ospf
timer
dead
4
ospf
network
-
type
p2p
//OSPF网络类型
ospf
2
router
-
id
10.21.254.253
//进程ID 路由ID
default
-
route
-
advertise
always
//始终下发默认路由
maximum
load
-
balancing
6
//定义最大的ECMP条目,也就是最多能连接的LVS数量
area
0.0.0.0
//区域IP
network
10.21.21.0
0.0.0.3
network
10.21.21.4
0.0.0.3
network
10.21.21.8
0.0.0.3
|
第二个端口:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
interface
GigabitEthernet2
/
9
/
0
/
20
//交换机与LVS机器连接的端口
port
link
-
mode
route
//路由接口
ip
address
10.21.21.5
255.255.255.252
ospf
timer
hello
1
ospf
timer
dead
4
ospf
network
-
type
p2p
//OSPF网络类型
ospf
2
router
-
id
10.21.254.253
//进程ID 路由ID
default
-
route
-
advertise
always
//始终下发默认路由
maximum
load
-
balancing
6
//定义最大的ECMP条目
area
0.0.0.0
//区域IP
network
10.21.21.0
0.0.0.3
network
10.21.21.4
0.0.0.3
network
10.21.21.8
0.0.0.3
|
第三个端口:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
interface
GigabitEthernet2
/
9
/
0
/
20
//交换机与LVS机器连接的端口
port
link
-
mode
route
//路由接口
ip
address
10.21.21.9
255.255.255.252
ospf
timer
hello
1
ospf
timer
dead
4
ospf
network
-
type
p2p
//OSPF网络类型
ospf
2
router
-
id
10.21.254.253
//进程ID 路由ID
default
-
route
-
advertise
always
//始终下发默认路由
maximum
load
-
balancing
6
//定义最大的ECMP条目
area
0.0.0.0
//区域IP
network
10.21.21.0
0.0.0.3
network
10.21.21.4
0.0.0.3
network
10.21.21.8
0.0.0.3
|
2. LVS的ospf配置:
LVS机器两张网卡,一个与交换机用做ospf互连,一个与内网连接
安装ospf软件:
1
|
yum
–
y
install
quagga
|
a.配置zerba.conf
1
|
vim
/
etc
/
quagga
/
zebra
.
conf
|
1
2
3
|
hostname
lvs
-
p1
###这个名字每台要不一样,另外两台用的p2和p3
password
xxxxxx
enable
password
xxxxxx
|
b.配置ospfd.conf
与交换机的通讯主要是这个进程,通过它将自己的VIP(42.xx.xx.100)声明出去
1
|
vim
/
etc
/
quagga
/
ospfd
.
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
|
hostname
lvs
-
p1
### 另外两台用的p2和p3
password
8
5ubmJdMAQxXbs
### 这个密码是123456
enable
password
8
4fcJB8NFa.0v6
log
stdout
log
syslog
service
password
-
encryption
!
!
interface
eth0
!
interface
eth1
ip
ospf
network
point
-
to
-
point
ip
ospf
hello
-
interval
1
ip
ospf
dead
-
interval
4
!
interface
lo
!
router
ospf
ospf
router
-
id
10.21.21.2
###各台的ID不能一样,这里我用的ospf互联地址做为ID,另外两台使用10.21.21.6 和10
log
-
adjacency
-
changes
!
Important
:
ensure
reference
bandwidth
is
consistent
across
all
routers
auto
-
cost
reference
-
bandwidth
1000
network
10.21.21.2
/
30
area
0.0.0.0
###这里是宣告自己的ospf互连地址和VIP地址,新增地址就是在这里添加
network
42.xx.xx.100
/
32
area
0.0.0.0
!
line
vty
!
|
其它的LVS机器ospf的配置修改一下hostname和 ospf router-id就可以了
开启转发:
1
2
|
echo
"net.ipv4.ip_forward = 1"
>>
/
etc
/
sysctl
.
conf
sysctl
–
p
|
开启服务:
1
2
|
/
etc
/
init
.
d
/
zebra
start
/
etc
/
init
.
d
/
ospfd
start
|
1
2
3
4
5
6
|
[
root
@
lg
-
pt
-
lvs02
~
]
# netstat -lntpu
Active
Internet
connections
(
only
servers
)
Proto
Recv
-
Q
Send
-
Q
Local
Address
Foreign
Address
State
PID
/
Program
name
tcp
0
0
127.0.0.1
:
2604
0.0.0.0
:
*
LISTEN
27071
/
ospfd
tcp
0
0
0.0.0.0
:
22
0.0.0.0
:
*
LISTEN
1596
/
sshd
tcp
0
0
127.0.0.1
:
2601
0.0.0.0
:
*
LISTEN
27006
/
zebra
|
可以看到这两个进程都启起来了;系统日志里,可以看到
说明已经找到ospf邻居,正常宣告地址了
再在每台机器的LO上绑上宣告的VIP:
1
|
vi
/
etc
/
sysconfig
/
network
-
scripts
/
ifcfg
-
lo
:
01
|
1
2
3
4
5
6
|
#for lvs-dr-real-server
DEVICE
=
lo
:
01
IPADDR
=
42.xx.xx.100
NETMASK
=
255.255.255.255
ONBOOT
=
yes
#
|
这时候可以ping一下42.xx.xx.100这个地址,能通就说明ospf已经配置成功了
在测试时遇到一个问题,我们在LVS机器上新添加地址时,需要Reload ospfd这个进程,查看启动脚本,他里面的Reload就是stop再start,所有宣告的IP会断开,再启起来
但是通过telnet 连接机器的ospfd管理端口添加新地址会立即生效,且不影响现有的IP,所以写了个脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#!/bin/bash
$
ip
=
$
1
pswd
=
"123456"
expect
-
c
" set timeout 30
eval spawn -noecho telnet 127.0.0.1 2604
expect \"
Password
:
\"
send
\"
$
pswd
\
r
\"
expect
\"
*
>
\"
send
\"
enable
\
r
\"
expect
\"
Password
:
\"
send
\"
$
pswd
\
r
\"
expect
\"
*
#\"
send
\"
configure
t
\
r
\"
expect
\"
*
(
config
)
#\"
send
\"
router
ospf
\
r
\"
expect
\"
*
(
config
-
router
)
#\"
send
\"
network
$
ip
/
32
area
0.0.0.0
\
r
\"
expect
\"
*
(
config
-
router
)
#\"
send
\"
w
\
r
\"
send
\"
exit
\
r
\"
send
\"
exit
\
r
\"
send
\"
exit
\
r
\"
interact"
>
/
dev
/
null
|
保存为addip.sh;
这里是需要先安装expect,再执行:
1
2
|
yum
-
y
install
expect
sh
addip
.
sh
x
.
x
.
x
.
x(
IP)就可以直接添加宣告
VIP,不用
Reload
ospfd进程了
|
Quagga软件还提供了类似supervise的进程监控软件watchquagga,可以监控并重启本机的zebra和ospfd进程,下面使用watchquagga来启zebra和ospfd服务:
1
2
|
killall
zebra
ospfd
#先把这两个进程停了
watchquagga
-
adz
-
r
'/sbin/service %s restart'
-
s
'/sbin/service %s start'
-
k
'/sbin/service %s stop'
zebra
ospfd
|
大家可以手动kill掉ospf进程测试一下:
3. 接下来就是LVS(DR)的配置:
1
|
yum
-
y
install
keepalived
ipvsadm
|
因为使用了ospf来选择路由,LVS上所有的VIP是用32位掩码绑在lo的网卡上的,所以在配置keepalived.conf时,主配置项vrrp_instance、等都不需要了,只需要配置virtual_server对应的后端就行了
我们服务器上就只配置了:
1
|
vi
/
etc
/
keepalived
/
keepalived
.
conf
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
virtual_server
42.xx.xx.100
80
{
delay_loop
6
lb_algo
wlc
lb_kind
DR
protocol
TCP
real_server
10.101.10.14
80
{
weight
6
TCP_CHECK
{
connect_port
80
connect_timeout
20
nb_get_retry
3
delay_before_retry
5
}
}
}
|
三台LVS的keepalived配置完全一至,再启动keepalived:
1
|
/
etc
/
init
.
d
/
keepalived
start
|
然后再到后端的realserver上把VIP绑到LO网卡上,
1
|
vi
/
etc
/
sysconfig
/
network
-
scripts
/
ifcfg
-
lo
:
01
|
1
2
3
4
5
6
|
#for lvs-dr-real-server
DEVICE
=
lo
:
01
IPADDR
=
42.xx.xx.100
NETMASK
=
255.255.255.255
ONBOOT
=
yes
#
|
1
|
ifup
lo
:
01
|
再打开转发:
1
2
|
echo
"net.ipv4.ip_forward = 1"
>>
etc
/
sysctl
.
conf
sysctl
–
p
|
到此就都配置完成了,用户访问42.xx.xx.100这个IP,会落到10.101.10.14这台realserver上,再直接返回给用户