1. LB Cluster 负载均衡集群
1.1 基于工作的协议层次划分
传输层(通用):利用DNAT 和 DPORT
代码语言:javascript复制 LVS:LVS中的DNAT, 可以把用户请求转发到不同的后端服务器, 而iptables(Netfilter)中的DNAT只能转发到一个后端服务器
nginx:stream
haproxy:mode tcp
应用层(专用):针对特定协议,常称为 proxy server
代码语言:javascript复制 http:nginx, httpd, haproxy(mode http), …
fastcgi:nginx, httpd, …
mysql:mysql-proxy, …
1.2 负载均衡的会话保持
1.session 绑定:同一用户调度固定服务器
代码语言:javascript复制基于 Source IP:LVS SH算法(可以对某一特定服务而言; nginx可以基于$ip_hash实现源地址hash, 也可以基于hash $remote_addr实现源地址hash
Cookie: lvs不支持, nginx支持基于请求报文的cookie字段进行调度, $cookie_NAME
2.session 复制:每台服务器拥有全部session
代码语言:javascript复制session multicast cluster
3.session 共享:利用专门的session服务器存储session, 应用程序链接session服务器获取session
代码语言:javascript复制Memcached,Redis
1.3 高可用集群实现
代码语言:javascript复制LVS本身存在单点失败问题, 需要配合keepalived实现高可用
keepalived:vrrp协议
2. Linux Virtual Server 简介
2.1 LVS介绍
LVS:Linux Virtual Server,负载调度器,内核集成的功能, 一般配合keepalived实现高可用负载均衡集群
2.2 LVS工作原理
LVS根据请求报文的目标IP和目标协议及端口将其调度转发至某RS,根据调度算法来挑选RS LVS是内核级功能,工作在INPUT链,将发往INPUT的流量进行“处理”
范例: 查看内核是否支持LVS, 已经支持的算法
代码语言:javascript复制grep -i -C 10 ipvs /boot/config-4.18.0-147.el8.x86_64
代码语言:javascript复制...(省略部分内容)...
CONFIG_NETFILTER_XT_MATCH_IPVS=m
CONFIG_NETFILTER_XT_MATCH_POLICY=m
...(省略部分内容)...
#
### 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_FO=m #新增
CONFIG_IP_VS_OVF=m #新增
CONFIG_IP_VS_LBLC=m
CONFIG_IP_VS_LBLCR=m
CONFIG_IP_VS_DH=m
CONFIG_IP_VS_SH=m
### CONFIG_IP_VS_MH is not set
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
...(省略部分内容)...
2.3 LVS集群体系架构
image
2.4 LVS 功能及组织架构
负载均衡的应用场景为高访问量的业务,提高应用程序的可用性和可靠性。
应用于高访问量的业务
如果您的应用访问量很高,可以通过配置监听规则将流量分发到不同的云服务器 ECS(Elastic Compute Service 弹性计算服务)实例上。此外,可以使用会话保持功能将同一客户端的请求转发到同一台后端ECS
扩展应用程序
可以根据业务发展的需要,随时添加和移除ECS实例来扩展应用系统的服务能力,适用于各种Web服务器和App服务器。
消除单点故障
可以在负载均衡实例下添加多台ECS实例。当其中一部分ECS实例发生故障后,负载均衡会自动屏蔽故障的ECS实例,将请求分发给正常运行的ECS实例,保证应用系统仍能正常工作
同城容灾 (多可用区容灾)
为了提供更加稳定可靠的负载均衡服务,阿里云负载均衡已在各地域部署了多可用区以实现同地域容灾。当主可用区出现机房故障或不可用时,负载均衡仍然有能力在非常短的时间内(如:大约30s中断)切换到另外一个备可用区恢复服务能力;当主可用区恢复时,负载均衡同样会自动切换到主可用区提供服务。
使用负载均衡时,您可以将负载均衡实例部署在支持多可用区的地域以实现同城容灾。此外,建议您结合自身的应用需要,综合考虑后端服务器的部署。如果您的每个可用区均至少添加了一台ECS实例,那么此种部署模式下的负载均衡服务的效率是最高的。
如下图所示,在负载均衡实例下绑定不同可用区的ECS实例。正常情况下,用户访问流量将同时转至发主、备可用区内的ECS实例;当可用区A发生故障时,用户访问流量将只转发至备可用区内的ECS实例。此种部署既可以避免因为单个可用区的故障而导致对外服务的不可用,也可以通过不同产品间可用区的选择来降低延迟。
负载均衡层和后端服务器都实现高可用
如果采取如下图所示的部署方案,即在负载均衡实例的主可用区下绑定多台ECS实例,而在备可用区没有任何ECS实例。当主可用区发生故障时会造成业务中断,因为备可用区没有ECS实例来接收请求。这样的部署方式很明显是以牺牲高可用性为代价来获取低延时。
仅实现负载均衡层的高可用, 后端服务器并没有高可用
image
跨地域容灾
您可以在不同地域下部署负载均衡实例,并分别挂载相应地域内不同可用区的ECS。上层利用云解析做智能DNS,将域名解析到不同地域的负载均衡实例服务地址下,可实现全局负载均衡。当某个地域出现不可用时,暂停对应解析即可实现所有用户访问不受影响。
2.5 LVS集群术语
VS: Virtual Server RS: Real Server, upstream server(nginx), backend server(haproxy) CIP: client IP, 客户端IP VIP: Virtual Server IP, LVS接受请求的网卡的IP DIP: Director IP, LVS和Real Server通信用的IP RIP: 后端服务器的IP
3. LVS工作模式和相关命令
3.1 LVS集群的工作模式
代码语言:javascript复制 lvs-nat:修改请求报文的目标IP,多目标IP的DNAT
lvs-dr:操纵封装新的MAC地址
lvs-tun:在原请求IP报文之外新加一个IP首部
lvs-fullnat:修改请求报文的源和目标IP, 内核默认不支持
3.1.1 LVS的NAT模式
lvs-nat:本质是多目标IP的DNAT,通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和PORT实现转发
代码语言:javascript复制(1)RIP和DIP可以是通过交换机相连的同一个网段, 也可以是路由器相连的不同网段, 只要保证是原路返回即可. 用交换机连接时, RS的网关要指向DIP, 而用路由器连接时, RS的网关指向路由器的接口地址. 不过一般NAT模式都是用交换机相连, 不会跨网络
(2)请求报文和响应报文都必须经由Director转发,Director易于成为系统瓶颈. 因此LVS-NAT模式要求后端服务器数量不能太高. 虽然LVS支持百万并发, 但是还要受到网段带宽的限制, 一般几十台
,
(3)支持端口映射,可修改请求报文的目标PORT
(4)VS必须是Linux系统,RS可以是任意OS系统
LVS-NAT模式的通信过程
代码语言:javascript复制1. 客户端发起请求, 源ip为客户端ip地址(如果有SNAT会被SNAT转换), 源端口为客户端开启的随机端口(如果有SNAT那么会被SNAT转换). 目标ip为LVS的vip, 目标端口为vip监听的端口
2. 经过LVS服务器, 修改请求报文的目标ip, 目标port(如果后端服务器修改了web服务器的监听端口那么就DNAT要修改目标端口)
3. 根据指定的调度算法, 把请求报文转发给相应的服务器
4. 服务器处理请求, 封装响应报文, 源ip为服务器自己的ip, 源端口为服务器监听的web端口, 目标客户端的ip, 目标端口是客户端的端口
5. 相应报文到达LVS, 进行SNAT, 把响应报文的源ip改为LVS的vip, 源端口改为LVS上监听的web端口
6. 客户端收到响应报文, 查看源ip和port是否和请求时的ip地址相同, 相同则接受, 不同则丢弃
LVS-NAT模式, 限定了请求和响应报文都必须经过LVS
代码语言:javascript复制客户端发起请求时, 目标ip是LVS的vip
如果响应报文不经过LVS做NAT转换, 直接由后端RS发给客户端, 那么客户端收到的响应报文的源ip是客户端ip, 和当初自己请求的vip不同, 因此不会处理
LVS工作在Netfilter的PREROUTING链后的路由预处理与INPUT链之间
请求报文 > PREROUTING > 路由预处理 > IPVS > INPUT > POSTROUTING
LVS服务器收到请求报文, 由于目标ip是自己的vip, 因此会通过PREROUTING链, 进入路由预处理 路由表检查发现请求报文的目标地址是自己的vip, 因此会转发到INPUT链, 而LVS策略就是工作在INPUT链之前, 直接做DNAT转换, 不让请求报文进到LVS内部, 而是做完转换直接从POSTROUTING链发给后端服务器
而DNAT工作在PREROUTING链, 在PREROUTING上直接做目标地址和端口修改, 否则因为请求报文的目标IP就是服务器的ip地址, 如果不在PREROUTING做转换, 那么就会进入到INPUT链, 交给防火墙自身处理, 而防火墙是没有处理功能的, 需要交给后端的服务器处理
虽然LVS的IPVS模块和Iptables的Netfilter模块是不同的内核模块, 但是使用LVS时, 不要在LVS服务器上做iptables规则, 尤其是PREROUTING链, 因为可能由于PREROUTING链设置不正确, 导致请求报文直接在PREROUTING被丢弃
利用路由器连接LVS和RS
image
利用交换机连接LVS和RS
image
3.1.2 LVS的DR模式
LVS-DR:Direct Routing,直接路由,LVS默认模式, 应用最广泛, 通过为请求报文重新封装一个MAC首部进行转发,修改请报文的目标MAC地址, 之后源MAC也被修改为DIP所在的接口的MAC,目标MAC是某挑选出的RS的RIP所在接口的MAC地址;源IP/PORT,以及目标IP/PORT均保持不变
DR模型简易图
DR模型通信过程
LVS如何得到后端服务器的MAC地址
代码语言:javascript复制LVS上会配置后端RS的RIP, 但是MAC地址是不知道的
LVS通过arp广播, 根据被被调度的RS的RIP, 查询其MAC地址
由于LVS和RS依靠arp广播, 因此, LVS和RS必须在同一个网段, 不能用路由器相连, 不远程调度, 需要LVS和RS部署在同一个机房, 一旦机房出现问题, 会有单点故障
DR模式的特点:
1.Director和各RS都配置有VIP. 因为DR模式下, 响应报文是直接由RS发给客户端, 客户端请求的目标ip是LVS的vip, 而RS的响应报文源ip是自己的RIP, 会造成客户端丢弃响应报文. 因此, 在RS配置VIP, 这样响应报文的源ip可以用VIP
2.确保前端路由器将目标IP为VIP的请求报文发往Director, DR模型下, LVS和RS都会配置VIP, 因此会产生地址冲突
地址产生冲突的原因:
代码语言:javascript复制服务器网卡启动后, 会向局域网发送免费arp, 探测网络中是否有服务器和自己用了相同的ip地址
如果没有服务器使用自己的ip, 那么会对外宣称自己的ip就是这个ip
如果有服务器使用了自己的ip, 那么就会发现地址冲突
解决地址冲突方法:
方法1: 在前端网关做静态绑定VIP和Director的MAC地址 ,让请求报文只转发到LVS, 不转发给RS
方法2: 在RS上使用arptables工具
代码语言:javascript复制 arptables -A IN -d VIP -j DROP
arptables -A OUT -sVIP -j mangle --mangle-ip-s $RIP
方法3: 在RS上调整内核参数, 禁止RS服务器响应免费arp广播, 禁止RS服务器发送免费arp广播
代码语言:javascript复制/proc/sys/net/ipv4/conf/all/arp_ignore
/proc/sys/net/ipv4/conf/all/arp_announce
3.RS的RIP可以使用私网地址,也可以是公网地址;如果是私网地址, 那么RIP与DIP在同一IP网络;RIP的网关不能指向DIP,而是指向前端路由器, 以确保响应报文不会经由Director
4.RS和Director要在同一个物理网络
5.请求报文要经由Director,但响应报文不经由Director,而由RS经过路由器直接发往Client
6.不支持端口映射(端口不能修改), DR模型, 修改的是二次的目标MAC地址, 三层以上的信息不会修改, 因此vip监听的端口和rs监听的端口必须一致
7.RS可使用大多数OS系统
3.1.3 LVS的隧道模型
转发方式:不修改请求报文的IP首部(源IP为CIP,目标IP为VIP),而在原IP报文之外再封装一个IP首部(源IP是DIP,目标IP是RIP),将报文发往挑选出的目标RS;RS直接响应给客户端(源IP是VIP,目标IP是CIP)
TUN模式特点:
代码语言:javascript复制DIP, VIP, RIP是公网地址, 也可私网地址(需要拉专线)
RS的网关一般不能指向DIP, RS会直接响应客户端
rs的隧道接口上配置vip地址, 以便接受lvs转发过来的数据包, 以及作为响应报文的源ip
lvs转发给rs时需要使用隧道, 隧道外层的ip头部源ip是lvs的DIP, 目标IP是RIP, 而RS响应给客户的报文的ip头部是根据隧道内层的ip头分析得到的, 源ip是vip, 目标ip是客户端ip
请求报文要经由Director,但响应不经由Director
不支持端口映射
RS的OS须支持隧道功能
虽然LVS和RS都配置vip, 但是并不冲突, 因为LVS和RS不在同一个物理网络中
隧道模型虽然支持LVS和RS在同一个物理网段, 但是性能不如RS
因为隧道模型要添加ip头部, 而RS只是修改源,目mac, 通讯过程本身就是要修改mac地址的
LVS适合有多机房的大型企业, 用户可以访问固定的部署了lvs的机房, 之后lvs根据用户的地址, 把请求调度到离用户进的机房, 回包直接送离用户进的机房返回给用户
应用场景:
一般来说, 隧道模式常会用来负载调度缓存服务器组, 这些缓存服务器一般放置在不同的网络环境, 不同的机房, 可以就近返回给用户 在请求对象不在缓存服务器本地命中的情况下, 缓存服务器要向源服务器发送请求, 将结果取回, 在本地缓存, 然后将结果返回给用户
3.1.4 FullNAT模式
通过同时修改请求报文的源IP地址和目标IP地址进行转发
CIP –> DIP
VIP –> RIP
特点:
1.VIP是公网地址,RIP和DIP是私网地址,且通常不在同一IP网络;因此,RIP的网关一般不会指向DIP 2.RS收到的请求报文源地址是DIP,因此,只需响应给DIP;但Director还要将其发往Client 3.请求和响应报文都经由Director 4.相对NATi模式,可以更好的实现LVS-RealServer间跨VLAN通讯 5.支持端口映射
与NAT模式相比, FullNAT除了修改请求报文的目标ip地址, 还会修改源ip地址 FullNAT下, RS看不到客户端的ip, 因为LVS会修改请求报文的源ip, 而NAT模式源ip不变, RS可以看到客户端的ip地址 可以支持局域网, 或者跨路由, 但是本身NAT模式也是都支持的, 因此, 一般FullNAT模式应用场景不是很多
注意:此类型kernel默认不支持
3.1.5 不同工作模式的比较
LVS工作模式总结和比较
lvs-nat与lvs-fullnat:
请求和响应报文都经由Director lvs-nat:RIP的网关要指向DIP lvs-fullnat:RIP和DIP未必在同一IP网络,但要能通信
lvs-dr与lvs-tun:
请求报文要经由Director,但响应报文由RS直接发往Client lvs-dr:通过封装新的MAC首部实现,通过MAC转发 lvs-tun:通过在原IP报文外封装新IP头实现转发,支持远距离通信
3.2 LVS的调度算法
根据LVS调度时是否考虑各RS当前的负载状态, 分为静态算法和动态算法
3.2.1 静态算法
特点: 仅根据算法本身进行调度, 不考虑后端服务器当前负载状态
1、RR:roundrobin,轮询
2、WRR:Weighted RR,加权轮询
3、SH:Source Hashing,实现session sticky,源IP地址hash;将来自于同一个IP地址的请求始终发往第一次挑中的RS,从而实现会话绑定
4、DH:Destination Hashing;目标地址哈希,第一次轮询调度至RS,后续将发往同一个目标地址的请求始终转发至第一次挑中的RS,典型使用场景是正向代理缓存场景中的负载均衡,如:宽带运营商
把不同RS上的内容, 缓存到不同的缓存服务器上, 让LVS去调度这些缓存服务器, LVS会将用户的请求按照其要访问的对象的ip地址进行调度, 也就目标地址hash
3.2.2 动态算法
根据RS当前的负载状态及调度算法进行调度Overhead=value 较小的RS将被调度
1、LC:least connections 适用于长连接应用
Overhead=activeconns*256 inactiveconns
2、WLC:Weighted LC,默认调度方法
Overhead=(activeconns*256 inactiveconns)/weight, 权重越高的服务器, 负载值越低, 越会被调度
3、SED:Shortest Expection Delay,初始连接高权重优先, 只检查活动链接, 不考虑非活动链接
Overhead=(activeconns 1)*256/weight
代码语言:javascript复制对于WLC算法来说, 当多台不同权重的服务器, 刚上线时, 权重大的服务器会被优先调度, 造成其承受过多的负载, 而权重小的服务器没有请求调度
同时, 非活动链接对于服务器负载的消耗不是很大, 但是如果不考虑非活动链接, 那么当没有活动链接时, 所有服务器的负载又都为0
因此, 在SED中, 使用活动链接 1来避免当活动链接为0, 所有服务器负载都为0的情况. 让权重高的主机优先被调度
4、NQ:Never Queue,第一轮均匀分配,后续SED
代码语言:javascript复制避免权重高的机器, 前几次都会被调度, 而其余服务器不会被调度
5、LBLC:Locality-Based LC,动态的DH算法,使用场景:根据负载状态实现正向代理
6、LBLCR:LBLC with Replication,带复制功能的LBLC,解决LBLC负载不均衡问题,从负载重的复制到负载轻的RS
内核版本 4.15 版本后新增调度算法:FO和OVF
FO(Weighted Fail Over)调度算法,在此FO算法中,遍历虚拟服务所关联的真实服务器链表,找到还未过载(未设置IP_VS_DEST_F_OVERLOAD标志)的且权重最高的真实服务器,进行调度. 不关心活动链接数, 只关系服务器的权重, 以及是否有过载标记位, 类似静态算法
OVF(Overflow-connection)调度算法,基于真实服务器的活动连接数量和权重值实现。将新连接调度到权重值最高的真实服务器,直到其活动连接数量超过权重值,之后调度到下一个权重值最高的真实服务器,在此OVF算法中,遍历虚拟服务相关联的真实服务器链表,找到权重值最高的可用真实服务器。属于动态的FO算法.
一个可用的真实服务器需要同时满足以下条件:
- 未过载(未设置IP_VS_DEST_F_OVERLOAD标志), 如果过载, 会设置IP_VS_DEST_F_OVERLOAD标记. 或者当某个RS服务器需要做升级或维护时, 可以加IP_VS_DEST_F_OVERLOAD标记, 让其不会调度, 等到升级或维护完成, 再继续调度
- 真实服务器当前的活动连接数量小于其权重值
- 其权重值不为零 链接:https://www.jianshu.com/p/3bd24f696a21