前言

负载均衡技术Load Balance简称LB是构建大型网站必不可少的架构策略之一。它的目的是把用户的请求分发到多台后端的设备上,用以均衡服务器的负载。我们可以把负载均衡器划分为两大类:硬件负载均衡器和软件负载均衡器。这里重点介绍软件实现方法中的LVS和Keepalived。

LVS和Keepalived的原理介绍和配置实践

更新历史

2019年09月03日 - 拆分LVS-Keepalived
2019年08月23日 - 更新LVS/NAT、LVS/DR、LVS/TUN三种模式的原理和配置实践
2018年12月03日 - 精简和更新配置步骤
2018年07月31日 - 初稿

阅读原文 - https://wsgzao.github.io/post/lvs-keepalived/

扩展阅读

LVS - http://www.linuxvirtualserver.org/zh/index.html
Keepalived - http://www.keepalived.org/


ReadMe

参考文章

LVS - http://www.linuxvirtualserver.org/Documents.html
How virtual server works? - http://www.linuxvirtualserver.org/how.html
Keepalived - http://www.keepalived.org/doc/
LVS入门系列:初识LVS与LVS-NAT - http://www.zsythink.net/archives/2134
使用 LVS 实现负载均衡原理及安装配置详解 - https://www.cnblogs.com/liwei0526vip/p/6370103.html
LVS 之 VS/TUN 应用场景 - https://www.jianshu.com/p/5524034b6086
LVS和Keepalived官方中文手册PDF - https://pan.baidu.com/s/1s0P6nUt8WF6o_N3wdE3uKg

【均衡负载之 LVS 系列一】 - LVS 五种工作模式
【均衡负载之 LVS 系列二】 - LVS 基础配置
【均衡负载之 LVS 系列三】 - 高可用 LVS+KeepAlived 集群
【均衡负载之 LVS 系列四】 - OSPF (ECMP)-LVS 集群

相关术语

以下术语涉及LVS三种工作模式的原理

  • LB (Load Balancer 负载均衡)
  • HA (High Available 高可用)
  • Failover (失败切换)
  • Cluster (集群)
  • LVS (Linux Virtual Server Linux 虚拟服务器)
  • DS (Director Server),指的是前端负载均衡器节点
  • RS (Real Server),后端真实的工作服务器
  • VIP (Virtual IP),虚拟的IP地址,向外部直接面向用户请求,作为用户请求的目标的 IP 地址
  • DIP (Director IP),主要用于和内部主机通讯的 IP 地址
  • RIP (Real Server IP),后端服务器的 IP 地址
  • CIP (Client IP),访问客户端的 IP 地址

负载均衡(LB)

负载均衡实现方法有两种:硬件实现和软件实现

硬件比较常见的有:

  1. F5 Big-IP
  2. Citrix Netscaler

软件比较常见的有:

  1. LVS(Linux Virtual Server)
  2. HAProxy
  3. Nginx

LVS特点是:

  1. 首先它是基于4层的网络协议的,抗负载能力强,对于服务器的硬件要求除了网卡外,其他没有太多要求;
  2. 配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,大大减少了人为出错的几率;
  3. 应用范围比较广,不仅仅对web服务做负载均衡,还可以对其他应用(mysql)做负载均衡;
  4. LVS架构中存在一个虚拟IP的概念,需要向IDC多申请一个IP来做虚拟IP。

Nginx负载均衡器的特点是:

  1. 工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构;
  2. Nginx安装和配置比较简单,测试起来比较方便;
  3. 也可以承担高的负载压力且稳定,一般能支撑超过上万次的并发;
  4. Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测;
  5. Nginx对请求的异步处理可以帮助节点服务器减轻负载;
  6. Nginx能支持http和Email,这样就在适用范围上面小很多;
  7. 默认有三种调度算法: 轮询、weight以及ip_hash(可以解决会话保持的问题),还可以支持第三方的fair和url_hash等调度算法;

HAProxy的特点是:

  1. HAProxy是工作在网络7层之上;
  2. 支持Session的保持,Cookie的引导等;
  3. 支持url检测后端的服务器出问题的检测会有很好的帮助;
  4. 支持的负载均衡算法:动态加权轮循(Dynamic Round Robin),加权源地址哈希(Weighted Source Hash),加权URL哈希和加权参数哈希(Weighted Parameter Hash);
  5. 单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度;
  6. HAProxy可以对Mysql进行负载均衡,对后端的DB节点进行检测和负载均衡。

LVS+Keepalived 简介

在lvs+keepalived环境里面,lvs主要的工作是提供调度算法,把客户端请求按照需求调度在real服务器,keepalived主要的工作是提供lvs控制器的一个冗余,并且对real服务器做健康检查,发现不健康的real服务器,就把它从lvs集群中剔除,real服务器只负责提供服务。

LVS

LVS是一个开源的软件,可以实现LINUX平台下的简单负载均衡。LVS是Linux Virtual Server的缩写,意思是Linux虚拟服务器。

LB 集群的架构和原理很简单,就是当用户的请求过来时,会直接分发到 Director Server 上,然后它把用户的请求根据设置好的调度算法,智能均衡地分发到后端真正服务器 (real server) 上。为了避免不同机器上用户请求得到的数据不一样,需要用到了共享存储,这样保证所有用户请求的数据是一样的。

LVS 是 Linux Virtual Server 的简称,也就是 Linux 虚拟服务器。这是一个由章文嵩博士发起的一个开源项目,它的官方网站是 http://www.linuxvirtualserver.org 现在 LVS 已经是 Linux 内核标准的一部分。使用 LVS 可以达到的技术目标是:通过 LVS 达到的负载均衡技术和 Linux 操作系统实现一个高性能高可用的 Linux 服务器集群,它具有良好的可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的性能。LVS 是一个实现负载均衡集群的开源软件项目,LVS 架构从逻辑上可分为调度层、Server 集群层和共享存储。

目前有三种IP负载均衡技术(VS/NAT,VS/TUN,VS/DR)

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

Virtual Server via IP Tunneling(VS/TUN)
采用NAT技术时,由于请求和响应报文都必须经过调度器地址重写,当客户请求越来越多时,调度器的处理能力将成为瓶颈。为了解决这个问题,调度器把请求报 文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。由于一般网络服务应答比请求报文大许多,采用 VS/TUN技术后,集群系统的最大吞吐量可以提高10倍。

Virtual Server via Direct Routing(VS/DR)
VS/DR通过改写请求报文的MAC地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。同VS/TUN技术一样,VS/DR技术可极大地 提高集群系统的伸缩性。这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,但是要求调度器与真实服务器都有一块网卡连 在同一物理网段上。

三种模式的主要区别

VS/NAT VS/TUN VS/DR
server any tunneling non-arp device
server network private LAN/WAN LAN
server number low (10~20) high high
server gateway load balancer own router own router
模式与特点 NAT 模式 IPIP 模式 DR 模式
对服务器的要求 服务节点可以使任何操作系统 必须支持 IP 隧道,目前只有 Linux 系统支持 服务器节点支持虚拟网卡设备,能够禁用设备的 ARP 响应
网络要求 拥有私有 IP 地址的局域网络 拥有合法 IP 地址的局域,网或广域网 拥有合法 IP 地址的局域,服务器节点与负载均衡器必须在同一个网段
通常支持节点数量 10 到 20 个,根据负载均衡器的处理能力而定 较高,可以支持 100 个服务节点 较高,可以支持 100 个服务节点
网关 负载均衡器为服务器节点网关 服务器的节点同自己的网关或者路由器连接,不经过负载均衡器 服务节点同自己的网关或者路由器连接,不经过负载均衡器
服务节点安全性 较好,采用内部 IP,服务节点隐蔽 较差,采用公用 IP 地址,节点安全暴露 较差,采用公用 IP 地址,节点安全暴露
IP 要求 仅需要一个合法的 IP 地址作为 VIP 地址 除了 VIPO 地址外,每个服务器界定啊需要拥有合法的 IP 地址,可以直接从路由到客户端 除了 VIP 外,每个服务节点需拥有合法的 IP 地址,可以直接从路由到客户端
特点 地址转换 封装 IP 修改 MAC 地址
配置复杂度 简单 复杂 复杂

基本工作原理

  1. 当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间
  2. PREROUTING链首先会接收到用户请求,判断目标IP确定是本机IP,将数据包发往INPUT链
  3. IPVS是工作在INPUT链上的,当用户请求到达INPUT时,IPVS会将用户请求和自己已定义好的集群服务进行比对,如果用户请求的就是定义的集群服务,那么此时IPVS会强行修改数据包里的目标IP地址及端口,并将新的数据包发往POSTROUTING链
  4. POSTROUTING链接收数据包后发现目标IP地址刚好是自己的后端服务器,那么此时通过选路,将数据包最终发送给后端的服务器

LVS的组成

LVS 由2部分程序组成,包括 ipvs 和 ipvsadm。

  1. ipvs(ip virtual server):一段代码工作在内核空间,叫ipvs,是真正生效实现调度的代码。
  2. ipvsadm:另外一段是工作在用户空间,叫ipvsadm,负责为ipvs内核框架编写规则,定义谁是集群服务,而谁是后端真实的服务器(Real Server)

工作模式

原生只有3种模式(NAT,TUN,DR), fullnat工作模式默认不支持

LVS是四层负载均衡,也就是说建立在OSI模型的第四层——传输层之上,传输层上有我们熟悉的TCP/UDP,LVS支持TCP/UDP的负载均衡。因为LVS是四层负载均衡,因此它相对于其它高层负载均衡的解决办法,比如DNS域名轮流解析、应用层负载的调度、客户端的调度等,它的效率是非常高的。

LVS的IP负载均衡技术是通过IPVS模块来实现的,IPVS是LVS集群系统的核心软件,它的主要作用是:安装在Director Server上,同时在Director Server上虚拟出一个IP地址,用户必须通过这个虚拟的IP地址访问服务。这个虚拟IP一般称为LVS的VIP,即Virtual IP。访问的请求首先经过VIP到达负载调度器,然后由负载调度器从Real Server列表中选取一个服务节点响应用户的请求。 当用户的请求到达负载调度器后,调度器如何将请求发送到提供服务的Real Server节点,而Real Server节点如何返回数据给用户,是IPVS实现的重点技术,IPVS实现负载均衡机制有几种,分别是NAT、DR、TUN及FULLNAT。

LVS/NAT

重点理解NAT方式的实现原理和数据包的改变。

(1). 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP
(2). PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链
(3). IPVS比对数据包请求的服务是否为集群服务,若是,修改数据包的目标IP地址为后端服务器IP,然后将数据包发至POSTROUTING链。 此时报文的源IP为CIP,目标IP为RIP
(4). POSTROUTING链通过选路,将数据包发送给Real Server
(5). Real Server比对发现目标为自己的IP,开始构建响应报文发回给Director Server。 此时报文的源IP为RIP,目标IP为CIP
(6). Director Server在响应客户端前,此时会将源IP地址修改为自己的VIP地址,然后响应给客户端。 此时报文的源IP为VIP,目标IP为CIP

LVS/NAT模型的特性

  • RS应该使用私有地址,RS的网关必须指向DIP
  • DIP和RIP必须在同一个网段内
  • 请求和响应报文都需要经过Director Server,高负载场景中,Director Server易成为性能瓶颈
  • 支持端口映射
  • RS可以使用任意操作系统
  • 缺陷:对Director Server压力会比较大,请求和响应都需经过director server

NAT(Network Address Translation 网络地址转换)是一种外网和内外地址映射的技术,内网可以是私有网址,外网可以使用NAT方法修改数据报头,让外网与内网能够互相通信。NAT模式下,网络数据报的进出都要经过LVS的处理。LVS需作为RS(真实服务器)的网关。当包到达LVS时,LVS做目标地址转换(DNAT),将目标IP改为RS的IP。RS接收到包以后,仿佛是客户端直接发给它的一样。RS处理完,返回响应时,源IP是RS IP,目标IP是客户端的IP。这时RS的包通过网(LVS)中转,LVS会做源地址转换(SNAT),将包的源地址改为VIP,这样,这个包对客户端看起来就仿佛是LVS直接返回给它的。客户端无法感知到后端RS的存在。

(1)RIP和DIP必须在同一个IP网络,且应该使用私网地址;RS的网关要指向DIP;
(2)请求报文和响应报文都必须经由Director转发;Director易于成为系统瓶颈;
(3)支持端口映射,可修改请求报文的目标PORT;
(4)vs必须是Linux系统,rs可以是任意系统;

缺点:在整个过程中,所有输入输出的流量都要经过LVS 调度服务器。显然,LVS 调度服务器的网络I/O压力将会非常大,因此很容易成为瓶颈,特别是对于请求流量很小,而响应流量很大的Web类应用来说尤为如此。

优点:NAT模式的优点在于配置及管理简单,由于了使用NAT技术,LVS 调度器及应用服务器可以在不同网段中,网络架构更灵活,应用服务器只需要进行简单的网络设定即可加入集群。

LVS/DR

重点将请求报文的目标MAC地址设定为挑选出的RS的MAC地址

(1) 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP
(2) PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链
(3) IPVS比对数据包请求的服务是否为集群服务,若是,将请求报文中的源MAC地址修改为DIP的MAC地址,将目标MAC地址修改RIP的MAC地址,然后将数据包发至POSTROUTING链。 此时的源IP和目的IP均未修改,仅修改了源MAC地址为DIP的MAC地址,目标MAC地址为RIP的MAC地址
(4) 由于DS和RS在同一个网络中,所以是通过二层来传输。POSTROUTING链检查目标MAC地址为RIP的MAC地址,那么此时数据包将会发至Real Server。
(5) RS发现请求报文的MAC地址是自己的MAC地址,就接收此报文。处理完成之后,将响应报文通过lo接口传送给eth0网卡然后向外发出。 此时的源IP地址为VIP,目标IP为CIP
(6) 响应报文最终送达至客户端

LVS/DR模型的特性

  • 特点1:保证前端路由将目标地址为VIP报文统统发给Director Server,而不是RS
  • RS可以使用私有地址;也可以是公网地址,如果使用公网地址,此时可以通过互联网对RIP进行直接访问
  • RS跟Director Server必须在同一个物理网络中
  • 所有的请求报文经由Director Server,但响应报文必须不能进过Director Server
  • 不支持地址转换,也不支持端口映射
  • RS可以是大多数常见的操作系统
  • RS的网关绝不允许指向DIP(因为我们不允许他经过director)
  • RS上的lo接口配置VIP的IP地址
  • 缺陷:RS和DS必须在同一机房中

特点1的解决方案:

  • 在前端路由器做静态地址路由绑定,将对于VIP的地址仅路由到Director Server
  • 存在问题:用户未必有路由操作权限,因为有可能是运营商提供的,所以这个方法未必实用
  • arptables:在arp的层次上实现在ARP解析时做防火墙规则,过滤RS响应ARP请求。这是由iptables提供的
  • 修改RS上内核参数(arp_ignore和arp_announce)将RS上的VIP配置在lo接口的别名上,并限制其不能响应对VIP地址解析请求。

DR(Direct Routing 直接路由模式)此模式时LVS 调度器只接收客户发来的请求并将请求转发给后端服务器,后端服务器处理请求后直接把内容直接响应给客户,而不用再次经过LVS调度器。LVS只需要将网络帧的MAC地址修改为某一台后端服务器RS的MAC,该包就会被转发到相应的RS处理,注意此时的源IP和目标IP都没变。RS收到LVS转发来的包时,链路层发现MAC是自己的,到上面的网络层,发现IP也是自己的,于是这个包被合法地接受,RS感知不到前面有LVS的存在。而当RS返回响应时,只要直接向源IP(即用户的IP)返回即可,不再经过LVS。

注意:
(1) 确保前端路由器将目标IP为VIP的请求报文发往Director:
(a) 在前端网关做静态绑定;
(b) 在RS上使用arptables;
(c) 在RS上修改内核参数以限制arp通告及应答级别;
arp_announce
arp_ignore
(2) RS的RIP可以使用私网地址,也可以是公网地址;RIP与DIP在同一IP网络;RIP的网关不能指向DIP,以确保响应报文不会经由Director;
(3) RS跟Director要在同一个物理网络;
(4) 请求报文要经由Director,但响应不能经由Director,而是由RS直接发往Client;
(5) 此模式不支持端口映射;

缺点:唯一的缺陷在于它要求LVS 调度器及所有应用服务器在同一个网段中,因此不能实现集群的跨网段应用。

优点:可见在处理过程中LVS Route只处理请求的直接路由转发,所有响应结果由各个应用服务器自行处理,并对用户进行回复,网络流量将集中在LVS调度器之上。

LVS/TUN

在原有的IP报文外再次封装多一层IP首部,内部IP首部(源地址为CIP,目标IIP为VIP),外层IP首部(源地址为DIP,目标IP为RIP)

(1) 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP 。
(2) PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链
(3) IPVS比对数据包请求的服务是否为集群服务,若是,在请求报文的首部再次封装一层IP报文,封装源IP为DIP,目标IP为RIP。然后发至POSTROUTING链。 此时源IP为DIP,目标IP为RIP
(4) POSTROUTING链根据最新封装的IP报文,将数据包发至RS(因为在外层封装多了一层IP首部,所以可以理解为此时通过隧道传输)。 此时源IP为DIP,目标IP为RIP
(5) RS接收到报文后发现是自己的IP地址,就将报文接收下来,拆除掉最外层的IP后,会发现里面还有一层IP首部,而且目标是自己的lo接口VIP,那么此时RS开始处理此请求,处理完成之后,通过lo接口送给eth0网卡,然后向外传递。 此时的源IP地址为VIP,目标IP为CIP
(6) 响应报文最终送达至客户端

LVS/TUN模型特性

  • RIP、VIP、DIP全是公网地址
  • RS的网关不会也不可能指向DIP
  • 所有的请求报文经由Director Server,但响应报文必须不能进过Director Server
  • 不支持端口映射
  • RS的系统必须支持隧道

其实企业中最常用的是 DR 实现方式,而 NAT 配置上比较简单和方便,后边实践中会总结 DR 和 NAT 具体使用配置过程。

TUN(virtual server via ip tunneling IP 隧道)调度器把请求的报文通过IP隧道转发到真实的服务器。真实的服务器将响应处理后的数据直接返回给客户端。这样调度器就只处理请求入站报文。此转发方式不修改请求报文的IP首部(源IP为CIP,目标IP为VIP),而在原IP报文之外再封装一个IP首部(源IP是DIP,目标IP是RIP),将报文发往挑选出的目标RS;RS直接响应给客户端(源IP是VIP,目标IP是CIP),由于一般网络服务应答数据比请求报文大很多,采用lvs-tun模式后,集群系统的最大吞吐量可以提高10倍

注意:
(1) DIP, VIP, RIP都应该是公网地址;
(2) RS的网关不能,也不可能指向DIP;
(3) 请求报文要经由Director,但响应不能经由Director;
(4) 此模式不支持端口映射;
(5) RS的操作系统得支持隧道功能

缺点:由于后端服务器RS处理数据后响应发送给用户,此时需要租借大量IP(特别是后端服务器使用较多的情况下)。

优点:实现lvs-tun模式时,LVS 调度器将TCP/IP请求进行重新封装并转发给后端服务器,由目标应用服务器直接回复用户。应用服务器之间是通过IP 隧道来进行转发,故两者可以存在于不同的网段中。

LVS/FULLNAT

lvs-fullnat工作模式默认不支持

此模式类似DNAT,它通过同时修改请求报文的源IP地址和目标IP地址进行转发

注意:
(1) VIP是公网地址,RIP和DIP是私网地址,且通常不在同一IP网络;因此,RIP的网关一般不会指向DIP;
(2) RS收到的请求报文源地址是DIP,因此,只需响应给DIP;但Director还要将其发往Client;
(3) 请求和响应报文都经由Director;
(4) 支持端口映射;

调度算法

八种调度算法(rr,wrr,lc,wlc,lblc,lblcr,dh,sh)

针对不同的网络服务需求和服务器配置,IPVS调度器实现了如下八种负载调度算法:

轮叫调度rr(Round Robin)
调度器通过”轮叫”调度算法将外部请求按顺序轮流分配到集群中的真实服务器上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。

加权轮叫wrr(Weighted Round Robin)
调度器通过”加权轮叫”调度算法根据真实服务器的不同处理能力来调度访问请求。这样可以保证处理能力强的服务器处理更多的访问流量。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。

最少链接lc(Least Connections)
调度器通过”最少连接”调度算法动态地将网络请求调度到已建立的链接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用”最小连接”调度算法可以较好地均衡负载。

加权最少链接wlc(Weighted Least Connections)
在集群系统中的服务器性能差异较大的情况下,调度器采用”加权最少链接”调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。

基于局部性的最少链接lblc(Locality-Based Least Connections)
“基于局部性的最少链接” 调度算法是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器 是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用”最少链接”的原则选出一个可用的服务 器,将请求发送到该服务器。

带复制的基于局部性最少链接lblcr(Locality-Based Least Connections with Replication)
“带复制的基于局部性最少链接”调度算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法的不同之处是它要维护从一个 目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。该算法根据请求的目标IP地址找出该目标IP地址对应的服务 器组,按”最小连接”原则从服务器组中选出一台服务器,若服务器没有超载,将请求发送到该服务器,若服务器超载;则按”最小连接”原则从这个集群中选出一 台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的 程度。

目标地址散列dh(Destination Hashing)
“目标地址散列”调度算法根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。

源地址散列sh(Source Hashing)
“源地址散列”调度算法根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。

keepalived

Keepalived 是运行在lvs之上,是一个用于做双机热备(HA)的软件,它的主要功能是实现真实机的故障隔离及负载均衡器间的失败切换,提高系统的可用性。

运行原理

keepalived通过选举(看服务器设置的权重)挑选出一台热备服务器做MASTER机器,MASTER机器会被分配到一个指定的虚拟ip,外部程序可通过该ip访问这台服务器,如果这台服务器出现故障(断网,重启,或者本机器上的keepalived crash等),keepalived会从其他的备份机器上重选(还是看服务器设置的权重)一台机器做MASTER并分配同样的虚拟IP,充当前一台MASTER的角色。

选举策略

选举策略是根据VRRP协议,完全按照权重大小,权重最大(0~255)的是MASTER机器,下面几种情况会触发选举

  1. keepalived启动的时候
  2. master服务器出现故障(断网,重启,或者本机器上的keepalived crash等,而本机器上其他应用程序crash不算)
  3. 有新的备份服务器加入且权重最大

keepalived的配置文件说明

Keepalived 是运行在lvs之上,它的主要功能是实现RealServer(真实服务器)的故障隔离及Director(负载均衡器)间的FailOver(失败切换).

  • keepalived 是lvs的扩展项目,因此它们之间具备良好的兼容性
  • 对RealServer的健康检查,实现对失效机器/服务的故障隔离
  • 负载均衡器之间的失败切换 failover

全局定义

全局配置又包括两个子配置

  1. 全局定义(global definition)
  2. 静态路由配置(static ipaddress/routes)
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
# 全局定义(global definition) 
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
notification_email: 表示keepalived在发生诸如切换操作时需要发送email通知以及email发送给哪些邮件地址邮件地址可以多个每行一个
notification_email_from admin@example.com: 表示发送通知邮件时邮件源地址是谁
smtp_server 127.0.0.1: 表示发送email时使用的smtp服务器地址这里可以用本地的sendmail来实现
smtp_connect_timeout 30: 连接smtp连接超时时间
router_id node1: 机器标识,通常配置主机名

# 静态地址和路由配置范例
static_ipaddress {
192.168.1.1/24 brd + dev eth0 scope global
192.168.1.2/24 brd + dev eth1 scope global
}
static_routes {
src $SRC_IP to $DST_IP dev $SRC_DEVICE
src $SRC_IP to $DST_IP via $GW dev $SRC_DEVICE
}
这里实际上和系统里面命令配置IP地址和路由一样例如
192.168.1.1/24 brd + dev eth0 scope global 相当于: ip addr add 192.168.1.1/24 brd + dev eth0 scope global
就是给eth0配置IP地址路由同理,一般这个区域不需要配置
这里实际上就是给服务器配置真实的IP地址和路由的在复杂的环境下可能需要配置一般不会用这个来配置我们可以直接用vi /etc/sysconfig/network-script/ifcfg-eth1来配置切记这里可不是VIP不要搞混淆了切记切记

VRRPD配置

包括三个类:

  1. VRRP同步组(synchroization group)
  2. VRRP实例(VRRP Instance)
  3. VRRP脚本
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
# VRRP同步组(synchroization group)配置范例
vrrp_sync_group VG_1 { //注意vrrp_sync_group 后面可自定义名称如lvs_httpd ,httpd
group {
http
mysql
}
notify_master /path/to/to_master.sh
notify_backup /path_to/to_backup.sh
notify_fault "/path/fault.sh VG_1"
notify /path/to/notify.sh
smtp_alert
}
其中http和mysql是实例名和下面的实例名一致
notify_master /path/to/to_master.sh //表示当切换到master状态时要执行的脚本
notify_backup /path_to/to_backup.sh //表示当切换到backup状态时要执行的脚本
notify_fault "/path/fault.sh VG_1" // keepalived出现故障时执行的脚本
notify /path/to/notify.sh
smtp_alert //表示切换时给global defs中定义的邮件地址发送邮件通知

# VRRP实例(instance)配置范例
vrrp_instance http { //注意vrrp_instance 后面可自定义名称如lvs_httpd ,httpd
state MASTER
interface eth0
dont_track_primary
track_interface {
eth0
eth1
}
mcast_src_ip <IPADDR>
garp_master_delay 10
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
autp_pass 1234
}
virtual_ipaddress {
#<IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPT> label <LABEL>
192.168.200.17/24 dev eth1
192.168.200.18/24 dev eth2 label eth2:1
}
virtual_routes {
# src <IPADDR> [to] <IPADDR>/<MASK> via|gw <IPADDR> dev <STRING> scope <SCOPE> tab
src 192.168.100.1 to 192.168.109.0/24 via 192.168.200.254 dev eth1
192.168.110.0/24 via 192.168.200.254 dev eth1
192.168.111.0/24 dev eth2
192.168.112.0/24 via 192.168.100.254
}
nopreempt
preemtp_delay 300
debug
}

state: state指定instance(Initial)的初始状态就是说在配置好后这台 服务器的初始状态就是这里指定的但这里指定的不算还是得要通过竞选通过优先级来确定里如果这里设置为master但如若他的优先级不及另外一台 那么这台在发送通告时会发送自己的优先级另外一台发现优先级不如自己的高那么他会就回抢占为master

interface: 实例绑定的网卡因为在配置虚拟VIP的时候必须是在已有的网卡上添加的

dont track primary: 忽略VRRP的interface错误

track interface: 跟踪接口设置额外的监控里面任意一块网卡出现问题都会进入故障(FAULT)状态例如用nginx做均衡器的时候内网必须正常工作如果内网出问题了这个均衡器也就无法运作了所以必须对内外网同时做健康检查

mcast src ip: 发送多播数据包时的源IP地址这里注意了这里实际上就是在那个地址上发送VRRP通告这个非常重要一定要选择稳定的网卡端口来发送这里相当于heartbeat的心跳端口如果没有设置那么就用默认的绑定的网卡的IP也就是interface指定的IP地址

garp master delay: 在切换到master状态后延迟进行免费的ARP(gratuitous ARP)请求,默认5s

virtual router id: 这里设置VRID这里非常重要相同的VRID为一个组他将决定多播的MAC地址

priority 100: 设置本节点的优先级优先级高的为master

advert int: 设置MASTER与BACKUP负载均衡之间同步即主备间通告时间检查的时间间隔,单位为秒,默认1s

virtual ipaddress: 这里设置的就是VIP也就是虚拟IP地址他随着state的变化而增加删除当state为master的时候就添加当state为backup的时候删除这里主要是有优先级来决定的和state设置的值没有多大关系这里可以设置多个IP地址

virtual routes: 原理和virtual ipaddress一样只不过这里是增加和删除路由

lvs sync daemon interface: lvs syncd绑定的网卡,类似HA中的心跳检测绑定的网卡

authentication: 这里设置认证

auth type: 认证方式可以是PASS或AH两种认证方式

auth pass: 认证密码

nopreempt: 设置不抢占master,这里只能设置在state为backup的节点上而且这个节点的优先级必须别另外的高,比如master因为异常将调度圈交给了备份serve,master serve检修后没问题,如果不设置nopreempt就会将调度权重新夺回来,这样就容易造成业务中断问题

preempt delay: 抢占延迟多少秒,即延迟多少秒后竞选master

debug:debug级别

notify master:和sync group这里设置的含义一样可以单独设置例如不同的实例通知不同的管理人员http实例发给网站管理员mysql的就发邮件给DBA

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
# VRRP脚本
# 如下所示为相关配置示例
vrrp_script check_running {
script "/usr/local/bin/check_running"
interval 10
weight 10
}

vrrp_instance http {
state BACKUP
smtp_alert
interface eth0
virtual_router_id 101
priority 90
advert_int 3
authentication {
auth_type PASS
auth_pass whatever
}
virtual_ipaddress {
1.1.1.1
}
track_script {
check_running
}
}
# 首先在vrrp_script区域定义脚本名字和脚本执行的间隔和脚本执行的优先级变更,如下所示:
vrrp_script check_running {
script "/usr/local/bin/check_running"
interval 10 #脚本执行间隔
weight 10 #脚本结果导致的优先级变更10表示优先级+10-10则表示优先级-10
}
# 然后在实例(vrrp_instance)里面引用有点类似脚本里面的函数引用一样先定义后引用函数名
track_script {
check_running
}

注意:
VRRP脚本(vrrp_script)和VRRP实例(vrrp_instance)属于同一个级别
keepalived会定时执行脚本并对脚本执行的结果进行分析,动态调整vrrp_instance的优先级。一般脚本检测返回的值为0,说明脚本检测成功,如果为非0数值,则说明检测失败
如果脚本执行结果为0,并且weight配置的值大于0,则优先级相应的增加, 如果weight为非0,则优先级不变
如果脚本执行结果非0,并且weight配置的值小于0,则优先级相应的减少, 如果weight为0,则优先级不变
其他情况,维持原本配置的优先级,即配置文件中priority对应的值。
这里需要注意的是:
1) 优先级不会不断的提高或者降低
2) 可以编写多个检测脚本并为每个检测脚本设置不同的weight
3) 不管提高优先级还是降低优先级,最终优先级的范围是在[1,254],不会出现优先级小于等于0或者优先级大于等于255的情况
这样可以做到利用脚本检测业务进程的状态,并动态调整优先级从而实现主备切换。

virtual_server 虚拟主机配置

关于keeplived的虚拟主机配置有三种如下所示
virtual server IP port
virtual server fwmark int
virtual server group string

以常用的第一种为例
virtual_server 192.168.1.2 80
含义:设置一个virtual server: VIP:Vport

delay_loop 3
含义:设置service polling的delay时间即服务轮询的时间间隔

lb_algo rr|wrr|lc|wlc|lblc|sh|dh
含义:设置LVS调度算法

lb_kind NAT|DR|TUN
含义:设置LVS集群模式

persistence_timeout 120
含义:设置会话保持时间秒为单位即以用户在120秒内被分配到同一个后端realserver,超过此时间就重新分配

persistence_granularity
含义:设置LVS会话保持粒度ipvsadm中的-M参数默认是0xffffffff即每个客户端都做会话保持

protocol TCP
含义:设置健康检查用的是TCP还是UDP

ha_suspend
含义:suspendhealthchecker’s activity

virtualhost
含义:HTTP_GET做健康检查时检查的web服务器的虚拟主机即host头

sorry_server
含义:设置backupserver就是当所有后端realserver节点都不可用时就用这里设置的也就是临时把所有的请求都发送到这里

real_server
含义:设置后端真实节点主机的权重等设置主要后端有几台这里就要设置几个

weight 1
含义:设置给每台的权重0表示失效(不知给他转发请求知道他恢复正常)默认是1

inhibit_on_failure
含义:表示在节点失败后把他权重设置成0而不是冲IPVS中删除

notify_up |
含义:设置检查服务器正常(UP)后要执行的脚本
notify_down |
含义:设置检查服务器失败(down)后要执行的脚本

注:keepalived检查机制说明
keepalived健康检查方式有:HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK几种如下所示

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
#HTTP/HTTPS方式 
HTTP_GET|SSL_GET { #设置健康检查方式

url { #设置要检查的URL可以有多个
path / #设置URL具体路径
digest <STRING> #检查后的摘要信息这些摘要信息可以通过genhash命令工具获取
status_code 200 #设置返回状态码
}
connect_port 80 #设置监控检查的端口
bindto <IPADD> #设置健康检查的IP地址
connect_timeout 3 #设置连接超时时间
nb_get_retry 3 #设置重连次数
delay_before_retry 2 #设置重连间隔
}

#TCP方式
TCP_CHECK {
connect_port 80 #设置监控检查的端口
bindto <IPADD> #设置健康检查的IP地址
connect_timeout 3 #设置连接超时时间
nb_get_retry 3 #设置重连次数
delay_before_retry 2 #设置重连间隔
}
#SMTP方式 (这个可以用来给邮件服务器做集群)
SMTP_CHECK {
host {
connect_ip <IP ADDRESS>
connect_port <PORT> #默认检查25端口
14 KEEPALIVED
bindto <IP ADDRESS>
}
connect_timeout <INTEGER>
retry <INTEGER>
delay_before_retry <INTEGER>
helo_name <STRING>|<QUOTED-STRING>
}

#MISC方式 这个可以用来检查很多服务器只需要自己会些脚本即可
MISC_CHECK {
misc_path <STRING>|<QUOTED-STRING> #外部程序或脚本
misc_timeout <INT> #脚本或程序执行超时时间
misc_dynamic
#这个就很好用了可以非常精确的来调整权重是后端每天服务器的压力都能均衡调配这个主要是通过执行的程序或脚本返回的状态代码来动态调整weight值使权重根据真实的后端压力来适当调整不过这需要有过硬的脚本功夫才行哦
#返回0健康检查没问题不修改权重
#返回1健康检查失败权重设置为0
#返回2-255健康检查没问题但是权重却要根据返回代码修改为返回码-2例如如果程序或脚本执行后返回的代码为200#那么权重这回被修改为 200-2
}

以上就是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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
[root@sg-gop-10-65-32-140 wangao]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}

vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.16
192.168.200.17
192.168.200.18
}
}

virtual_server 192.168.200.100 443 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP

real_server 192.168.201.100 443 {
weight 1
SSL_GET {
url {
path /
digest ff20ad2481f97b1754ef3e12ecd3a9cc
}
url {
path /mrtg/
digest 9b3a0c85a887a256d6939da88aabd8cd
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}

virtual_server 10.10.10.2 1358 {
delay_loop 6
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP

sorry_server 192.168.200.200 1358

real_server 192.168.200.2 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}

real_server 192.168.200.3 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}

virtual_server 10.10.10.3 1358 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 50
protocol TCP

real_server 192.168.200.4 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}

real_server 192.168.200.5 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}

ipvsadm

一般建议和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
58
59
60
61
62
63
64
65
66
67
68
[root@d126009 wangao]# ipvsadm -h
ipvsadm v1.27 2008/5/15 (compiled with popt and IPVS v1.2.1)
Usage:
ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask] [--pe persistence_engine] [-b sched-flags]
ipvsadm -D -t|u|f service-address
ipvsadm -C
ipvsadm -R
ipvsadm -S [-n]
ipvsadm -a|e -t|u|f service-address -r server-address [options]
ipvsadm -d -t|u|f service-address -r server-address
ipvsadm -L|l [options]
ipvsadm -Z [-t|u|f service-address]
ipvsadm --set tcp tcpfin udp
ipvsadm --start-daemon state [--mcast-interface interface] [--syncid sid]
ipvsadm --stop-daemon state
ipvsadm -h

Commands:
Either long or short options are allowed.
--add-service -A add virtual service with options
--edit-service -E edit virtual service with options
--delete-service -D delete virtual service
--clear -C clear the whole table
--restore -R restore rules from stdin
--save -S save rules to stdout
--add-server -a add real server with options
--edit-server -e edit real server with options
--delete-server -d delete real server
--list -L|-l list the table
--zero -Z zero counters in a service or all services
--set tcp tcpfin udp set connection timeout values
--start-daemon start connection sync daemon
--stop-daemon stop connection sync daemon
--help -h display this help message

Options:
--tcp-service -t service-address service-address is host[:port]
--udp-service -u service-address service-address is host[:port]
--fwmark-service -f fwmark fwmark is an integer greater than zero
--ipv6 -6 fwmark entry uses IPv6
--scheduler -s scheduler one of rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq,
the default scheduler is wlc.
--pe engine alternate persistence engine may be sip,
not set by default.
--persistent -p [timeout] persistent service
--netmask -M netmask persistent granularity mask
--real-server -r server-address server-address is host (and port)
--gatewaying -g gatewaying (direct routing) (default)
--ipip -i ipip encapsulation (tunneling)
--masquerading -m masquerading (NAT)
--weight -w weight capacity of real server
--u-threshold -x uthreshold upper threshold of connections
--l-threshold -y lthreshold lower threshold of connections
--mcast-interface interface multicast interface for connection sync
--syncid sid syncid for connection sync (default=255)
--connection -c output of current IPVS connections
--timeout output of timeout (tcp tcpfin udp)
--daemon output of daemon information
--stats output of statistics information
--rate output of rate information
--exact expand numbers (display exact values)
--thresholds output of thresholds information
--persistent-conn output of persistent connection info
--nosort disable sorting output of service/server entries
--sort does nothing, for backwards compatibility
--ops -o one-packet scheduling
--numeric -n numeric output of addresses and ports
--sched-flags -b flags scheduler flags (comma-separated)

测试

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
# 每台realserver index.html文件内容为ip 地址,例如httpd: 
echo "172.27.233.43" > /var/www/html/index.html
echo "172.27.233.44" > /var/www/html/index.html

# Nginx test
echo "rs1" > /usr/share/nginx/html/index.html
echo "rs2" > /usr/share/nginx/html/index.html

# 启动http服务
/etc/init.d/httpd start

# 客户端模拟请求
for((i=1;i<=10;i++));do curl http://172.27.233.45/; done
172.27.233.44
172.27.233.43
172.27.233.44
172.27.233.43
172.27.233.44
172.27.233.43
172.27.233.44
172.27.233.43
172.27.233.44
172.27.233.43

# 请求分配结果
ipvsadm -Ln --stats
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
-> RemoteAddress:Port
TCP 172.27.233.45:80 10 50 0 4330 0
-> 172.27.233.43:80 5 25 0 2165 0
-> 172.27.233.44:80 5 25 0 2165 0

参数含义
--stats 显示统计信息
Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
连接数 输入包 输出包 输入流量 输出流量

# 实时观察
watch ipvsadm -Ln --stats

lvs+keepalived配置实践

防火墙的配置不在本文的范围,请关闭selinux和firewall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 关闭防火墙
systemctl disable firewalld
systemctl stop firewalld

# 禁用selinux
setenforce 0
vi /etc/selinux/config

SELINUX=disabled

# 安装keepalived,ipvsadm
yum install keepalived ipvsadm -y

# 开启LVS服务器的IP路由转发功能
echo "1" > /proc/sys/net/ipv4/ip_forward
# 添加路由转发至sysctl.conf
vi /etc/sysctl.conf
net.ipv4.ip_forward = 1

sysctl -p

最简单的keepalived做HA

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
# 如果开启防火墙,请添加VRRP白名单
# For keepalived
# allow vrrp
-A INPUT -p vrrp -j ACCEPT
-A INPUT -p igmp -j ACCEPT
# allow multicast
-A INPUT -d 224.0.0.18 -j ACCEPT

# 编辑keepalived配置文件
vi /etc/keepalived/keepalived.conf

vrrp_sync_group VI_GOP_NC1_HA {
group {
VI_GOP_NC1_HA_PRI
}
}

vrrp_instance VI_GOP_NC1_HA_PRI {
state BACKUP
interface bond0
virtual_router_id 139
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.65.33.139/23 dev bond0
}
}


配置LVS-NAT

DS

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# Install keepalived
# Ubuntu
apt-get install keepalived ipvsadm
# CentOS
yum install keepalived ipvsadm

# update iptables
vim /etc/sysconfig/iptables

# For keepalived:
# allow vrrp
-A INPUT -p vrrp -j ACCEPT
-A INPUT -p igmp -j ACCEPT
# allow multicast
-A INPUT -d 224.0.0.18 -j ACCEPT

# reload iptables
service iptables reload

# open ip_forward
echo "1" > /proc/sys/net/ipv4/ip_forward
# edit sysctl.conf
vi /etc/sysctl.conf
net.ipv4.ip_forward = 1

sysctl -p

# keepalived for lvs-nat
vim /etc/keepalived/keepalived.conf

vrrp_sync_group NC-MAIN-API {
group {
NC-MAIN-API-PUB
}
}

vrrp_instance NC-MAIN-API-PUB {
state BACKUP
interface bond1
virtual_router_id 222
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
xx.xx.xx.xx/25 dev bond1
}
}

virtual_server xx.xx.xx.xx 15000 {
delay_loop 6
lb_algo rr
lb_kind NAT
protocol TCP

real_server 10.71.12.69 15000 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 15000
}
}
real_server 10.71.12.76 15000 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 15000
}
}
}

RS

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

配置LVS-DR

DS

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# Install keepalived
# Ubuntu
apt-get install keepalived ipvsadm
# CentOS
yum install keepalived ipvsadm

# update iptables
vim /etc/sysconfig/iptables

# For keepalived:
# allow vrrp
-A INPUT -p vrrp -j ACCEPT
-A INPUT -p igmp -j ACCEPT
# allow multicast
-A INPUT -d 224.0.0.18 -j ACCEPT

# reload iptables
service iptables reload

# open ip_forward
echo "1" > /proc/sys/net/ipv4/ip_forward
# edit sysctl.conf
vi /etc/sysctl.conf
net.ipv4.ip_forward = 1

sysctl -p

# keepalived for lvs-dr
vim /etc/keepalived/keepalived.conf

vrrp_sync_group GOP {
group {
VI_PRI_CONNECT
VI_PRI_AUTH
}
}

vrrp_instance VI_PRI_CONNECT {
state BACKUP
interface bond0
virtual_router_id 128
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.65.32.28/23 dev bond0
}
}

virtual_server 10.65.32.28 80 {
delay_loop 6
lb_algo rr
lb_kind DR
protocol TCP

real_server 10.65.32.13 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 10.65.32.14 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

virtual_server 10.65.32.28 443 {
delay_loop 6
lb_algo rr
lb_kind DR
protocol TCP

real_server 10.65.32.13 443 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 443
}
}
real_server 10.65.32.14 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 443
}
}
}

vrrp_instance VI_PRI_AUTH {
state BACKUP
interface bond0
virtual_router_id 129
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.65.32.29/23 dev bond0
}
}

virtual_server 10.65.32.29 80 {
delay_loop 6
lb_algo rr
lb_kind DR
protocol TCP

real_server 10.65.32.22 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 110.65.32.23 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

virtual_server 10.65.32.29 443 {
delay_loop 6
lb_algo rr
lb_kind DR
protocol TCP

real_server 10.65.32.22 443 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 443
}
}
real_server 110.65.32.23 443 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 443
}
}
}


# enable and start keepalived
systemctl start keepalived
systemctl enable keepalived
watch ipvsadm -L -n --stats

RS

  1. Edit “/etc/sysconfig/network-scripts/ifcfg-lo” to patch bug in Centos 7 (if using Centos 7). Add TYPE=Loopback to the file.
  2. Add loopback for each Virtual IP on each worker. E.g. first virtual IP create file “/etc/sysconfig/network-scripts/ifcfg-lo:0”.
  3. Start adapters if not yet started
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# add TYPE=Loopback
echo "TYPE=Loopback" >> /etc/sysconfig/network-scripts/ifcfg-lo
# add ifcfg-lo:0
cat > /etc/sysconfig/network-scripts/ifcfg-lo:0 << EOF
DEVICE=lo:0
IPADDR=10.65.32.28
NETMASK=255.255.255.255
ONBOOT=yes
EOF

# ifup lo:0
ifup lo:0

# add real_start
cat > /root/real_start.sh << EOF
#!/bin/bash
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
EOF

# chmod 755
chmod 755 /root/real_start.sh

# add real.service
cat > /usr/lib/systemd/system/real.service << EOF
[Unit]
Description=autostart lvs real
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/root/real_start.sh

[Install]
WantedBy=multi-user.target
EOF

# enable service
systemctl enable real.service


# lvs real server example
vim /root/lvs_real.sh

#!/bin/bash
### BEGIN INIT INFO
# Provides:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start realserver
# Description: Start realserver
### END INIT INFO

# change the VIP to proper value
VIP=10.65.32.28

case "$1" in
start)

echo "Start REAL Server"
/sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 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

;;

stop)

/sbin/ifconfig lo:0 down
echo "Stop REAL Server"
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

;;

restart)

$0 stop
$0 start

;;

*)

echo "Usage: $0 {start|stop}"
exit 1

;;
esac

exit 0

配置LVS-TUN

DS

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# Install keepalived
# Ubuntu
apt-get install keepalived ipvsadm
# CentOS
yum install keepalived ipvsadm

# update iptables
vim /etc/sysconfig/iptables

# For keepalived:
# allow vrrp
-A INPUT -p vrrp -j ACCEPT
-A INPUT -p igmp -j ACCEPT
# allow multicast
-A INPUT -d 224.0.0.18 -j ACCEPT

# reload iptables
service iptables reload

# open ip_forward
echo "1" > /proc/sys/net/ipv4/ip_forward
# edit sysctl.conf
vi /etc/sysctl.conf
net.ipv4.ip_forward = 1

sysctl -p

# keepalived for lvs-tun
vim /etc/keepalived/keepalived.conf

vrrp_sync_group GOP {
group {
VI_PRI_AUTH
}
}

vrrp_instance VI_PRI_AUTH {
state BACKUP
interface em1
virtual_router_id 11
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.10.36.11/23 dev em1
}
}

virtual_server 10.10.36.11 80 {
delay_loop 6
lb_algo rr
lb_kind TUN
protocol TCP

real_server 10.10.36.4 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 10.10.36.7 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

# enable and start keepalived
systemctl start keepalived
systemctl enable keepalived
watch ipvsadm -L -n --stats


# 编写DS脚本,推荐用keepalived配置文件
#!/bin/sh
# Startup script handle the initialisation of LVS
# chkconfig: - 28 72
# description: Initialise the Linux Virtual Server for TUN
#
### BEGIN INIT INFO
# Provides: ipvsadm
# Required-Start: $local_fs $network $named
# Required-Stop: $local_fs $remote_fs $network
# Short-Description: Initialise the Linux Virtual Server
# Description: The Linux Virtual Server is a highly scalable and highly
# available server built on a cluster of real servers, with the load
# balancer running on Linux.
# description: start LVS of TUN
LOCK=/var/lock/lvs-tun.lock
VIP=10.10.36.11
RIP1=10.10.36.4
RIP2=10.10.36.7
. /etc/rc.d/init.d/functions

start() {
PID=`ipvsadm -Ln | grep ${VIP} | wc -l`
if [ $PID -gt 0 ];

then
echo "The LVS-TUN Server is already running !"
else
#Load the tun mod
/sbin/modprobe tun
/sbin/modprobe ipip
#Set the tun Virtual IP Address
/sbin/ifconfig tunl0 $VIP broadcast $VIP netmask 255.255.255.255 up
/sbin/route add -host $VIP dev tunl0
#Clear IPVS Table
/sbin/ipvsadm -C
#The icmp recruit setting
echo "0" >/proc/sys/net/ipv4/ip_forward
echo "0" >/proc/sys/net/ipv4/conf/all/send_redirects
echo "0" >/proc/sys/net/ipv4/conf/default/send_redirects
#Set Lvs
/sbin/ipvsadm -At $VIP:80 -s rr
/sbin/ipvsadm -at $VIP:80 -r $RIP1:80 -i -w 1
/sbin/ipvsadm -at $VIP:80 -r $RIP2:80 -i -w 1
/bin/touch $LOCK
#Run Lvs
echo "starting LVS-TUN-DIR Server is ok !"
fi
}

stop() {
#stop Lvs server
/sbin/ipvsadm -C
/sbin/ifconfig tunl0 down >/dev/null
#Remove the tun mod
/sbin/modprobe -r tun
/sbin/modprobe -r ipip
rm -rf $LOCK
echo "stopping LVS-TUN-DIR server is ok !"
}

status() {
if [ -e $LOCK ];
then
echo "The LVS-TUN Server is already running !"
else
echo "The LVS-TUN Server is not running !"
fi
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 1
start
;;
status)
status
;;
*)
echo "Usage: $1 {start|stop|restart|status}"
exit 1
esac
exit 0

RS

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# 在加载好ipip模块后就会有默认的tunl0隧道
modprobe ipip

# 添加VIP
# ifconfig tunl0 down
ifconfig tunl0 10.10.36.11 broadcast 10.10.36.11 netmask 255.255.255.255 up

# 添加路由
route add -host 10.10.36.11 tunl0

# 手动关闭ARP转发
echo '1' > /proc/sys/net/ipv4/conf/tunl0/arp_ignore
echo '2' > /proc/sys/net/ipv4/conf/tunl0/arp_announce
echo '1' > /proc/sys/net/ipv4/conf/all/arp_ignore
echo '2' > /proc/sys/net/ipv4/conf/all/arp_announce
echo '0' > /proc/sys/net/ipv4/conf/tunl0/rp_filter
echo '0' > /proc/sys/net/ipv4/conf/all/rp_filter

# iptables允许ipip协议
iptables -I INPUT 1 -p 4 -j ACCEPT
vim /etc/sysconfig/iptables
-A INPUT -p ipv4 -j ACCEPT

# 编写RS启停脚本
vim /etc/init.d/lvs-tun

#!/bin/sh
#
# Startup script handle the initialisation of LVS
# chkconfig: - 28 72
# description: Initialise the Linux Virtual Server for TUN
#
### BEGIN INIT INFO
# Provides: ipvsadm
# Required-Start: $local_fs $network $named
# Required-Stop: $local_fs $remote_fs $network
# Short-Description: Initialise the Linux Virtual Server
# Description: The Linux Virtual Server is a highly scalable and highly
# available server built on a cluster of real servers, with the load
# balancer running on Linux.
# description: start LVS of TUN-RIP
LOCK=/var/lock/ipvsadm.lock
VIP=10.10.36.11
. /etc/rc.d/init.d/functions
start() {
PID=`ifconfig | grep tunl0 | wc -l`
if [ $PID -ne 0 ];
then
echo "The LVS-TUN-RIP Server is already running !"
else
#Load the tun mod
/sbin/modprobe tun
/sbin/modprobe ipip
#Set the tun Virtual IP Address
/sbin/ifconfig tunl0 $VIP netmask 255.255.255.255 broadcast $VIP up
/sbin/route add -host $VIP dev tunl0
echo "1" >/proc/sys/net/ipv4/conf/tunl0/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/tunl0/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "0" > /proc/sys/net/ipv4/conf/tunl0/rp_filter
echo "0" > /proc/sys/net/ipv4/conf/all/rp_filter
/bin/touch $LOCK
echo "starting LVS-TUN-RIP server is ok !"
fi
}

stop() {
/sbin/ifconfig tunl0 down
echo "0" >/proc/sys/net/ipv4/conf/tunl0/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/tunl0/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
#Remove the tun mod
/sbin/modprobe -r tun
/sbin/modprobe -r ipip
rm -rf $LOCK
echo "stopping LVS-TUN-RIP server is ok !"
}

status() {
if [ -e $LOCK ];
then
echo "The LVS-TUN-RIP Server is already running !"
else
echo "The LVS-TUN-RIP Server is not running !"
fi
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo "Usage: $1 {start|stop|restart|status}"
exit 1
esac
exit 0

# start lvs-tun
chmod 755 /etc/init.d/lvs-tun
service lvs-tun start
chkconfig lvs-tun on

# Nginx test
echo "rs1" > /usr/share/nginx/html/index.html
echo "rs2" > /usr/share/nginx/html/index.html

for i in {1..100}; do curl 10.10.36.11; sleep 0.5; done

这一步的主要目的是让 RS 禁言,在相对较新的版本中新增了两个内核参数 (kernel parameter)

  • 第一个是 arp_ignore 定义接受到 ARP 请求时的相应级别
  • 第二个是 arp_announce 定义将自己地址向外通告是的通告级别
  • 第三个是 rp_filter 定义系统是否开启对数据包源地址的校验

总结: LVS/TUN 是所有模式中最最适用于跨网络跨地域地理位置的一种模式,需要注意的是:

  1. 若 DIR 和 RIP 在不同 lan 网络中,比如不同的网段,不同的 IDC 机房,就不需要设置 arp 仰制,不同网段中,arp 会被屏蔽掉,所以只需设置 ip tunne 以及报文反向验证即可;
  2. 若 DIR 和 RIP 在同一广播域中,需要和 LVS/DR 模式一样在所有的 RIP 上仰制 arp,防止 arp 响应导致 arp 表混乱,这样 lvs 就不能正常工作!

配置时除了配置 DIR,还需要需要配置后端 RS server,即在 tunl 上口配置 vip 地址(需要系统支持 tunl 才行),广播为为自己,此模式下无需开启路由转发功能!

配置LVS/DR和LVS/TUN混合模式

DS

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# 关于3中模式的参数
[packet-forwarding-method]
-g, --gatewaying Use gatewaying (direct routing). This is the default.
-i, --ipip Use ipip encapsulation (tunneling).
-m, --masquerading Use masquerading (network access translation, or NAT).
Note: Regardless of the packet-forwarding mechanism specified, real servers for addresses for which there are interfaces on the local node will be use the
local forwarding method, then packets for the servers will be passed to upper layer on the local node. This cannot be specified by ipvsadm, rather it set by
the kernel as real servers are added or modified.

# ipvsadm命令行混配
/sbin/ifconfig tunl0 10.10.36.11 broadcast 10.10.36.11 netmask 255.255.255.255 up
/sbin/route add -host 10.10.36.11 dev tunl0
/sbin/ipvsadm -At 10.10.36.11:80 -s rr
/sbin/ipvsadm -at 10.10.36.11:80 -r 10.10.36.4:80 -g -w 1
/sbin/ipvsadm -at 10.10.36.11:80 -r 10.10.36.7:80 -i -w 1

# keepalived混配
vrrp_sync_group GOP {
group {
VI_PRI_AUTH
}
}

vrrp_instance VI_PRI_AUTH {
state BACKUP
interface em1
virtual_router_id 11
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.10.36.11/23 dev em1
}
}

virtual_server 10.10.36.11 80 {
delay_loop 6
lb_algo rr
lb_kind DR
protocol TCP

real_server 10.10.36.4 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

virtual_server 10.10.36.11 80 {
delay_loop 6
lb_algo rr
lb_kind TUN
protocol TCP

real_server 10.10.36.7 80 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}

# 检查结果可用
[root@d126027 wangao]# for i in {1..100}; do curl 10.10.36.11; sleep 0.5; done
rs2
rs1
rs2
rs1
rs2

[root@d126009 keepalived]# ipvsadm -Ln --stats
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
-> RemoteAddress:Port
TCP 10.10.36.11:80 100 700 0 36700 0
-> 10.10.36.4:80 50 350 0 18350 0
-> 10.10.36.7:80 50 350 0 18350 0

RS

DR和TUN的模式基本不用做改动

LVS 部署之细枝末节

原作者写得很详细,我这边做下引用在此表示感谢,LVS 部署之细枝末节

简介

本文总结了在 LVS 部署过程中需要注意的一些小细节。这些内容比较杂,并且没有规律和内在联系;它们分散在 LVS 部署过程中的各个小环节中,不是系统性的知识,也没有主线对它们进行连接。你可以通过此文对他们进行一个大概的了解,在实践过程中如果遇到可以再过来进行详细的查阅,以解决实际问题。

开启 Linux 的路由转发功能

LVS 在 VS/NAT 方式下需要开启数据包转发 (ip_forward) 功能。因为在 LVS 的 VS/NAT 模式下,对 IP 数据进行负载均衡时,需要把多台真实服务器节点中的专网 IP 映射到同一个虚拟服务器的公网 IP 上;这就需要通过 NAT 技术对 IP 数据包进行转发,从而将 IP 数据包发送到真实服务器上进行处理。LVS 在 VS/DR 模式下,因为 director 的 DIP 与真实服务器节点的 RIP 在同一网段,所以不需要开启路由转发功能。LVS 在 VS/TUN 模式下,IP 数据包是通过 IP 隧道技术进行封包后再分发的方式到达真实服务器节点的,也不需要开启路由转发功能。

开启 Linux 的路由转发功能的方法很多,具体细节请参阅文章 Linux ip_forward 数据包转发

配置真实服务器的 ARP 请求与响应策略

在 ARP 协议中,为了减少 arp 请求的次数,当主机接收到询问自己的 arp 请求的时候,就会把源 ip 和源 Mac 放入自 己的 arp 表里面,方便接下来的通讯。如果收到不是询问自己的包(arp 是广播的,所有人都收到),就会丢掉,这样不会造成 arp 表里面无用数据太多导致 有用的记录被删除。

在 LVS 的 VS/DR 模式下,当内网的真实服务器(Linux 主机)要发送一个到外部网络的 ip 包(LVS 负载器分配置过来的作业的处理结果),那么它就会请求路由器的 Mac 地址,发送一个 arp 请求,这个 arp 请求里面包括了自己的 ip 地址和 Mac 地址。而 linux 主机默认是使用 ip 数据包的源 ip 地址作为 arp 里面的源 ip 地址,而不是使用发送设备上面网络接口卡的 ip 地址。这样在 LVS 的 VS/DR 架构下,所有真实服务器在响应外部请求时的 IP 数据包的源地址都是同一个 VIP 地址,那么 arp 请求就会包括 VIP 地址和设备 Mac。而路由器收到这个 arp 请求就会更新自己的 arp 缓存,这样就会造成 ip 欺骗了,VIP 被抢夺,所以就会有问题。

所以当 LVS 运行在 VS/DR 模式下时,需要在所有真实服务器上修改 ARP 请求与响应策略,以保证以上问题不会发生。

因为在 lo(本地环回网络接口)上配置了 VIP,所以需要对真实服务器中的 ARP 请求与响应策略配置如下:

1
2
3
4
5
6
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.lo.arp_ignore=1

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

将以上代码段追加到 /etc/sysctl.conf 文件中,然后执行 sysctl -p 指令就可以。以上配置的具体含义请参阅 Linux 内核参数 arp_ignore & arp_announce 详解

在 VS/DR 模式下 VIP 、DIP 和 RIP 必须在同一网段吗?

在 VS/DR 模式下 VIP 、DIP 和 RIP 不需要在同一网段!

其中 VIP 必须是公网 IP;而 DIP 和 RIP 必须在同一网段(可以是任意网段的 IP,也可以是私网 IP),且需要节点主机的 RIP 可以把 IP 数据包发送到一个能把 IP 数据包路由到公网的路由器上。

其实 LVS 在 VS/DR 模式下的要求是 DIP 和 RIP 必须处于同一网段中。在实际的部署过程中发现如果在 Director 上 VIP 和 DIP 在同一网段、或在 RealServer 上 VIP 与 RIP 在同一网段,LVS 集群工作会很不稳定。因为当一个 IP 数据包需要发到默认网关时(在 RealServer 或 Director 上),Linux 主机不知道应该使用哪个接口(在同一子网中的 VIP 和 DIP/RIP),他可能会随机选一个,但这个不一定能成功。我感觉可以通过在 Linux 中配置路由表来解决,但没有验证(哪位同学如果有兴趣可以实践验证一下,如果能把验证结果反馈给我那是再好不过了)。

配置真实服务器的 反向路由过滤 策略

在 Linux 中用于对 网卡的反向路由过滤策略进行配置的内核参数是 rp_filter,有关此参数的详细介绍以及配置方式请参见 Linux 内核参数 rp_filter

LVS 在 VS/TUN 模式下,需要对 tunl0 虚拟网卡的反向路由过滤策略进行配置。最直接的办法是把其值设置为 0。

1
2
3
net.ipv4.conf.tunl0.rp_filter=0
net.ipv4.conf.all.rp_filter=0

因为 Linux 系统在对网卡应用反向路由过滤策略时,除了检查本网卡的 rp_filter 参数外,还会检查 all 配置项上的 rp_filter 参数,并使用这两个值中较大的值作为应用到当前网卡的反向路由过滤策略。所以需要同时把 net.ipv4.conf.all.rp_filter 参数设置为 0。

配置 tunl0 网卡

LVS 在 VS/TUN 模式下,需要在每个真实服务器上开启 tunl0 网卡,并把 VIP 配置到 tunl0 网卡上。有关 tunl0 网卡的说明可以参考一下 Linux 中 IP 隧道模块浅析

LVS 在 VS/TUN 模式下 RealServer 上的防火墙配置

LVS 在 VS/TUN 模式下 因为 Director 主机需要通过 ipip 协议向 RealServer 分发数据包;所以需要在 RealServer 上配置防火墙,允许 ipip 协议的数据包通过。

1
2
iptables -I INPUT 1 -p 4 -j ACCEPT

常见问题

配置日志

此配置为可选步骤

keepalived 默认将日志输出到系统日志/var/log/messages中,因为系统日志很多,查询问题时相对麻烦。

我们可以将 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
# 修改 Keepalived 配置
vi /etc/sysconfig/keepalived

# Options for keepalived. See `keepalived --help' output and keepalived(8) and
# keepalived.conf(5) man pages for a list of all options. Here are the most
# common ones :
#
# --vrrp -P Only run with VRRP subsystem.
# --check -C Only run with Health-checker subsystem.
# --dont-release-vrrp -V Dont remove VRRP VIPs & VROUTEs on daemon stop.
# --dont-release-ipvs -I Dont remove IPVS topology on daemon stop.
# --dump-conf -d Dump the configuration data.
# --log-detail -D Detailed log messages.
# --log-facility -S 0-7 Set local syslog facility (default=LOG_DAEMON)
#

# 把 KEEPALIVED_OPTIONS=”-D” 修改为 KEEPALIVED_OPTIONS=”-D -d -S 0”,其中 -S 指定 syslog 的 facility
KEEPALIVED_OPTIONS="-D -d -S 0"

# 修改 /etc/rsyslog.conf 末尾添加
vi /etc/rsyslog.conf
local0.* /var/log/keepalived.log

# 重启日志记录服务
systemctl restart rsyslog

# 重启 keepalived
systemctl restart keepalived

# 此时可以从 /var/log/keepalived.log 查看日志了
tailf /var/log/keepalived.log

ARP导致MAC地址冲突

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
[root@sg-gop-10-65-32-35 wangao]# arp -n
Address HWtype HWaddress Flags Mask Iface
10.65.32.31 ether 48:8e:ef:7b:c6:0a C bond0
10.65.32.83 ether 50:5d:ac:ed:89:dd C bond0
10.65.32.254 ether 00:00:0c:9f:f0:ec C bond0
10.65.32.252 ether bc:16:65:68:07:81 C bond0
10.65.32.34 ether 50:1d:93:f5:eb:97 C bond0
10.65.32.8 ether 48:8e:ef:7c:0a:8d C bond0
10.65.32.253 ether 18:e7:28:97:e5:01 C bond0
[root@sg-gop-10-65-32-35 wangao]# arp -d 10.65.32.31
[root@sg-gop-10-65-32-35 wangao]#
[root@sg-gop-10-65-32-35 wangao]#
[root@sg-gop-10-65-32-35 wangao]# telnet 10.65.32.31 12100
Trying 10.65.32.31...
Connected to 10.65.32.31.
Escape character is '^]'.

[root@sg-gop-10-65-32-35 wangao]# arp -n
Address HWtype HWaddress Flags Mask Iface
10.65.32.31 ether 48:8e:ef:7b:c7:5a C bond0
10.65.32.70 ether 00:2e:c7:3a:a5:b5 C bond0
10.65.32.83 ether 50:5d:ac:ed:89:dd C bond0
10.65.32.254 ether 00:00:0c:9f:f0:ec C bond0
10.65.32.252 ether bc:16:65:68:07:81 C bond0
10.65.32.34 ether 50:1d:93:f5:eb:97 C bond0
10.65.32.8 ether 48:8e:ef:7c:0a:8d C bond0
10.65.32.253 ether 18:e7:28:97:e5:01 C bond0

LVS和Keepalived系列

LVS和Keepalived的原理介绍和配置实践
LVS原理介绍和配置实践
Keepalived原理介绍和配置实践
LVS-NAT原理介绍和配置实践
LVS-DR原理介绍和配置实践
LVS-TUN原理介绍和配置实践

文章目录
  1. 1. 前言
  2. 2. 更新历史
  3. 3. ReadMe
    1. 3.1. 参考文章
    2. 3.2. 相关术语
  4. 4. 负载均衡(LB)
  5. 5. LVS+Keepalived 简介
  6. 6. LVS
    1. 6.1. 基本工作原理
    2. 6.2. LVS的组成
    3. 6.3. 工作模式
      1. 6.3.1. LVS/NAT
      2. 6.3.2. LVS/DR
      3. 6.3.3. LVS/TUN
      4. 6.3.4. LVS/FULLNAT
    4. 6.4. 调度算法
  7. 7. keepalived
    1. 7.1. 运行原理
    2. 7.2. 选举策略
  8. 8. keepalived的配置文件说明
    1. 8.1. 全局定义
    2. 8.2. VRRPD配置
    3. 8.3. virtual_server 虚拟主机配置
  9. 9. ipvsadm
    1. 9.1. 命令
    2. 9.2. 测试
  10. 10. lvs+keepalived配置实践
    1. 10.1. 最简单的keepalived做HA
    2. 10.2. 配置LVS-NAT
      1. 10.2.1. DS
      2. 10.2.2. RS
    3. 10.3. 配置LVS-DR
      1. 10.3.1. DS
      2. 10.3.2. RS
    4. 10.4. 配置LVS-TUN
      1. 10.4.1. DS
      2. 10.4.2. RS
    5. 10.5. 配置LVS/DR和LVS/TUN混合模式
      1. 10.5.1. DS
      2. 10.5.2. RS
  11. 11. LVS 部署之细枝末节
    1. 11.1. 简介
    2. 11.2. 开启 Linux 的路由转发功能
    3. 11.3. 配置真实服务器的 ARP 请求与响应策略
    4. 11.4. 在 VS/DR 模式下 VIP 、DIP 和 RIP 必须在同一网段吗?
    5. 11.5. 配置真实服务器的 反向路由过滤 策略
    6. 11.6. 配置 tunl0 网卡
    7. 11.7. LVS 在 VS/TUN 模式下 RealServer 上的防火墙配置
  12. 12. 常见问题
    1. 12.1. 配置日志
    2. 12.2. ARP导致MAC地址冲突
  13. 13. LVS和Keepalived系列