负载均衡选择
四层实现负载均衡的软件
| 类型 | 协议 | 特点 | 说明 | ||
|---|---|---|---|---|---|
| lvs | tcp/udp (自带) | 重量级 | |||
| nginx | tcp/udp (支撑这两者需要额外带–with-stream编译) | 轻量级,带缓存功能,正则表达式较灵活 | |||
| haproxy | tcp | 模拟四层转发,较灵活 | |||
nginx虽然通过额外的stream模块,可以实现tcp/udp负载均衡,但是针对主动自定义的健康检查(Healthchecks ),却需要收费?
haproxy不支持udp可参阅官方文档描述:
- HAProxy官网:The Reliable, High Performance TCP/HTTP Load Balancer(可靠、高性能的 TCP/HTTP 负载均衡器)。
- 关于HAProxy是否要支持UDP的讨论
Keepalived+ LVS,可以执行健康检查、可以跟踪接口状态、可以配置为故障转移等。免费、性能高。
DNS 和 syslog等软件,是极少数基于udp传输的应用。

简介In a nutshell
传输层:提供TCP(传输控制协议),UDP(用户数据报协议)两个协议,主要功能是数据格式化、数据确认和丢失重传等。
LVS(Linux Virtual Server)
- 基于IP层和基于内容请求分发的负载平衡调度解决方法
- 并在Linux内核中实现了这些方法
- 将一组服务器构成一个实现可伸缩的、高可用网络服务的虚拟服务器
IPVS软件实现了三种IP负载均衡技术和10种连接调度算法。
可利用如下命令查看ipvs相关信息(发现ipvs已经在内核中了):
1 | grep -i -C 10 ipvs /boot/config-3.10.0-1160.11.1.el7.x86_64 |
能够支持绝大多数的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地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。
- 同VS/TUN技术一样,VS/DR技术可极大地 提高集群系统的伸缩性。
- 这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,
- 但是要求调度器与真实服务器都有一块网卡连 在同一物理网段上。
Virtual Server via IP Tunneling(VS/TUN)
采用NAT技术时,由于请求和响应报文都必须经过调度器地址重写,当客户请求越来越多时,调度器的处理能力将成为瓶颈。为了解决这个问题,
调度器把请求报 文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。
由于一般网络服务应答比请求报文大许多,采用 VS/TUN技术后,集群系统的最大吞吐量可以提高10倍。
Virtual Server via Network Address Translation(VS/NAT)
通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。
八种连接调度算法
DR
LVS DR原理:
- 用户请求LVS VIP到达Director(LB均衡器)。
- Director(LVS)将所请求消息的目标MAC地址更改为后端RealServer MAC地址,目标IP为VIP(不变),源IP是用户IP地址(不变)。
- Director(LVS)将消息发送到RealServer
- 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..
注意点:
- LVS服务器和后端RealServer必须位于同一网络段(Intranet和公共网络)中
- 不要修改VIP消息的目标MAC目录。
- LVS和RealServer需要配置VIP地址,VIP地址相同,并且RealServer VIP配置的网卡需要抑制ARP响应。
- VIP保持不变。在Real Server客户端和Lo NIC上配置VIP(无冲突)。
- RealServer客户端服务器的网关指向路由器,并给出一个fright (默认网关),以确保数据可以go out(访问互联网)
- 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)
- 所有RealServer客户端服务器都可以禁止VIP ARP广播,禁止VIP相应的解析。但确保real网卡不能禁止ARP广播
- Real-Server和Direct-Server必须在同一网段
- Real-Server的lo接口必须绑定VIP
- 抑制Real-Server原因:保证前端路由将目标地址为VIP的报文发给Direct-Server,而不是Real-Server

参考
- Linux服务器集群系统(一) – LVS项目介绍 (linuxvirtualserver.org)
- LVS官网 The Linux Virtual Server Project - Linux Server Cluster for Load Balancing
LVS NAT 负载均衡的实现 | fufeixiang’s Blogs
- ipvs: linux内核中,真正执行负载均衡调度工作。
- 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 | yum install -y keepalived |
安装ipvsadm
1 | yum install -y ipvsadm |
查看内核中是否拥有ipvs
1 | lsmod | grep ip_vs |
如果没有,启动下keepalived / 或者启动ipvsadm,再次查看
1 | systemctl start keepalived |
防火墙等
1 | systemctl status firewalld |
操作ipvsadm,清理已有的,重新进行观察
1 | ipvsadm -Ln |
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 | 设置ipv4转发 |
real server
1 | 增加网关(会导致ssh等方式也不行)(指定必须经过VIP才能达到client) |
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
- 重启服务器生效
- 重启网络服务,则静态路由失效
- rc.local是系统启动后最后运行的一个脚本,因此如果有如NFS需要网络才能挂载的服务需求,则该方式不适合
1 | sudo vim /etc/rc.local |
【废弃】方式2 static-routes
适合cent0s6,但RHEL7 官网文档没有提到/etc/sysconfig/static-routes,经测试此文件已经无效。
- 重启服务器生效
- 重启网络服务生效【优点】
- 适合需要网络需求的服务
如果需要添加静态路由,尽量将静态路由添加到/etc/sysconfig/static-routes文件中。避免因重启网络服务导致路由失效,从而避免故障的发生。
1 | route -n |
【使用】方式3 network-scripts配置
永久静态路由需要写到 /etc/sysconfig/network-scripts/route-interface 文件中
1 | vim /etc/sysconfig/network-scripts/route-eth1 |
1 | route show | column -t |
DR-同网段
主机
keepalived 是为了解决lvs的问题而诞生的。
keepalived和lvs结合的特别紧密,不需要单独跟踪lvs的健康情况来漂移vip。(lvs启动在linux内核中,没有单独的进程)
keepalived + lvs 是最常用方案,可以自动管理vip,且自动real server健康检查。
配置keepalived,让LVS拥有VIP:
1 | ifconfig #判断使用eth0还是ens33 |
keepalived修改配置重载:
1 | 1. 修改conf并退出 |
说明:man ./keepalived.8
RS
在每一台real server上绑定VIP
临时生效!
1 | lo上绑定vip,32位来绑定 |
永久生效!
1 | lo |
验证
real server
1 | python -m SimpleHTTPServer 8989 |
客户端
1 | 访问 vip:8989 |

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刚好可以回应。
从上述可知,
- 要把Director的VIP配置到物理接口上(例如,keepalive中配置参数为:interface ens33)
- 要把Real Server的VIP配置到本地接口lo上,且Real Server要进行ARP抑制(如果不抑制,则会导致client访问物理接口ens33时,lo配置的vip也会响应!)
- Real Server能否充当client——从rs自己发出的vip请求,不再经过Director进行负载均衡分发。直接访问自己的lo发现vip进行访问:
tcpdump -i lo port 8989。 - 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 | tcpdump -i any port 8989 -n |
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 | ipvsadm |
开启路由转发
临时有效
1 | 不可以使用vim |
永久
1 | vim /etc/sysctl.conf |
1 | 修改内核参数后,重新加载配置.只是暂时开启,重启机器后会失 |
可有可无
1 | # 关闭ICMP的重定向 |
1 | iptables |
real server
制作一个简单的http服务
1 | /usr/bin/python2.7 -m SimpleHTTPServer 8989 |
或者
1 | yum install httpd |
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 | 修改默认网关 |
1 | route add default gw 10.154.5.163 dev eth0 |
1 | #1. 绑定VIP到lo网卡 |
1 | sysctl –p |
1 | curl 10.154.5.3:8989 |
1 | vim /etc/rc.local |
1 | ip a s eth0 |
在集群中服务器与director之间的时间误差不能超过一秒
1 | 办法一:运行ntp服务,与网络上的ntp服务器进行时间同步即可 |
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服务器
- –with-http_ssl_module 开启SSL加密功能
- –with-stream 开启4层反向代理功能
下载安装
1 | yum install -y make zlib zlib-devel gcc-c++ libtool openssl openssl-devel pcre pcre-devel |
1 | cd /data |
1 | ln -snf /usr/local/nginx/sbin/nginx /usr/local/sbin |
1 | lsof -i:53 |
1 | vim nginx.conf |
负载均衡方法
- round-robin(轮询)——默认,Nginx使用轮询算法负载均衡通信。因为是默认方法,所以没有round-robin指令;只创建upstream配置块在顶级stream上下文并像之前步骤添加server指令。
- last_conn(最少连接)——Nginx选择当前活跃连接数较少的服务器。
- least_time——Nginx选择最低平均延迟和最少活跃连接的服务器。最低活跃连接基于least_time指令的以下参数计算:
- connect——连接upstream服务器的时间
- first_byte——接收第一个数据字节的时间
- last_byte——从服务器接收完整响应的时间
被动健康检查
fail_timeout默认为10秒,max_fails默认为1次。因此,如果连接10秒内尝试至少一次失败,Nginx标记服务器10秒内不可用。
主动健康检查
1 | nginx |
1 | dig www.wei01.com @10.154.5.162 +short A |
1 | tailf access-2021-07-08.log |
平滑升级
若前期未带stream模块已经安装了nginx,此时可以选择平滑添加stream模块,并不会对线上业务造成多大影响
1)先在LB的slave从机上进行平滑添加,然后再将vip切换到从机上,随即在对master主机进行平滑添加该模块。
2)平滑添加即是重新configure编译的时候加上–with-stream,接着make。
3)千万注意,make之后,不要make install,否则会覆盖掉之前的配置!!!
1 | whereis nginx |
1 | 查阅编译情况是否带了stream(若有则带了 --with-stream) |
1 | cd /usr/servers/nginx-1.18.0/ |
CentOS7下使用nginx实现TCP和UDP代理 - yuanfan2012的个人空间 - OSCHINA - 中文开源技术交流社区