Ceph入门到精通-基于ECMP的多活负载均衡策略

本文简单介绍一下,如何基于ECMP,使用Quagga+LVS+Keepalived构建多活负载均衡方案

1. 背景介绍

负载均衡,主要用于大规模分布式集群下,提供高性能服务。为了给负载均衡器提供高可用,一般利用主备或者主主模式实现。主备模式即只有主负载均衡器提供负载均衡功能,当主负载均衡器出现异常时,自动切换到备负载均衡器,继续提供负载均衡功能。主主模式(也称之为双活负载均衡),两个负载均衡器同时提供负载均衡服务,全部为主模式,流量均摊到两个负载均衡设备。本文基于LVS+OSPF+Keepalived搭建了一套多活负载均衡。

1.1 LVS

LVS(Linux Virtual Server)即linux虚拟服务器。是一个虚拟的服务器集群系统,讲发送给VIP的请求,转发给对应的后端服务器。从而起到负载均衡的作用。后端服务器处理完请求,将结果返还给用户。LVS主要通过工作在linux内核层的ipvs来实现。而对于ipvs,我们可以用ipvsadm来进行配置。ipvsadm工作
在用户空间,ipvs工作在内核空间。ipvsadm和ipvs的关系就好比是iptables和netfilter的关系。综上所述,LVS由两部分组成,ipvs和ipvsadm

ipvsadm: LVS管理工具,通过ipvsadm定义和管理集群规则。
ipvs:LVS核心实现,根据定义好的集群规则进行工作。

注: LVS为四层负载均衡,基于ip和端口进行转发。

1.2 OSPF/ECMP

OSPF,开放式最短路径优先协议,一种基于链路状态的内部网关协议。每个OSPF路由器都包含了整个网络的拓扑。并计算通过网络的最短路径。OSPF会通过多播的方式自动对外传播检测到的网络变化。

RIP,即路由信息协议,是一个老的协议。RIP路由器向网络中周期性多播它的整个路由表,而不像ospf只多播网络的变化。RIP通过跳数来测量路由,任何超过15跳的路由,都被视为不可达。

ECMP:等价多路径协议。即当存在多条不同的链路到达同一目的地址时,利用ECMP可以同时使用多条链路,不仅增加了传输带宽,还可以无时延、无丢包的备份失效链路的数据传输。如果利用传统的路由算法,只能利用其中的一条链路进行数据的传输。

1.3 quagga

quagga是一个实现ospf的路由软件,用于模拟ospf协议。

2. 双活负载均衡架构

2.1 方案一、利用DNS轮训

配置两套主备模式的负载均衡器,分别配置VIP A和VIP B。在DNS server测针对同一域名,同时注册VIP A和VIP B。然后在请求域名的时候,dns通过轮训返回VIP A或者 VIP B。在服务端,需要通过memcached集群来共享不同节点的内存数据。从而保证session的持久性

2.2 方案二、利用ECMP

在此方案中,不存在主备模式的负载均衡器,所有负载均衡器均为主模式,配置同一VIP。在router测,利用quagga模拟ospf,可以看到到达VIP的链路有两条,当请求到达router的时候,会将流量分配到两台主负载均衡器上。

3. 环境准备

本文利用fusion创建了6台虚拟机。基于centos 7.5,具体信息如下:

  • VIP: 10.0.1.100
  • client: 10.0.1.132
  • router: 10.0.1.136
  • lb1: 10.0.1.133
  • lb2: 10.0.1.135
  • real_server1: 10.0.1.129
  • real_server2: 10.0.1.131

注: 所有虚拟机关闭防火墙

1
2
systemctl stop firewalld
systemctl disable firewalld

4. 环境部署

4.1 real server端

  1. 安装nginx提供http服务。
1
2
3
4
5
6
yum install nginx -y
systemctl start nginx
systemctl enable nginx
对于real_server1: echo "RealServer1 10.0.1.129" > /usr/share/nginx/html/index.html
对于real_server2: echo "RealServer2 10.0.1.131" > /usr/share/nginx/html/index.html
systemctl restart nginx
  1. 配置vip

由于接收数据包的目的IP是VIP,所以需要将vip绑定到lo网卡,因为lo:vip不是用来通信的,所以这里的一定设置/32位子网掩码。对应修改脚本中的”VIP”变量。

由于real_server1, real_sever2, lb1, lb2均绑定vip到lo,所以需要关闭real_server1和real_server2的arp响应。对于linux内核参数arp_ignore和arp_announce的配置,参考文档 https://www.cnblogs.com/lipengxiang2009/p/7451050.html

arp_ignore设置为1:只响应目的IP地址为接收网卡上的本地地址的arp请求。所以对于lo网卡绑定VIP(lo是不接收外部数据包的),所以不会做出响应
arp_announce设置为2:忽略IP数据包的源IP地址,选择该发送网卡上最合适的本地地址作为arp请求的源IP地址。arp_announce的作用是控制系统在对外发送arp请求的数据包时,如何选择发送的源ip地址。因为对于任一主机,当接收到arp请求时,如果该arp的目的ip不是自己的ip,主机会把对端的ip和mac地址的对应关系存储到本地的mac地址表中。所以,如果real_server1发送arp的ip是lo的VIP,那么其他主机就会将VIP和mac的对应关系存储到mac地址表中,当下次像vip发送请求的时候,会直接到达real_server1,而不会经过lb。所以要设置arp_announce为2,这样就避免了通过lo:vip发送arp请求包。

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
[root@localhost ~]# cat relserver.sh
#!/bin/bash
# Script to start LVS DR real server.
# description: LVS DR real server
. /etc/rc.d/init.d/functions

VIP=10.0.1.100 #修改为VIP
host=`/bin/hostname`
case "$1" in
    start)
        /sbin/ifconfig lo down
        /sbin/ifconfig lo up
        echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
        echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
        echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
        echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
        /sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
        /sbin/route add -host $VIP dev lo:0
        ;;
    stop)
        /sbin/ifconfig lo:0 down
        echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
        echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce
        echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
        echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
        ;;
    status)
        islothere=`/sbin/ifconfig lo:0 | grep $VIP`
        isrothere=`netstat -rn | grep "lo" | grep $VIP`
        if [ ! "$islothere" -o ! "isrothere" ];then
            # Either the route or the lo:0 device not found.
            echo "LVS-DR real server Stopped."
        else
            echo "LVS-DR real server Running."
        fi
        ;;
    *)
        # Invalid entry.
        echo "$0: Usage: $0 {start|status|stop}"
        exit 1
        ;;
    esac
    exit 0
[root@localhost ~]# ./realserver.sh start

4.2 lb端

配置lb1和lb2,lb1和lb2为双主的负载均衡器,基于LVS和keepalived配置。
由于我们使用ospf来实现高可用,所以keepalived不需要配置vrrp功能。keepalived只使用期后端服务检测功能。

在keepalived-LVS集群的抢占模式下,master节点的网卡挂在VIP,此时VIP的设备是唯一的。但是在OSPF-LVS集群下,router根据ospf信息,通过修改报文的目的mac地址,转发到对应的LVS来实现负载均衡。并不根据VIP对应的arp信息,所以对应的每台LVS将VIP挂载在lo上。

  1. 配置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
    
    yum install keepalived -y
    [root@localhost ~]# cat /etc/keepalived/keepalived.conf
    global_defs {
        router_id LVS1 #路由器标识
        script_user root
        enable_script_security
    }
    
    virtual_server 10.0.1.100 80 {  #此处是VIP
        delay_loop 5  #定义健康检查的时间间隔,单位为秒。
        lb_algo rr    #后端的负载均衡算法,rr为round-robin
        lb_kind DR    #lvs的调度类型,DR/TUN/NAT
        #persistence_timeout 60  #保持客户端的请求在<INT>时间段内全部发到同一个真实服务器。适用于动态网页session共享的环境。默认六分钟。
        persistence_granularity 255.255.255.255  #会话保持粒度,配合persistence_timeout使用,通过子网掩码来定义会话保持对一个IP生效还是对一组IP生效。默认值为255.255.255.255,表示单个客户端分配到一个RS上;255.255.255.0表示客户端IP所在的整个网段的请求都会分配给同一台RS
        protocol TCP   # 使用协议,TCP|UDP|SCTP
        inhibit_on_failure on #配置该项,在检测到后端RS节点故障后将weight值改为0,而不是从IPVS中删除
        ha_suspend    # 在LB节点状态从Master切换到Backup时,不启用对RS节点的健康检查
        sorry_server 127.0.0.1 80
        real_server 10.0.1.131 80 {
            weight 10
            HTTP_GET {
                url {
                    path /
                    status_code 200
                }
            connect_port 80
            connect_timeout 2
            retry 1
            delay_before_retry 1
            }
        }
        real_server 10.0.1.129 80 {
            weight 10
        HTTP_GET {
                url {
                    path /
                    status_code 200
                }
            connect_port 80
            connect_timeout 2
            retry 1
            delay_before_retry 1
            }
        }
    }
    [root@localhost ~]# systemctl reload keepalived
    [root@localhost ~]# systemctl enable keepalived
    
    验证结果:
    [root@localhost ~]# ipvsadm -L
    IP Virtual Server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
      -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
    TCP  localhost.localdomain:http rr
      -> 10.0.1.129:http              Route   10     0          0
      -> 10.0.1.131:http              Route   10     0          0
    [root@localhost ~]#
    
  2. 配置vip
    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
    
    [root@localhost ~]#ifconfig lo:0 10.0.1.100 netmask 255.255.255.255 up
    [root@localhost ~]# ifconfig
    ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 10.0.1.133  netmask 255.255.255.0  broadcast 10.0.1.255
            inet6 fe80::af35:1bc3:d630:16c1  prefixlen 64  scopeid 0x20<link>
            ether 00:0c:29:4a:64:33  txqueuelen 1000  (Ethernet)
            RX packets 169865  bytes 20546055 (19.5 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 131247  bytes 23749082 (22.6 MiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            inet6 ::1  prefixlen 128  scopeid 0x10<host>
            loop  txqueuelen 1000  (Local Loopback)
            RX packets 746  bytes 57280 (55.9 KiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 746  bytes 57280 (55.9 KiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    lo:0: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 10.0.1.100  netmask 255.255.255.255
            loop  txqueuelen 1000  (Local Loopback)
    
    [root@localhost ~]#
    
  3. 配置quagga
    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
    
    [root@localhost ~]# yum install quagga -y
    [root@localhost ~]# cat /etc/quagga/ospfd.conf
    hostname 10.0.1.133   #用主机ip代替即可
    password test
    log file /var/log/quagga/ospfd.log
    log stdout
    log syslog
    service password-encryption
    interface ens33        #主机ip所在的网卡名
      ip ospf hello-interval 1
      ip ospf dead-interval 4
      ip ospf priority 0
      ip ospf cost 1
    router ospf
      ospf router-id 10.0.1.133  #用主机ip代替
      log-adjacency-changes
      network 10.0.1.0/24 area 0.0.0.0
    access-list 1 permit 127.0.0.1
    line vty
     access-class 1
    [root@localhost ~]# cat /etc/quagga/zebra.conf
    hostname 10.0.1.133    # 主机ip代替
    password test
    enable password test
    log file /var/log/quagga/zebra.log
    service password-encryption
    interface ens33
    access-list 1 permit 127.0.0.1
    ip prefix-list ANY seq 5 permit 0.0.0.0/0 le 32
    route-map ANY deny 10
      match ip address prefix-list ANY
    ip protocol ospf route-map ANY
    line vty
      access-class 1
    [root@localhost ~]# systemctl  start zebra
    [root@localhost ~]# systemctl  start ospfd
    

    4.3 router端

quagga配置

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
//开启转发
[root@localhost ~]# echo 1 >  /proc/sys/net/ipv4/ip_forward
//Router作为网关的接口必须开启arp proxy:
[root@localhost ~]# echo 1 > /proc/sys/net/ipv4/conf/ens33/proxy_arp
[root@localhost ~]# yum install -y quagga
[root@localhost ~]# cat /etc/quagga/ospfd.conf
hostname 10.0.1.136    #主机ip地址
password test
log file /var/log/quagga/ospfd.log
log stdout
log syslog
service password-encryption
interface ens33
  ip ospf hello-interval 1
  ip ospf dead-interval 4
  ip ospf priority 1
  ip ospf cost 1
router ospf
  ospf router-id 10.0.1.136
  log-adjacency-changes
  network 10.0.1.0/24 area 0.0.0.0
access-list 1 permit 127.0.0.1
line vty
 access-class 1
[root@localhost ~]# cat /etc/quagga/zebra.conf
hostname 10.0.1.136 # HOSTNAME改为IP也可以
password test
enable password test
log file /var/log/quagga/zebra.log
#log syslog
service password-encryption
interface ens33
access-list 1 permit 127.0.0.1
ip prefix-list ANY seq 5 permit 0.0.0.0/0 le 32
route-map ANY permit 10  #将ospf路由映射到kernel
  match ip address prefix-list ANY
ip protocol ospf route-map ANY
line vty
  access-class 1
[root@localhost ~]#

验证结果:可以看到访router到达vip 10.0.1.100有两条链路,一条是10.0.1.133(lb1),一条是10.0.1.135(lb2)

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
[root@localhost ~]# vtysh

Hello, this is Quagga (version 0.99.22.4).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

localhost.localdomain# show ip ospf neighbor

    Neighbor ID Pri State           Dead Time Address         Interface            RXmtL RqstL DBsmL
10.0.1.133        0 Full/DROther       3.274s 10.0.1.133      ens33:10.0.1.136         0     0     0
10.0.1.135        0 Full/DROther       3.934s 10.0.1.135      ens33:10.0.1.136         0     0     0
localhost.localdomain# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, A - Babel,
       > - selected route, * - FIB route

K>* 0.0.0.0/0 via 10.0.1.2, ens33
O   10.0.1.0/24 [110/1] is directly connected, ens33, 00:03:18
C>* 10.0.1.0/24 is directly connected, ens33
O>* 10.0.1.100/32 [110/11] via 10.0.1.133, ens33, 00:03:09
  *                        via 10.0.1.135, ens33, 00:03:09
C>* 127.0.0.0/8 is directly connected, lo
localhost.localdomain# exit
[root@localhost ~]# ip route
default via 10.0.1.2 dev ens33 proto dhcp metric 100
10.0.1.0/24 dev ens33 proto kernel scope link src 10.0.1.136 metric 100
10.0.1.100 proto zebra metric 11
	nexthop via 10.0.1.133 dev ens33 weight 1
	nexthop via 10.0.1.135 dev ens33 weight 1
[root@localhost ~]#

4.4 client端

client端,需要配置路由,针对访问VIP的请求均跳转到router,这样router就可以利用ospf的ECMP,将流量分发到后端的lb1和lb2。

5. 结果验证

为了验证router确实最client端数据做了分流。将后端lb做了改动,lb1来对接real_server1, lb2来对接real_server2。通过返回的信息就可以确定lb是否为真的双活。

client1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost ~]# ifconfig|grep 10.0
        inet 10.0.1.138  netmask 255.255.255.0  broadcast 10.0.1.255
        ether 00:0c:29:c8:e5:37  txqueuelen 1000  (Ethernet)
        loop  txqueuelen 1000  (Local Loopback)
[root@localhost ~]# ip route
default via 10.0.1.2 dev ens33 proto dhcp metric 100
10.0.1.0/24 dev ens33 proto kernel scope link src 10.0.1.138 metric 100
10.0.1.100 via 10.0.1.136 dev ens33
[root@localhost ~]# traceroute 10.0.1.100
traceroute to 10.0.1.100 (10.0.1.100), 30 hops max, 60 byte packets
 1  10.0.1.136 (10.0.1.136)  0.260 ms  0.146 ms  0.146 ms
 2  10.0.1.100 (10.0.1.100)  0.293 ms  0.303 ms  0.226 ms
[root@localhost ~]# curl 10.0.1.100
server 10.0.1.129
[root@localhost ~]#

client2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost ~]# ifconfig|grep 10.0
        inet 10.0.1.137  netmask 255.255.255.0  broadcast 10.0.1.255
        ether 00:0c:29:09:ae:d5  txqueuelen 1000  (Ethernet)
        loop  txqueuelen 1000  (Local Loopback)
[root@localhost ~]# ip route
default via 10.0.1.2 dev ens33 proto dhcp metric 100
10.0.1.0/24 dev ens33 proto kernel scope link src 10.0.1.137 metric 100
10.0.1.100 via 10.0.1.136 dev ens33
[root@localhost ~]# traceroute 10.0.1.100
traceroute to 10.0.1.100 (10.0.1.100), 30 hops max, 60 byte packets
 1  10.0.1.136 (10.0.1.136)  0.278 ms  0.180 ms  0.091 ms
 2  10.0.1.100 (10.0.1.100)  0.452 ms  0.370 ms  0.266 ms
[root@localhost ~]# curl 10.0.1.100
server 10.0.1.131
[root@localhost ~]#

参考文献

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未来AI编程

共鸣===鼓励 打赏您随意

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值