lvs

负载均衡选择

四层实现负载均衡的软件

类型 协议 特点 说明
lvs tcp/udp (自带) 重量级
nginx tcp/udp (支撑这两者需要额外带–with-stream编译) 轻量级,带缓存功能,正则表达式较灵活
haproxy tcp 模拟四层转发,较灵活

nginx虽然通过额外的stream模块,可以实现tcp/udp负载均衡,但是针对主动自定义的健康检查(Healthchecks ),却需要收费?

haproxy不支持udp可参阅官方文档描述:

  1. HAProxy官网:The Reliable, High Performance TCP/HTTP Load Balancer(可靠、高性能的 TCP/HTTP 负载均衡器)。
  2. 关于HAProxy是否要支持UDP的讨论

Keepalived+ LVS,可以执行健康检查、可以跟踪接口状态、可以配置为故障转移等。免费、性能高。

DNS 和 syslog等软件,是极少数基于udp传输的应用。

image-20210709101836749

简介In a nutshell

传输层:提供TCP(传输控制协议),UDP(用户数据报协议)两个协议,主要功能是数据格式化、数据确认和丢失重传等。

LVS(Linux Virtual Server)

  1. 基于IP层和基于内容请求分发的负载平衡调度解决方法
  2. 并在Linux内核中实现了这些方法
  3. 将一组服务器构成一个实现可伸缩的、高可用网络服务的虚拟服务器

IPVS软件实现了三种IP负载均衡技术和10种连接调度算法。

可利用如下命令查看ipvs相关信息(发现ipvs已经在内核中了):

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
grep -i -C 10 ipvs /boot/config-3.10.0-1160.11.1.el7.x86_64

...
#
# IPVS transport protocol load balancing support
#
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y

#
# IPVS scheduler
#
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
CONFIG_IP_VS_LBLC=m
CONFIG_IP_VS_LBLCR=m
CONFIG_IP_VS_DH=m
CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m

能够支持绝大多数的TCP和UDP协议:

协议 内 容
TCP HTTP,FTP,PROXY,SMTP,POP3,IMAP4,DNS,LDAP,HTTPS,SSMTP等
UDP DNS,NTP,ICP,视频、音频流播放协议等

无需对客户机和服务器作任何修改,可适用大多数Internet服务。

LVS服务器集群系统具有良好的伸缩性,可支持几百万个并发连接。配置100M网卡,采用VS/TUN或VS/DR调度技术,集群系统的吞吐量可高达1Gbits/s;如配置千兆网卡,则系统的最大吞吐量可接近10Gbits/s。

LVS集群软件是按GPL(GNU Public License)许可证发行的自由软件,这意味着你可以得到软件的源代码,有权对其进行修改,但必须保证你的修改也是以GPL方式发行。

三种IP负载均衡技术

Virtual Server via Direct Routing(VS/DR)

VS/DR通过改写请求报文的MAC地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。

  1. 同VS/TUN技术一样,VS/DR技术可极大地 提高集群系统的伸缩性。
  2. 这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,
  3. 但是要求调度器与真实服务器都有一块网卡连 在同一物理网段上。
Virtual Server via IP Tunneling(VS/TUN)

采用NAT技术时,由于请求和响应报文都必须经过调度器地址重写,当客户请求越来越多时,调度器的处理能力将成为瓶颈。为了解决这个问题,

调度器把请求报 文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。

由于一般网络服务应答比请求报文大许多,采用 VS/TUN技术后,集群系统的最大吞吐量可以提高10倍。

Virtual Server via Network Address Translation(VS/NAT)

通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。

八种连接调度算法

DR

LVS DR原理:

  1. 用户请求LVS VIP到达Director(LB均衡器)。
  2. Director(LVS)将所请求消息的目标MAC地址更改为后端RealServer MAC地址,目标IP为VIP(不变),源IP是用户IP地址(不变)。
  3. Director(LVS)将消息发送到RealServer
  4. RealServer检测到目的地是其自己的本地VIP(Real)。如果服务器处于同一网络段,则请求将直接返回给用户。如果用户和RealServer不在同一网络段中,则通过网关返回用户。

在 DR 模式中,接收请求也是由Director分发者负责, rs 直接将响应数据返回给客户端,和 tun 模式不同,DR 模式中的分发者和后端 rs 必须在同一个内网,

这个模型还需要在Director中有一个VIP配置并且所有的rs都开启

rs在响应客户端IP时需要设置源VIP地址,目标是IP为客户端IP,这样客户端访问到Director的VIP地址,响应的源地址还是同一个VIP地址,

Director不修改包报文,将包头的MAC地址改为rs的MAC地址,发送包到.rs..

注意点:

  1. LVS服务器和后端RealServer必须位于同一网络段(Intranet和公共网络)中
  2. 不要修改VIP消息的目标MAC目录。
  3. LVS和RealServer需要配置VIP地址,VIP地址相同,并且RealServer VIP配置的网卡需要抑制ARP响应。
  4. VIP保持不变。在Real Server客户端和Lo NIC上配置VIP(无冲突)。
  5. RealServer客户端服务器的网关指向路由器,并给出一个fright (默认网关),以确保数据可以go out(访问互联网)
    1. The gateway of the Realserver client server points to the router and gives a fright (the default gateway) to ensure that the data can go out (access the Internet)
  6. 所有RealServer客户端服务器都可以禁止VIP ARP广播,禁止VIP相应的解析。但确保real网卡不能禁止ARP广播
  • Real-Server和Direct-Server必须在同一网段
  • Real-Server的lo接口必须绑定VIP
  • 抑制Real-Server原因:保证前端路由将目标地址为VIP的报文发给Direct-Server,而不是Real-Server

img

参考

  1. Linux服务器集群系统(一) – LVS项目介绍 (linuxvirtualserver.org)
  2. LVS官网 The Linux Virtual Server Project - Linux Server Cluster for Load Balancing

img

LVS NAT 负载均衡的实现 | fufeixiang’s Blogs

lvs-nat

  1. ipvs: linux内核中,真正执行负载均衡调度工作。
  2. ipvsadm和keepalived是并行的,都是ipvs的管理工具。

实验

cat /etc/redhat-release uname -rm

ip 负载均衡角色 高可用角色 备注
192.168.80.128 LB(keepalived+lvs) MASTER VIP为192.168.80.212 CentOS Linux release 7.9.2009 (Core) / 3.10.0-1160.el7.x86_64 x86_64
192.168.80.131(暂时没有启动) LB(keepalived+lvs) BACKUP
192.168.80.129 RS1
192.168.80.130 RS2

测试环境,上述ip都选择一个网段的。如果生产环境且是Web服务器,还需要接入一个内网网段?

安装keepalived

1
2
3
4
5
6
7
8
9
yum install -y keepalived

#启动
systemctl start keepalived

#开机启动
systemctl enable keepalived

#日志处理

安装ipvsadm

1
2
3
4
5
6
7
yum install -y ipvsadm

#启动
ipvsadm

#开机启动
systemctl enable ipvsadm

查看内核中是否拥有ipvs

1
lsmod | grep ip_vs

如果没有,启动下keepalived / 或者启动ipvsadm,再次查看

1
2
3
systemctl start keepalived

lsmod | grep ip_vs

防火墙等

1
2
3
4
5
6
7
8
9
systemctl status firewalld
systemctl stop firewalld #关闭防火墙
systemctl disable firewalld #禁止firewall开机启动

sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/sysconfig/selinux #关闭selinux,重启生效
#setenforce 0        #关闭selinux,临时生效
reboot #重启机器!!!

ntpdate 0.centos.pool.ntp.org #时间同步

操作ipvsadm,清理已有的,重新进行观察

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ipvsadm -Ln
ipvsadm -C #清空所有之前配置的内容
ipvsadm -Ln

# 手动lvs,没有自动健康检查功能(keepalived有哦),可以自己写脚本实现(探测rs的服务状态,有就 -a 加入规则,没有就 -d 删除。注意检查次数。)。
# 也可以手动增加lvs规则
ipvsadm -A -t vip:port -s rr #创建一个vs规则
-p 300 会话保持300秒(这个时间内,只能用某个real server)

ipvsadm -a -t vip:port -r rip1:port -g #给vs,增加一个real server,-g是lvs的dr模式 (-m NAT模式;-i TUN模式)
ipvsadm -a -t vip:port -r rip2:port -g

ipvsadm -Ln
ipvsadm -Ln --stats

#手动设置超时时间
ipvsadm --set tcp tcpfin udp
ipvsadm --set 30 5 60
#手动删除规则
ipvsadm -d -t vip:port -r rip2:port #删除一个rs

DR模式的缺陷
1:Realserver和 lvs的vip提供服务的端口必须一致。
也就是说:vip的端口对外端口为 80,但后端服务的真实端口为8080,通过lvs的DR模式是实现不了的。
2:Realserver和LVS不能在同一台机器上
3: Realserver 和LVS需要在同一个vlan或者局域网下。

NAT模式的缺陷
1:NAT模式流量的入和出都需要通过LVS服务器。
2: 效率相比DR模式,性能和效率上会差一些。

NAT

主机

1
2
3
4
5
6
7
8
9
# 设置ipv4转发
vim /etc/sysctl.conf
net.ipv4.ip_forward=1

sysctl -p


#临时生效
echo 1 > /proc/sys/net/ipv4/ip_forward

real server

1
2
3
4
5
6
7
8
9
10
11
12
13
#增加网关(会导致ssh等方式也不行)(指定必须经过VIP才能达到client)
#route add default gw VIP

#单独增加一条路由(指定必须经过VIP才能达到client)
route add cip via VIP

#eg.
#ip route add 192.168.80.1/32 via 192.168.80.212 dev ens33
ip route add 192.168.80.131/32 via 192.168.80.212 dev ens33

route -n
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.80.1 192.168.80.212 255.255.255.255 UGH 0 0 0 ens33
1
tcpdump -i any port 8989 -n

客户端访问

在192.168.80.131服务器上访问:

1
curl 192.168.80.212:8989
ip 负载均衡角色 高可用角色 备注
192.168.80.132 LB(keepalived+lvs) MASTER VIP为192.168.80.212 CentOS Linux release 7.9.2009 (Core) / 3.10.0-1160.el7.x86_64 x86_64
LB(keepalived+lvs) BACKUP
192.168.80.133 RS1
192.168.80.134 RS2
192.168.80.131 client

route相关操作

【废弃】方式1 rc.local
  1. 重启服务器生效
  2. 重启网络服务,则静态路由失效
  3. rc.local是系统启动后最后运行的一个脚本,因此如果有如NFS需要网络才能挂载的服务需求,则该方式不适合
1
2
3
4
5
6
7
sudo vim /etc/rc.local
ip route add 10.253.103.43 via 10.253.103.200 dev eth1

sudo chmod +x /etc/rc.d/rc.local

#reboot
#route -n
【废弃】方式2 static-routes

适合cent0s6,但RHEL7 官网文档没有提到/etc/sysconfig/static-routes,经测试此文件已经无效。

  1. 重启服务器生效
  2. 重启网络服务生效【优点】
  3. 适合需要网络需求的服务

如果需要添加静态路由,尽量将静态路由添加到/etc/sysconfig/static-routes文件中。避免因重启网络服务导致路由失效,从而避免故障的发生。

1
2
3
4
5
6
route -n
vi /etc/sysconfig/static-routes
any net 192.168.100.0 netmask 255.255.255.0 gw 192.168.102.1gg

service network restart
route -n
【使用】方式3 network-scripts配置

永久静态路由需要写到 /etc/sysconfig/network-scripts/route-interface 文件中

1
2
3
4
5
6
7
8
9
vim /etc/sysconfig/network-scripts/route-eth1
10.253.103.43 via 10.253.103.200 dev eth1

#重启设备或计算机生效
#nmcli dev connect eth1
#或者nmcli dev disconnect eth1 && nmcli dev connect eth1

#reboot
#route -n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
route show | column -t

#查看经过的网卡名,是eth0还是其他
ip addr

# 如果是eth0则新建并编辑
vim /etc/sysconfig/network-scripts/route-eth1

#在route-eth0文件中添加以下行
#目标网段及掩码 网关 途径设备
192.168.100.0/24 via 192.168.102.1 dev eth0

#重启网络服务
service network restart

ip route show | column -t

DR-同网段

主机

keepalived 是为了解决lvs的问题而诞生的。

keepalived和lvs结合的特别紧密,不需要单独跟踪lvs的健康情况来漂移vip。(lvs启动在linux内核中,没有单独的进程)

keepalived + lvs 是最常用方案,可以自动管理vip,且自动real server健康检查。

配置keepalived,让LVS拥有VIP:

1
2
3
4
5
6
7
8
ifconfig  #判断使用eth0还是ens33

vim /etc/keepalived/keepalived.conf #配置

systemctl restart keepalived

ip addr #查看vip是否已经在本机上
ipvsadm -Ln #查看rs规则已经建立

keepalived修改配置重载:

1
2
3
1. 修改conf并退出
2. kill -HUP $(cat /var/run/keepalived.pid)
3. 观察日志

说明:man ./keepalived.8

RS

在每一台real server上绑定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
# lo上绑定vip,32位来绑定
ip addr add VIP/32 dev lo label lo:0
或者
ifconfig lo:0 VIP/32 dev up

##【但是系统会自动补充这个路由所以可以不要了】此地址仅用作发送Web响应数据包的源地址,并不需要监听客户机的访问请求(改由调度器监听并分发)。因此使用需接口lo:0来承载VIP地址,并为本机添加一条路由记录,将访问VIP的数据限制在本地(本机的VIP只允许本机访问),以避免通信紊乱
#route add -host VIP dev lo:0

#查看,在lo下面出现
ip addr
------------------------------
# arp抑制
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore #只响应目的IP地址为接收网卡lo上的本地地址的arp请求。
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce #只向该网卡lo回应与该网段匹配的ARP报文。
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore #只响应目的IP地址为所有接收网卡上的本地地址的arp请求。
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce


------------------------------

#添加一个主机的路由
route add -host vip dev lo

#查看
route -n
永久生效!
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
#lo
cd /etc/sysconfig/network-scripts
cp ifcfg-lo ifcfg-lo:0
vim ifcfg-lo:0

DEVICE=lo:0
IPADDR=VIP #修改位vip
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=VIP #修改位vip
ONBOOT=yes
NAME=loopback


#重启网卡
systemctl restart network
ifconfig查看


#lo路由,不要了!
#vim /etc/rc.local
#/sbin/route add -host VIP dev lo:0
#chmod +x /etc/rc.d/rc.local

# arp抑制
vim /etc/sysctl.conf

net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2

sysctl -p

验证

real server

1
2
3
python -m SimpleHTTPServer 8989

确保网络打开 curl RIP:8989

客户端

1
2
访问 vip:8989
刷新按钮,发现会回显不同页面

image-20210714172728213

arp_ignore,定义了对目标地址为本机IP的ARP询问的不同应答模式。
arp_announce,对网络接口(网卡)上发出的ARP请求包中的源IP地址作出相应的限制;主机会根据这个参数值的不同选择使用IP数据包的源IP或当前网络接口卡的IP地址作为ARP请求包的源IP地址。

arp_ignore和arp_announce参数分别有all,default,lo,eth0等对应不同网卡。当all和具体网卡的参数值不一致时,【配置为较大值的生效】。一般只需修改all和某个具体网卡的参数即可。

arp_ignore 使RS不响应针对VIP的ARP请求

  • 0:主机上任意一个网卡接口,只要有一个有arp广播请求报文中的IP地址,就进行回应。
    • 收到arp广播请求的网卡接口,还会查看其他所有网卡有没有配置这个IP地址,只要有一个配置了,就会响应。
  • 1:只响应目的IP地址为接收网卡上的本地地址的arp请求。
    • 收到arp广播请求的网卡接口,只查看自身有没有配置这个IP地址,如果没有配置,即使别的接口上配置了,也不会响应。
  • 2:只响应目的IP地址为【接收网卡上的本地地址】的arp请求,并且arp请求的【源IP必须和接收网卡同网段】。
    • 不仅要满足取值为1的要求,而且还会对arp请求包的源IP地址做校验,一个网段内的才会做相应。
  • 3:如果ARP请求数据包所请求的IP地址对应的本地地址其作用域(scope)为主机(host),则不回应ARP响应数据包,如果作用域为全局(global)或链路(link),则回应ARP响应数据包。
  • 4~7:保留未使用
  • 8:不回应所有的arp请求

地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址。收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。

因为RealServer解开IP包头查看到的目标IP是VIP,而只有RS自己的IP符合目标IP(VIP)才会接收进来,所以我们需要在RS的上面配置VIP(配置在lo上)。

在lvs-DR模式中,调度器Director和所有的Real Server都配置了VIP地址,其中,LVS的VIP配置在物理网卡接口上,Real Server配置在了本地接口lo上。

当客户端发送ARP广播时,因为arp请求一定来自别的主机,所以接收的网卡只能是物理接口 ens33或eth0。()

对于Real Server来说,Real Server将VIP配置到了lo接口上,ens33或者eth0等物理接口上没有VIP。又设置了所有网卡的arp_ignore为1,因此当client发送arp广播时,ens33刚好不会回应。

对于Director来说,ens33或者eth0刚好因为keepalived漂移到这个服务器,因此拥有了VIP。因此当client发送arp广播时,ens33刚好可以回应。

从上述可知,

  1. 要把Director的VIP配置到物理接口上(例如,keepalive中配置参数为:interface ens33)
  2. 要把Real Server的VIP配置到本地接口lo上,且Real Server要进行ARP抑制(如果不抑制,则会导致client访问物理接口ens33时,lo配置的vip也会响应!)
  3. Real Server能否充当client——从rs自己发出的vip请求,不再经过Director进行负载均衡分发。直接访问自己的lo发现vip进行访问:tcpdump -i lo port 8989
  4. Director能否充当client——不可以。

数据包到达 RealServer 服务器后,发现请求报文的 MAC 地址是自己的网卡 MAC 地址,将会接受此报文,待处理完成之后,将响应报文通过 lo 接口传送给 eth0 网卡然后向外发出。此时的源 IP 地址为 VIP,目标 IP 也是 VIP,变成了RS中自己的VIP –》VIP发送。无法返回响应到Director了。

graph LR
director(1.vip:vip) --2.mac:vip:vip--> director --3.lvs--> rs(4.vip:vip-ens33)  --5.vip-ens33:vip--> rs
1
2
tcpdump -i any port 8989 -n
抓包,发现在director中发送curl vip时,是vip --> vip的发送过程!
  1. lvs和rs部署在同一台机器上——可以。

    • client 访问目标IP—— VIP:53端口。(监听ens33的VIP:53端口)
    • LVS将VIP:53端口转发到RIP:53端口。(监听ens33的RIP:53端口)
    • 发现MAC地址就是本机。本机回包(VIP:CIP)

arp_announce rs回包时,数据包重新封装报文 (源IP地址为VIP,目标IP为CIP),将响应报文通过 lo 接口传送给物理网卡ens33然后向外发出。系统不使用IP包的源地址来设置ARP请求的源地址(lo),而选择发送接口的IP地址(ens33)。

  • 0:表示无论哪块网卡收到了arp的请求,只要发现本机有请求的mac,就会响应。
  • 1:表示尽量避免响应ARP请求中MAC不是本网卡的。如一个主机有多块网卡,其中一块网卡接收到了ARP请求,发现所请求的MAC是本机另一块网卡的,这个时候接收到ARP请求的这块网卡就尽量避免响应。
  • 2:表示总是使用最合适的网卡来响应。一个主机有多块网卡,其中一块网卡接收到了ARP请求,发现所请求的MAC是本机另一块网卡的,这个时候接收到ARP请求的这块网卡就一定不响应,只有发现请求的MAC是自己的才给与响应。

sysctl.conf中包含all和eth/lo(具体网卡)的arp_ignore参数,取其中较大的值生效。

Linux 内核参数 arp_ignore & arp_announce 详解 - 简书 (jianshu.com)

当客户端用户发送请求给 www.baidu.com 网站时,首先经过 DNS 解析到 IP 后并向百度服务器发送请求,

数据包经过网络到百度 LVS 负载均衡服务器,这时到达 LVS 网卡时的数据包包括:源 IP 地址(客户端地址)、目的 IP 地址(百度对外服务器 IP 地址,也就是 VIP)、源 MAC 地址(CMAC / LVS 连接路由器的 MAC 地址)、目标 MAC 地址(VMAC / VIP 对应的 MAC 地址)。

数据包到达网卡后,经过链路层到达 PREROUTING 链,进行查找路由,发现目的 IP 是 LVS 的 VIP,这时就会发送至 INPUT 链中并且数据包的 IP 地址、MAC 地址、Port 都未经过修改。

数据包到达 INPUT 链中,LVS 会根据目的 IP 和 Port(端口)确认是否为 LVS 定义的服务,如是定义过的 VIP 服务,会根据配置的服务信息,从 RealServer 中选择一个后端服务器 RS1,然后 RS1 作为目标出方向的路由,确定下一跳信息及数据包通过具体的哪个网卡发出,最好将数据包通过 INET_HOOK 到 OUTPUT 链中。

数据包通过 POSTROUTING 链后,目的 MAC 地址将会修改为 RealServer 服务器 MAC 地址(RMAC)源 MAC 地址修改为 LVS 与 RS 同网段的 IP 地址的 MAC 地址(DMAC)此时,数据包将会发至 RealServer 服务器

数据包到达 RealServer 服务器后,发现请求报文的 MAC 地址是自己的网卡 MAC 地址,将会接受此报文,待处理完成之后,将响应报文通过 lo 接口传送给 eth0 网卡然后向外发出。此时的源 IP 地址为 VIP,目标 IP 为 CIP,源 MAC 地址为 RS1 的 RMAC,目的 MAC 地址为下一跳路由器的 MAC 地址(CMAC),最终数据包通过 RS 相连的路由器转发给客户端。

LVS脑裂问题

尝试keepalived+httpd协议lvs

使用DR作为负载平衡,真实服务器应该能够接收针对VIP 的传入请求并直接响应客户端。

这对主机的配置有一些影响,但使用这种方法允许像以前一样单独使用真实服务器,就好像负载平衡设置不存在一样。

请注意,Real Server A 和 B 不运行 Keepalived 的实例

lvs server
1
vim keepalived.conf
1
2
3
4
ipvsadm

#查看是否安装
rpm -q ipvsadm

开启路由转发

临时有效

1
2
#不可以使用vim
echo 1 > /proc/sys/net/ipv4/ip_forward

永久

1
2
# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1     #lvs主机都开启路由转发功能。设置为“1”开启路由转发功能,“0”为关闭路由转发;
1
2
# 修改内核参数后,重新加载配置.只是暂时开启,重启机器后会失
sysctl -p

可有可无

1
2
3
4
# 关闭ICMP的重定向
echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects
echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects
1
iptables
real server

制作一个简单的http服务

1
/usr/bin/python2.7 -m SimpleHTTPServer 8989

或者

1
2
3
4
5
6
yum install httpd

systemctl start httpd
systemctl enable httpd

echo Rs1Test Server on rip > /var/www/html/index.html
1
curl rip

修改默认网关指向 NAT 的 VIP / DIP 地址

默认网关改为eth0的虚拟ip(由于临时添加的方式,网关有可能会消失,消失就添加即可。)

Real Server这里需要配置路由,将默认的网关改为Load Balancer 服务器的内网ip地址,来实现路由转发的效果。

这个命令需要在每台Real Server之上执行,否则其他Real Server没有办法接受到转发的ip数据包,会被Load Balance屏蔽,从而没有办法实现我们期待的负载均衡的结果。

  • RS 应该使用私有地址,RS 的网关必须指向 DIP
  • DIP 和 RIP 必须在同一个网段内
  • 请求和响应报文都需要经过 Director Server,高负载场景中,Director Server 易成为性能瓶颈
  • 支持端口映射
  • VS 必须是 Linux 系统,RS可以是任意系统;
1
2
3
4
5
6
7
8
#修改默认网关
route add default gw vip dev eth0
#还原
route del default gw vip

#在Realserver上修改到该内网IP(CIP)的路由。
#LVS NAT模式下,正常流程是,CIP向VIP发送一个数据包,Director修改DestIP为RIP,RIP处理后反馈给VIP(GW)。如果CIP和RIP位于同一个网段,则会导致RIP不通过网关,直接将数据包发送到CIP。
route add -host CIP gw DIP
1
2
3
4
5
6
7
8
route add default gw 10.154.5.163  dev eth0

route -n

#内容如下
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.154.5.163 0.0.0.0 UG 0 0 0 eth0
1
2
3
4
5
6
7
8
#1. 绑定VIP到lo网卡
net.ipv4.ip_nonlocal_bind=1

#2. 抑制ARP,抑制目标地址和接线网卡不是同一个ip
net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.eth0.arp_announce = 2
net.ipv4.conf.eth1.arp_ignore = 1
net.ipv4.conf.eth1.arp_announce = 2
1
sysctl –p
1
curl 10.154.5.3:8989
1
2
vim /etc/rc.local
/sbin/route add -host 10.154.5.3 dev lo:0
1
2
3
4
5
6
ip a s eth0

ipvsadm -ln

关闭一个real server ,再次观察,发现规则少了一个(健康检查生效)再次启动观察(注意延时)
ipvsadm -ln

在集群中服务器与director之间的时间误差不能超过一秒

1
2
3
4
5
6
7
8
9
办法一:运行ntp服务,与网络上的ntp服务器进行时间同步即可

service ntpd start

办法二:把director当作时间服务器使realserver与director进行时间同步

director运行: service ntpd start

realserver运行ntpd directorIP,: ntpd

How to use Keepalived for high availability and load balancing | Pen Test Partners

抛弃keepalived,直接采用lvs + httpd协议

尝试keepalived + bind协议

尝试直接采用lvs+ bind协议

nginx

  • Nginx编译安装时使用–with-stream开启ngx_stream_core_module模块(Nginx1.9以上版本)
    • nginx默认编译时,该模块并未编译进去,需要编译的时候添加–with-stream,使其支持stream代理即可
    • ngx_stream_core_module模块,使nginx支持四层负载均衡,实现TCP和UDP代理。
      • TCP是stream上下文的默认协议
      • UDP需要专门指定,listen 53 udp;
  • Nginx采用轮询的方式调用后端SSH服务器
  1. –with-http_ssl_module 开启SSL加密功能
  2. –with-stream 开启4层反向代理功能

下载安装

1
yum install -y make zlib zlib-devel gcc-c++ libtool openssl openssl-devel pcre pcre-devel
1
2
3
4
5
6
7
8
9
10
11
cd /data

wget http://nginx.org/download/nginx-1.20.1.tar.gz

tar -zxvf nginx-1.20.1.tar.gz

cd nginx-1.20.1/

./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_ssl_module --with-stream --with-stream_realip_module

make && make install
1
2
3
4
5
6
7
8
ln -snf /usr/local/nginx/sbin/nginx /usr/local/sbin
useradd -s /sbin/nologin -M nginx

cd /usr/local/nginx/logs
mkdir access

cd /usr/local/nginx/conf
mv nginx.conf nginx.conf_bak
1
lsof -i:53
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
vim nginx.conf

user root;
worker_processes auto;
error_log logs/error.log error;
events {
worker_connections 1024;
}
stream {
upstream dns_upstreams {
server 10.154.5.162:53 weight=1 max_fails=3 fail_timeout=30s;
server 10.154.5.214:53 weight=1 max_fails=3 fail_timeout=30s;
}

server {
listen 53 udp;
proxy_pass dns_upstreams;
proxy_timeout 1s;
proxy_responses 1;
}

server {
listen 53;
proxy_pass dns_upstreams;
proxy_timeout 1s;
proxy_responses 1;
}

log_format proxy '$remote_addr - [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time "$upstream_addr" ' '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time" ' '$remote_addr $remote_port $server_addr $server_port';

map $bytes_received $loggable { 0 0; default 1; }

map $time_iso8601 $logdate {
'~^(?<ymd>\d{4}-\d{2}-\d{2})' $ymd;
default 'date-not-found';
}

access_log logs/access/access-dns-$logdate.log proxy if=$loggable;

open_log_file_cache off;
}
负载均衡方法
  1. round-robin(轮询)——默认,Nginx使用轮询算法负载均衡通信。因为是默认方法,所以没有round-robin指令;只创建upstream配置块在顶级stream上下文并像之前步骤添加server指令。
  2. last_conn(最少连接)——Nginx选择当前活跃连接数较少的服务器。
  3. least_time——Nginx选择最低平均延迟和最少活跃连接的服务器。最低活跃连接基于least_time指令的以下参数计算:
    1. connect——连接upstream服务器的时间
    2. first_byte——接收第一个数据字节的时间
    3. last_byte——从服务器接收完整响应的时间
被动健康检查

fail_timeout默认为10秒,max_fails默认为1次。因此,如果连接10秒内尝试至少一次失败,Nginx标记服务器10秒内不可用。

主动健康检查
1
2
3
4
nginx
nginx -s reload
tail -f /var/log/nginx/error.log
ps aux | grep nginx
1
2
dig www.wei01.com @10.154.5.162 +short A
dig www.wei01.com @10.154.5.163 +short A
1
2
3
4
5
tailf access-2021-07-08.log

10.154.5.163 - [08/Jul/2021:15:23:12 +0800] UDP 200 58 42 0.002 "10.154.5.214:53" "42" "58" "0.000" 10.154.5.163 45808 10.154.5.163 53

10.154.5.163 - [08/Jul/2021:15:23:13 +0800] UDP 200 58 42 0.001 "10.154.5.162:53" "42" "58" "0.000" 10.154.5.163 48863 10.154.5.163 53

平滑升级

若前期未带stream模块已经安装了nginx,此时可以选择平滑添加stream模块,并不会对线上业务造成多大影响

1)先在LB的slave从机上进行平滑添加,然后再将vip切换到从机上,随即在对master主机进行平滑添加该模块。
2)平滑添加即是重新configure编译的时候加上–with-stream,接着make。
3)千万注意,make之后,不要make install,否则会覆盖掉之前的配置!!!

1
2
whereis nginx
find / -name nginx
1
2
3
4
5
6
7
8
#查阅编译情况是否带了stream(若有则带了 --with-stream)
nginx -V

nginx version: nginx/1.20.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_ssl_module --with-stream --with-stream_realip_module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cd /usr/servers/nginx-1.18.0/

#注意将旧的nginx -V得到的configure arguments附加在后面,再增加-with-stream等内容
./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_ssl_module --with-stream --with-stream_realip_module

make

#覆盖nginx执行程序
cp -f /usr/servers/nginx-1.18.0/objs/nginx /usr/local/nginx/sbin/nginx

pkill -9 nginx

#查阅编译情况带了stream
/usr/local/nginx/sbin/nginx -V

#制作超链接方便全局访问
ln -snf /usr/local/nginx/sbin/nginx /usr/local/sbin

CentOS7下使用nginx实现TCP和UDP代理 - yuanfan2012的个人空间 - OSCHINA - 中文开源技术交流社区

nginx tcp stream 访问日志配置的优化 | 码农网 (codercto.com)

nginx 1.12 stream 日志设置_秋天的博客-CSDN博客_nginx stream 日志

-------------Keep It Simple Stupid-------------
0%