基于lvs实现4层负载均衡

Linux Virtual Server Linux虚拟服务器

章文嵩:研发,原就职alibaba公司,目前就职滴滴;

l4(layer 4):四层路由或四层交换
根据请求报文的目标IP和目标PORT,将其进行调度转发至后端的某RS;根据调度算法来挑选RS;

ipvsadm/ipvs类似于iptables/netfilter
iptables/netfilter
iptables:是用户空间的命令行工具;
netfilter:是内核空间框架;

流入:PREROUTING --> INPUT
转发:PREROUTING --> FORWARD --> POSTROUTING
流出:OUTPUT --> POSTROUTING

DNAT:目标地址转换; PREROUTING;
SNAT:源地址转换;POSTROUTING;

lvs:2部分组成
ipvsadm:用户空间的命令行工具;用于管理集群服务及集群服务上的RS;
ipvs:是内核中的框架;工作于内核上的netfilter的INPUT钩子上的程序,可根据用户定义的集群实现请求转发;

注意:在lvs主机上,不允许在INPUT链上添加规则,一般不建议与ipvs一同使用filter规则;更不能使用nat规则,任何链接追踪功能都不能开启,链接会话表就限制了会话能力,否则,并发响应能力将大大受到限制;

支持基于TCP UDP SCTP AH EST AH_EST等协议及端口进行调度;

lvs集群的专用术语:

vs:Virtual Server虚拟服务器,Director调度器,Dispatcher分发器,Balancer均衡器
rs:Real Server 后端主机

CIP:Client IP 客户端IP地址;
VIP:Virtual Server IP 面向客户端服务的IP地址,不是固定配置在主机上,需要在两个节点间流动,因为当前主机挂了,备用主机替换上,一般配置在网卡别名上,作为辅助地址存在;
DIP:Director IP 调度器的IP,用于与后端服务器通信的IP地址;
RIP:Real Server IP 后端主机IP地址;一般不止一个;

lvs集群的4类工作模式

以下部分内容摘自于:https://www.jianshu.com/p/5184c6564ee2

lvs-nat

多目标的DNAT;通过将请求报文中的目标地址和目标端口修改为挑选出的某RS的RIP和PORT实现转发;

ipvs工作在INPUT链上,所以只有在INPUT链上才能判断出集群服务,然后才能向后转发,转发时,基于某种调度算法,ipvs自动从后端主机中挑选出一个来响应用户请求,挑选出的主机IP会成为报文目标IP的修改对象;
定义负载均衡集群服务时,要定义集群服务,集群服务的真实主机;

nat应用场景逻辑图

上图为lvs-nat的常见的使用场景,其工作流程如下:
1、客户端的请求发往Director 的VIP。
2、Director发到客户端请求报文后,将报文中的目标Ip修改为集群中的选定的RIP,目标端口80也修改成8080,然后将请求报文发往RS。
3、当RS收到请求报文后,在检查报文的目标IP为自己的RIP后,会接受报文并进行处理响应。响应的源Ip为RIP,目标IP为CIP,端口不变。
4、Director收到RS的响应报文,修改响应报文的源IP为VIP,端口为80,然后转发给客户端。
5、客户端接受响应报文,其源IP为VIP,端口为80,整个过程对于客户端来说是透明无感知的。

特点

(1)RIP和DIP必须在同一IP网络,且应该使用私有地址;RS的网关必须指向DIP(保证响应报文必须经由VS);
(2)请求报文和响应报文都经由Director转发,较高负载下,Director易于成为系统性能瓶颈;
(3)支持端口映射;后端真实主机尽量为同一端口;
(4)VS必须是Linux,RS可以是任意OS(操作系统);

lvs-dr

Director Routing 直接路由,默认lvs工作类型

通过修改请求报文的MAC地址,重新封装一个MAC首部进行转发;源MAC是DIP所在接口的MAC地址,目标MAC是挑选出的某RS的RIP所在接口的MAC地址;IP首部不会发生变化(依然是CIP<-->VIP)

lvs服务主机与后端服务器主机接在同一交换机上,且每个后端主机都配有vip,为了避免地址冲突,把各后端主机配置的vip进行隔离;

隔离的方法有3种

  • 可使用arptables命令,专门控制进行arp广播隔离;
  • Linux内核较新版本中,提供了一个精巧的开关,也能够实现隔离;
  • 在前端lvs服务器上游的路由器上绑定lvs的MAC地址与vip地址;此方法,较为不便,一般路由器由运营商负责,且lvs服务器主机会有两个,所以绑定MAC后,当一台坏了时,另一台则不能通过路由器与外界通信;
特点

(1)确保前端路由器将目标IP为VIP的请求报文转发往Director;

解决方案:3种
1.在路由器上静态绑定VIP和Dieretor的MAC地址;
禁止RS响应VIP的ARP请求,禁止RS的VIP进行通告;
2.arptables
3.修改RS的内核参数,并把VIP绑定lo的别名上;
arp_ignore,arp_announce

(2)RS的RIP可以使用私有地址,也可以使用公网地址;
(3)RS跟Director必须在同一物理网络(基于MAC地址转发);RS的网关必须不能指向DIP;
(4)请求报文必须由Directory调度,但响应报文必须不能经由Director;
(5)不支持端口映射;
(6)RS可以使用大多数的OS;一般都为Linux系统;

lvs-dr应用场景

上图为lvs-dr的常见的使用场景,其工作流程如下:
1、客户端的请求会发往Director,此时,客户端请求报文的源Ip为CIP,目标Ip为Director的VIP。
2、当Director接受到客户端的请求报文后,Director会在请求报文外封装一个MAC首部,其源MAC为Director接口的MAC地址,目标MAC为选定RS的MAC地址;
3、当RS收到Director转发过来的请求报文后,检查发现请求报文的目标Ip为本地环回接口上配置的VIP,因此会接受报文进行响应处理。另外由于对ARP响应规则做了修改,因此RS不会把响应报文响应给director ,而是响应给GW;
4、客户端接收响应报文,完成通信。

lvs-tun

tunnel,lvs隧道模型
转发方式:不修改请求报文的IP首部(源IP为CIP,目标IP为VIP),而是源IP首部之外再封装一个IP首部(源IP为DIP,目标IP为挑选出的RS的RIP);ip报文上承载ip报文;

请求报文源IP为cip,目标IP为vip,到达lvs服务进入INPUT链上,在整个ip报文外又加了一层ip首部,即IP报文传输IP报文所以叫IP隧道,此时外层源IP为dip,目标IP为某一个被挑选出来远端的rip,远端的服务主机收到报文经过不断拆包后,将响应报文发给客户端,构建响应报文的源IP为rip,目标IP为cip;

特点

(1)RIP,DIP,VIP全得是公网地址;
(2)RS网关不能指向也不可能指向DIP;
(3)请求报文经由Director转发,但响应报文将直接发往CIP;
(4)不支持端口映射;
(5)RS的OS必须支持隧道功能;

lvs-tun应用逻辑图

lvs-fullnat

不是lvs的标准模型;淘宝研发;
通过同时修改请求报文的源IP地址(CIP-->DIP)和目标IP地址(VIP-->RIP)进行转发;
其实,是nat模型是一种转换;lvs服务器可通过路由器连接后端服务器,即后端服务器可在远端;

特点:

(1)VIP是公网地址,RIP和DIP一般是私网地址,且通常不再同一网络中,但需要经由路由器互通;
(2)RS收到的请求报文源IP为DIP,因此响应报文将直接响应给DIP;
(3)请求和响应报文都经由Director;
(4)支持端口映射;
(5)RS可以使用大多数的OS;

负载均衡集群中会话保持的方式
(1)原地址哈希;
(2)会话集群;
(3)会话服务器;

fullnat应用场景逻辑图

如上图所示:
1.客户端的请求会发往Director,此时,客户端请求报文的源IP为CIP,目标IP为Director的VIP
2.当Director收到客户端的请求报文时,会将源IP修改为本机的DIP,同时将请求报文中的目标IP修改为后端某个RS的RIP,具体为哪个RS的RIP,取决于LVS使用的具体算法
3.当RS收到对应的请求报文时,会发现报文的目标IP就是自己的RIP,于是就会接收报文并处理后进行响应。响应报文的源IP则为RIP,目标IP则为DIP
4.当Director收到对应的响应报文时,Director会将响应报文的源IP修改为VIP,目标IP修改为CIP,于是响应报文被发往客户端。
5.客户端则会收到响应报文,源IP为VIP,端口为80,而LVS相对于客户端而言,转换过程是透明的。

lvs scheduler(lvs调度方法)

根据其调度时是否考虑后端主机的当前负载,可分为静态方法动态方法两类

静态调度方法

仅根据算法本身进行调度

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

  • WRR:Weighted RR,加权轮询,基于权重的方式;
    调度器通过加权轮叫调度算法,根据真实服务器的不同处理能力来调度访问请求;这样可以保证处理能力强的服务器处理更多的访问流量;调度器可以自动询问真实服务器的负载情况,并动态地调整其权值;

  • SH:Source Hashing,源地址哈希;
    功能:保存会话时才用到;
    来自于同一IP地址的请求,始终发往同一个真实服务器,从而实现会话保持的功能,根据原地址挑选真实服务器;把原地址与挑选真实服务器绑定起来;

基于客户端瘦cookie+服务器端的session机制,在负载均衡时,同一用户被调度不同后端服务器时,为了保持会话连接功能不丢失;当第一次用户请求时,通过调度机制给该用户分配了一个负责响应后端服务器,以后来自该用户的请求就由这个服务器负责响应了,而不再调度,这就叫源地址哈希

在调度器上有会话追踪表,在这个会话追踪模板中,把用户的IP地址和挑选的后端服务器对应的记录下来,而且定义一个超时时长,在定义的时间内该条目不会删除;所以,用户请求到来时,先检查这个表,把原IP当做k查找,因为哈希就是k/v数据,对应的v就是后端的真实服务器;如果检查有用户的IP对应的记录,则直接将请求报文发给记录中对应的后端真实服务器,而不通过调度;

缺陷:当记录的真实服务器挂了时,就没有会话保持记录了;当内网用户同过同一IP地址访问外网时,可能会把内网用户的所有请求都发往会话记录表上的真实服务器,这样负载均衡能力是受到损害的;

解决办法

方法一:
可在更高层级实现,基于cookie做绑定,但是cookie是应用层数据,所以lvs在内核,不能通过lvs实现;但,htpd,nginx可实现;
方法二:
要想通过lvs解决,可以把几个lvs服务器做一个session集群,是实现会话同步的集群,每一个节点创建会话后,通过网络协议,会立即同步到其它节点,这样,每一台节点上保存的都是全局的所有会话,任何一台节点挂了,用户请求被重新调度时会话不会丢失;如果有30台服务器,每一台服务器都要同步所有服务器上的session会话信息,会给服务器带来很大压力,所以此种方法仅适用于小规模的真实主机集群的场景;后面讲tomcat时,演示session集群;
方法三:
可用一个session服务器做共享存储,一般在后端当存储的节点为专用的k/v数据存储;例如memche,radis;

  • DH:Destination Hashing,目标地址哈希;
    保存的是目标地址,通常用在正向web代理(有缓存功能),负载均衡内网用户对外部服务器的请求;
    哈希的是目标地址;

内网用户请求的目标地址,在调度器上把目标地址绑定到一个代理缓存服务器上,以后,任何用户访问的是该目标地址就发往绑定的代理服务器,代理服务器收到请求后,再发往后端服务器主机,从而实现正向代理负载均衡的作用;

动态调度方法

根据算法及各RS当前的负载状态进行调度;Overhead=
计算各RS当前的负载状态,通过Overhead值表示;

  • LC:least connections,最少连接;
    Overhead=Active数量*256+Inactive
    通过最少路径调度算法动态地将网络请求调度到已经建立的链接数最少的服务器上;如果集群系统的真实服务器具有相近的系统性能,采用最小链接调度算法可以较好的均衡负载;

  • WLC:Weight LC,加权的最少连接;是通用方法,即考虑了算法又考虑了服务器负载,默认的调度方法;
    Overhead=(Active数*256+Inactive)/weight
    在集群系统中的服务器性能差异较大的情况下,调度器采用加权最少链接调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载;调度器可以自动询问真实服务器的负载情况,并动态地调整其权值;
    缺陷:如果权值最小的服务器排在第一行,每次会响应客户端请求,这样对权值大的服务器利用率就不是很高;

  • SED:Shortes Expections Delay
    Overhead=(Active+1)*256/weight
    弥补了WLC的缺点;但又出现了缺点:权值最小的服务器,在其它权值较大服务器负载较大时才工作;放弃了非活动链接的考量;

  • NQ:Never Queue 从不排队
    是SED的改进,弥补了SED的缺点;请求到来后,会按权值大小,都会分配每个服务器来响应客户端请求;放弃了非活动链接的考量;

  • LBLC:Locality-Based LC
    基于本地的LC,其实就是动态的DH算法,考虑了服务器的负载;损失了命中率,提高了均衡性;
    针对目标IP地址的负载均衡,目前主要用于cache集群系统;该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若改服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用最少链接的原则选出一个可用的服务器,将请求发送到该服务器;

  • LBLCR:LBLC with Replication
    带复制的LBLC;
    也是针对目标IP地址的负载均衡,目前主要用于cache集群系统;它与LBLC算法的不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射;该算法根据请求的目标IP地址找出该目标IP地址对应的服务器组,按最小链接原则从服务器组中选出一台服务器,若服务器没有超载,将请求发往该服务器,若服务器超载,则按最小链接原则从这个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发往该服务器;同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度;

ipvs实现

  • ipvs:工作在内核中的协议栈上实现
  • ipvsadm:工作在用户空间的集群服务器管理工具

ipvs工作模式:就是在filter的input链上附加了一段代码,就称为ipvs功能;类似于钩子一样,能够根据定义的集群规则,监控任何一个送往input链上的请求报文,且请求报文中所请求的目标地址和端口被定义成了集群服务,则会根据调度方法和集群类型,强行修改报文的流程到postrouting;一般定义lvs集群时,一定要跟filter分隔,不能同iptables一块使用,尤其不能跟filter表一起使用;
因为ipvs在内核中工作的特性,解脱了套接字文件数量和套接字自身数量的限制,使得ipvs在优化得当的场景中看,负载能力可达数百个;

ipvs功能特别强大,一般网站用到的可能性比较小,但面试必会问到;
如果负载不是特别大,使用配置比较麻烦,维护成本较大;

ipvs/ipvsadm的关系相当于netfilter/iptables的关系;
真正提供lvs服务的是ipvs;

根据目标ip和目标端口进行转发;
一个ipvs(Director)主机可以同时定义多个cluster service;
一个ipvs服务至少应该有一个rs;

因为是根据请求的目标ip地址和目标端口(能识别协议)进行转发;一个ipvs(Director)主机就可同时为多个集群提供服务进行调度;这就是四层交换的原因;只不过一个Director很有可能成为负载均衡的瓶颈;

注意:单个Director可同时为多个集群提供调度服务;

在centos 7系统上:
判断内核是否支持ipvs:

[root@VM_0_2_centos ~]# grep -i "IPVS" /boot/config-3.10.0-327.el7.x86_64 
显示:
CONFIG_NETFILTER_XT_MATCH_IPVS=m 支持模块化
# IPVS transport protocol load balancing support
# IPVS scheduler
# IPVS SH scheduler
# IPVS application helper

[root@VM_0_2_centos ~]# uname -r
3.10.0-514.26.2.el7.x86_64
[root@VM_0_2_centos ~]# grep -A 10 -i "IPVS" /boot/config-3.10.0-327.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

# IPVS SH scheduler 
#
CONFIG_IP_VS_SH_TAB_BITS=8 原地址哈希

判断ipvsadm程序包是否安装

[root@VM_0_2_centos ~]# yum -y install ipvsadm
[root@VM_0_2_centos ~]# rpm -ql ipvsadm
/etc/sysconfig/ipvsadm-config
/usr/lib/systemd/system/ipvsadm.service
/usr/sbin/ipvsadm
/usr/sbin/ipvsadm-restore
/usr/sbin/ipvsadm-save
/usr/share/doc/ipvsadm-1.27
/usr/share/doc/ipvsadm-1.27/README
/usr/share/man/man8/ipvsadm-restore.8.gz
/usr/share/man/man8/ipvsadm-save.8.gz
/usr/share/man/man8/ipvsadm.8.gz

ipvsadm命令

管理集群服务

ipvsadm -A|E -t|u|f service-address [-s scheduler]
-A:增,添加
-E:修改

ipvsadm -D -t|u|f service-address
-D:删除集群服务;

service-address:定义集群服务的地址
-t:tcp,把tcp端口定义成集群服务,vip:tcp_port;
-u:udp,把udp端口定义成集群服务,vip:udp_port;
-f:Firewalls mark防火墙标记,是一个数字;

-s scheduler:定义集群服务的调度方法,默认为wlc加权最少连接;

管理集群上的RS

ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight]
-a:增,添加RS;
-e:改,修改RS;

ipvsadm -d -t|u|f service-address
-d:删除

-r server-address:向已存在的service-address(集群服务)添加RS的地址;
rip[:port] 端口省略时,表示不做端口映射,与请求服务的端口为同一端口;有些集群服务不支持端口映射,如lvs-dr,lvs-tun,只要响应报文不经过Director都不支持;

-g,gateway,dr:指明集群类型为lvs-dr;默认类型;
-i,ipip,tun:指明集群类型为lvs-tun;
-m,masquerad,nat(地址伪装):指明集群类型为lvs-nat;
-w weight:指明权重,对不支持权重的调度算法没用;用在wrr,wrc,sed调度算法;

查看:ipvsadm -L|l [options]
-L,--list:列出集群服务;
-n, --numeric:数字格式显示,不反解主机名到ip地址,服务到端口号;
--exact:精确显示数值,不进行单位换算;
-c, --connection:显示当前ipvs连接;可查看后端服务器是否连接;
--stats:统计数据;
--rate:速率;

清空:clear
ipvsadm -C

保存和重载
保存:输出重定向
ipvsadm -S > /PATH/TO/SOME_RULE_FILE
ipvsadm-save > /PATH/TO/SOME_RULE_FILE

重载:输入重定向
ipvsadm -R < /PATH/TO/SOME_RULE_FILE
ipvsadm-restore < /PATH/TO/SOME_RULE_FILE

清空计数器:
ipvsadm -Z [-t|u|f service-address]

负载均衡集群设计时要注意的问题:
(1) 是否需要会话保持;
(2) 是否需要共享存储;

例如:

#查看ipvs服务,以数值格式显示
[root@VM_0_2_centos ~]# ipvsadm -Ln 
IP Virtual Server version 1.2.1 (size=4096) 
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

Port显示协议,只有三种:tcp、udp、firewalls mark
Scheduler表示调度方法;
RemoteAddress:Port 表示RS(真实服务器)地址;不同集群服务,一般RS不同;
Forward 表示转发方法;
Weight 表示权重值;
ActiveConn 活动连接数;
InActConn 非活动连接数;

例如:

添加集群服务,vip为172.18.11.111提供web服务,指明调度方法为rr;不指明为默认wlc;

[root@VM_0_2_centos ~]# ipvsadm -A -t 172.18.11.111:80 -s rr 
[root@VM_0_2_centos ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 rr

在集群服务中添加RS地址为192.168.255.2,类型为lvs-nat,权重为1此值无意义,因为前面已经指明使用rr调度算法

[root@VM_0_2_centos ~]# ipvsadm -a -t 172.18.11.111:80 -r 192.168.255.2 -m -w 1
[root@VM_0_2_centos ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 rr
  -> 192.168.255.2:80             Masq    1      0          0 

[root@VM_0_2_centos ~]# ipvsadm -Ln --rate
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port                 CPS    InPPS   OutPPS    InBPS   OutBPS
  -> RemoteAddress:Port
TCP  172.18.11.111:80                    0        0        0        0        0
  -> 192.168.255.2:80                    0        0        0        0        0

其中:
CPS:connect per second,表示每秒钟的连接数;
InPPS:input packets per second,每秒的入栈报文数;
OutPPS:out packets per second,每秒的出栈报文数;
InBPS:input bytes per second,每秒的入栈字节数;
OutBPS:output bytes per second,每秒的出栈字节数;

[root@VM_0_2_centos ~]# ipvsadm -Ln --stats
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
  -> RemoteAddress:Port
TCP  172.18.11.111:80                    0        0        0        0        0
  -> 192.168.255.2:80                    0        0        0        0        0

其中:
Conns:表示总的连接数量;
InPkts:入栈报文数;
OutPkts:出栈报文数;
InBytes:入栈字节数;
OutBytes:出栈字节数;

再次添加一个RS

[root@VM_0_2_centos ~]# ipvsadm -a -t 172.18.11.111:80 -r 192.168.255.3 -m -w 3
[root@VM_0_2_centos ~]# ipvsadm -Ln
显示内容:
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 rr
  -> 192.168.255.2:80             Masq    1      0          0         
  -> 192.168.255.3:80             Masq    3      0          0

再次添加一个集群服务

[root@VM_0_2_centos ~]# ipvsadm -A -t 172.18.11.111:3306 -s wlc
[root@VM_0_2_centos ~]# ipvsadm -Ln
显示内容:
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 rr
  -> 192.168.255.2:80             Masq    1      0          0         
  -> 192.168.255.3:80             Masq    3      0          0         
TCP  172.18.11.111:3306 wlc

在另一个集群服务上添加2个RS

[root@VM_0_2_centos ~]# ipvsadm -a -t 172.18.11.111:3306 -r 192.168.255.4 -m -w 1
[root@VM_0_2_centos ~]# ipvsadm -a -t 172.18.11.111:3306 -r 192.168.255.5 -m -w 2
[root@VM_0_2_centos ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 rr
  -> 192.168.255.2:80             Masq    1      0          0         
  -> 192.168.255.3:80             Masq    3      0          0         
TCP  172.18.11.111:3306 wlc
  -> 192.168.255.4:3306           Masq    1      0          0         
  -> 192.168.255.5:3306           Masq    2      0          0 

修改集群服务的调度方法为wrr

[root@VM_0_2_centos ~]# ipvsadm -E -t 172.18.11.111:80 -s wrr
[root@VM_0_2_centos ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 wrr
  -> 192.168.255.2:80             Masq    1      0          0         
  -> 192.168.255.3:80             Masq    3      0          0         
TCP  172.18.11.111:3306 wlc
  -> 192.168.255.4:3306           Masq    1      0          0         
  -> 192.168.255.5:3306           Masq    2      0          0

注意:修改只能改属性,不能改IP地址;只有删除集群服务才能从新改IP地址;

修改RS的权重值为10

[root@VM_0_2_centos ~]# ipvsadm -e -t 172.18.11.111:80 -r 192.168.255.2 -m -w 10
[root@VM_0_2_centos ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 wrr
  -> 192.168.255.2:80             Masq    10     0          0         
  -> 192.168.255.3:80             Masq    3      0          0         
TCP  172.18.11.111:3306 wlc
  -> 192.168.255.4:3306           Masq    1      0          0         
  -> 192.168.255.5:3306           Masq    2      0          0

保存集群服务规则至指定路径

[root@VM_0_2_centos ~]# ipvsadm -S > /tmp/ipvsadm-config.v1

查看保存的内容:

[root@VM_0_2_centos ~]# cat /tmp/ipvsadm-config.v1
-A -t localhost.localdomain:http -s wrr
-a -t localhost.localdomain:http -r 192.168.255.2:http -m -w 10
-a -t localhost.localdomain:http -r 192.168.255.3:http -m -w 3
-A -t localhost.localdomain:mysql -s wlc
-a -t localhost.localdomain:mysql -r 192.168.255.4:mysql -m -w 1
-a -t localhost.localdomain:mysql -r 192.168.255.5:mysql -m -w 2

清空集群服务

[root@VM_0_2_centos ~]# ipvsadm -C

重载集群服务配置文件

[root@VM_0_2_centos ~]# ipvsadm -R < /tmp/ipvsadm-config.v1

想要知道陌生的命令使用方法:
对于centos 7,要查看该命令的Unit file;
对于centos 6,要查看该命令的service脚本;

[root@VM_0_2_centos ~]# cat /usr/lib/systemd/system/ipvsadm.service 
显示部分内容:
[Service]
Type=oneshot
ExecStart=/bin/bash -c "exec /sbin/ipvsadm-restore < /etc/sysconfig/ipvsadm"
ExecStop=/bin/bash -c "exec /sbin/ipvsadm-save -n > /etc/sysconfig/ipvsadm"
ExecStop=/sbin/ipvsadm -C
RemainAfterExit=yes

其中:
ExecStart=表示启动时,会从/etc/sysconfig/ipvsadm集群配置文件重载;
ExecStop=表示停止时,会保存集群配置文件至/etc/sysconfig/ipvsadm文件中吗,然后再清空当前集群服务;

下次开机时会自动载入集群服务规则:
所以,可把规则保存在/etc/sysconfig/ipvsadm文件中;
[root@VM_0_2_centos ~]# ipvsadm-save > /etc/sysconfig/ipvsadm
一般手动保存后(确保保存无误),下次开机时,会自动重载此文件;

需要开机自动有效:
[root@VM_0_2_centos ~]# systemctl enable ipvsadm.service

搭建lvs-nat

RS1:192.168.10.11,网关指向192.168.10.254
RS2:192.168.10.12,网关指向192.168.10.254

lvs-nat设计要点:
(1)DIP与RIP要在同一IP网络,RIP的网关要指向DIP;
(2)支持端口映射;
(3)是否用到共享存储,取决于业务需要;

1、配置RS1

#在RS1上安装httpd服务
[root@rs1 ~]# yum install -y httpd mod_ssl  
#设置指定的RIP
[root@rs1 ~]# ifconfig ens33 192.168.10.11/24 up  
#指定网关地址为DIP
[root@rs1 ~]# route add default gw 192.168.10.254  
[root@rs1 ~]# vim /var/www/html/index.html
<h1>RS1-192.168.10.11</h1>
[root@rs1 ~]# vim /etc/httpd/conf/httpd.conf
Listen 8080
[root@rs1 ~]# systemclt start httpd.service
#查看80端口是否打开
[root@rs1 ~]# ss -tnl  
#编辑iptables放开8080端
[root@rs1 ~]# iptables -I INPUT -d 192.168.10.11 -p tcp --dport 8080 -j ACCEPT
[root@rs1 ~]# iptables -I OUTPUT -s 192.168.10.11 -p tcp --sport 8080 -j ACCEPT  口

2、配置RS2

#在RS1上安装httpd服务
[root@rs2 ~]# yum install -y httpd mod_ssl  
#设置指定的RIP
[root@rs2 ~]# ifconfig ens33 192.168.10.12/24 up  
#指定网关地址为DIP
[root@rs2 ~]# route add default gw 192.168.10.254  
[root@rs2 ~]# vim /var/www/html/index.html
<h1>RS1-192.168.10.12</h1>
[root@rs1 ~]# vim /etc/httpd/conf/httpd.conf
Listen 8080
[root@rs2 ~]# systemclt start httpd.service
#查看80端口是否打开
[root@rs2 ~]# ss -tnl  
#编辑iptables放开8080端
[root@rs2 ~]# iptables -I INPUT -d 192.168.10.12 -p tcp --dport 8080 -j ACCEPT
[root@rs2 ~]# iptables -I OUTPUT -s 192.168.10.12 -p tcp --sport 8080 -j ACCEPT  口

3、配置Director

#安装ipvsadm工具
[root@director ~]# yum install -y ipvsadm
...
已安装:
  ipvsadm.x86_64 0:1.27-7.el7                                                                                                                            

完毕!

Director:192.168.10.254
VIP:172.18.11.121

[root@director ~]# ifconfig eno16777736:0 172.18.11.121/24  up
[root@director ~]# ifconfig eno33554984 192.168.10.254/24 up
[root@director ~]# ifconfig
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.0.2  netmask 255.255.255.0  broadcast 172.16.0.255
        inet6 fe80::20c:29ff:fe21:59b9  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:21:59:b9  txqueuelen 1000  (Ethernet)
        RX packets 6433  bytes 8332396 (7.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1544  bytes 144496 (141.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eno16777736:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.11.121  netmask 255.255.255.0  broadcast 172.18.11.255
        ether 00:0c:29:21:59:b9  txqueuelen 1000  (Ethernet)

eno33554984: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.10.254  netmask 255.255.255.0  broadcast 10.10.10.255
        inet6 fe80::20c:29ff:fe21:59c3  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:21:59:c3  txqueuelen 1000  (Ethernet)
        RX packets 104  bytes 8225 (8.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 68  bytes 8642 (8.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

打开网卡核心转发功能;永久有效:

[root@director ~]# sysctl -w net.ipv4.ip_forward=1
[root@director ~]# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

查看内核参数是否打开核心转发功能

[root@VM_0_2_centos ~]# cat /proc/sys/net/ipv4/ip_forward

此时,在Director测试,访问RS1、RS2;

[root@rs1 ~]# curl http://192.168.10.11
<h1>RS1-192.168.10.11</h1>

[root@rs ~]# curl http://192.168.10.12
<h1>RS2-192.168.10.12</h1>

添加ipvs集群:

[root@director ~]# ipvsadm -A -t 172.18.11.121:80 -s rr
#指定lvs虚拟服务对应的Real server
[root@director ~]# ipvsadm -a -t 172.18.11.121:80 -r 192.168.10.11:8080 -m
[root@director ~]# ipvsadm -a -t 172.18.11.121:80 -r 192.168.10.12:8080 -m
[root@director ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.121:80 rr
  -> 192.168.10.11:8080             Masq    1      0          0         
  -> 192.168.10.12:8080             Masq    1      0          0    

在另一台虚拟机上测试,调度是否起作用:
测试主机为:172.18.11.111

[root@localhost ~]# for i in {1..20}; do curl http://172.18.11.111;done
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
[root@director ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 rr
#因为使用的调度算法为rr轮询,因此两个RS负载的连接数接近一比一
  -> 192.168.10.11:8080             Masq    1      0          10        
  -> 192.168.10.12:8080             Masq    1      0          11     

修改Director上的调度方式为wrr

[root@director ~]# ipvsadm -E -t 172.18.11.121 -s wrr
[root@director ~]# ipvsadm -e -t 192.168.0.99:80 -r 10.10.10.11:8080 -m -w 5
[root@director ~]# ipvsadm -e -t 192.168.0.99:80 -r 10.10.10.12:8080 -m -w 10
[root@director ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.111:80 wrr
  -> 192.168.10.11:8080             Masq    5      0          0         
  -> 192.168.10.12:8080             Masq    10     0          0      

再到测试主机为:172.18.11.111,测试wrr的调度效果

[root@localhost ~]# for i in {1..15}; do curl http://192.168.0.99;done
<h1>RS2-192.168.10.12</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS2-192.168.10.12</h1>
<h1>RS1-192.168.10.11</h1>
#负载访问的比例为1:2

经过多次请求测试后,有明显wrr调度效果;
其RS服务器响应权重比是1:2,即RS1响应1次后RS响应2次;

数据同步:rsync+inotify

  • rsync:远程同步,能够将两台主机上的两个文件系统,彼此间做同步;有主从之分,同步是单向的,主服务器有支持读、写操作,从服务器只能读操作,要从主服务器上拉取完成同步;类似于dns中的主从区域复制;

  • inotify机制:是内核的机制;在从服务器拉取主服务器数据时,可能刚来取完,主服务器就变化了,这样不能准时获得同步;inotify机制就要解决此问题,当主服务器有变化时,主动通知从服务器;
    一主一从,或一主两从,再多就无法使用;

搭建lvs-dr

响应报文不用经过Director,每个RS必须配置VIP,为了避免地址冲突,有3种方式:

  • 第一,在路由器上做静态绑定Director上的MAC与Director上的VIP,各RS还有添加arptables拒绝网络通告;
  • 第二,在RS上仅适用arptables解决;
  • 第三,修改内核参数解决,完成阻断通告和响应;

每个主机只需一块网卡即可,各主机都在同一物理网络中;确保请求报文能到达Director,Director收到报文后挑选出一台RS负责响应,在Director上把报文重新封装MAC,把报文转发给该RS;
在各RS上,先隔离arp通告,再添加入栈路由即到达VIP必须经lo:0这样的别名(VIP地址配置在的别名接口)接口上,这样出栈时,源IP才能被改成VIP;
请求报文经过过Director,响应报文不经过Director,各RS的网关不能指向DIP;端口映射不能实现;
如果VIP和RIP不在同一网段;如何确保响应报文能出去;

在各主机(Director,RS)均需要配置VIP,因此,要解决地址的冲突的问题,目标是让各RS上的VIP不可见,仅用接收目标地址为VIP的报文,同时可作为响应报文的源地址;
(1)在前端的网关接口上静态绑定(vip+mac);
缺陷:一旦Director挂了,基于高可用转移另外节点上无法实现;而且,要在网关上有权限操作;
(2)在各RS上使用arptables;添加规则,拒绝自己的VIP地址向外通告及响应arp解析地址的请求;
(3)在各RS上修改内核参数,来限制arp响应和通告;
注意:要将VIP配置在lo的别名上,不能配置在网卡的别名上;

限制响应级别:arp_ignore
0:默认值,使用本地任意接口上配置的地址进行响应;回应任何网络接口上对任何本地IP地址的arp查询请求
1:仅在请求的目标IP配置在本地主机的接收报文的接口上时,才给予响应;只回答目标IP地址是来访网络接口本地地址的ARP查询请求;
2:只回答目标IP地址是来访网络接口本地地址的ARP查询请求,且来访IP必须在该网络接口的子网段内;
3:不回应该网络界面的arp请求,而只对设置的唯一和连接地址做出回应;
4-7:预留;
8:不回应所有(本地地址)的arp查询;

限制通告级别:arp_announce
0:默认值,把本机所有接口信息向每个接口通告;
1:尽量避免向非本网络通告;
2:总是避免向非本网络通告;

在各RS上设置arp通告级别即修改两个内核参数arp_ignore、arp_announce,因为地址是属于内核的,所以在Linux主机默认的通告方式是所有本机的可用IP地址通告给每个接口;

arp_announce要限制通告级别,每一个网卡仅在把自己的网络地址向所在物理网络中通告,即各网卡间地址绝不交叉通告;arp_announce设置为2;

arp_ignore是限制响应别人arp请求的级别;默认响应请求是无论从哪个接口接收到arp请求,只要本机有这个地址都会响应;限制arp响应级别后可实现,从哪个网卡接收的arp请求,
必须与该接口属于同一网络时才响应;arp_ignore`设置为1

lvs-dr设计要点:
(1)各主机一个接口即可,但需要在同一物理网络中;
(2)RIP的网关不能指向DIP,RIP和DIP通常应在同一网络,但此二者未必会与VIP在同一网络;
(3)各RS需要先设置内核参数,再设置VIP和路由;

搭建网络环境

Director:
VIP:172.18.11.7
DIP:172.18.11.121

RS1:
VIP:172.18.11.7
RIP:172.18.11.8

RS2:
VIP:172.18.11.7
RIP:172.18.11.9

1、配置Director

[root@director ~]# ifconfig eno16777736:0 172.18.11.7 netmask 255.255.255.255 broadcast 172.18.11.7
[root@director ~]# ipvsadm -A -t 172.18.11.7:80 -s rr
[root@director ~]# ipvsadm -a -t 172.18.11.7:80 -r 172.18.11.8:80 -g
[root@director ~]# ipvsadm -a -t 172.18.11.7:80 -r 172.18.11.9:80 -g
[root@director~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.18.11.7:80 rr
  -> 172.18.11.8:80              Route   1      0          0         
  -> 172.18.11.9:80              Route   1      0          0         
[root@director ~]# systemctl stop firewalld

2、配置RS1

[root@rs1 ~]# yum install -y httpd mod_ssl
#在本地环回接口上配置VIP并指定路由
[root@rs1 ~]# ifconfig lo:0 172.18.11.7 netmask 255.255.255.255 broadcast 172.18.11.7
[root@rs1 ~]# route add 172.18.11.7 dev lo:0
#修改内核参数,限制ARP响应
[root@rs2 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@rs2 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@rs2 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
[root@rs2 ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@rs1 ~]# vim /var/www/html/index.html
<h1>RS1-172.18.11.8</h1>
[root@rs1 ~]# systemctl start httpd
[root@rs1 ~]# systemctl stop firewalld

3、配置RS2

[root@rs2 ~]# yum install -y httpd mod_ssl
#在本地环回接口上配置VIP并指定路由
[root@rs2 ~]# ifconfig lo:0 172.18.11.7 netmask 255.255.255.255 broadcast 172.18.11.7
[root@rs2 ~]# route add 172.18.11.7 dev lo:0
#修改内核参数,限制ARP响应
[root@rs2 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@rs2 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@rs2 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
[root@rs2 ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@rs2 ~]# vim /var/www/html/index.html
<h1>RS2-172.18.11.9</h1>
[root@rs2 ~]# systemctl start httpd
[root@rs2 ~]# systemctl stop firewalld

4、访问测试

[root@localhost ~]# for i in {1..10};do curl http://172.18.11.7;done
<h1>RS1-172.18.11.8</h1>
<h1>RS1-172.18.11.9</h1>
<h1>RS1-172.18.11.8</h1>
<h1>RS1-172.18.11.9</h1>
<h1>RS1-172.18.11.8</h1>
<h1>RS1-172.18.11.9</h1>
<h1>RS1-172.18.11.8</h1>
<h1>RS1-172.18.11.9</h1>
<h1>RS1-172.18.11.8</h1>
<h1>RS1-172.18.11.9</h1>
lvs-dr集群的配置脚本
#RS
[root@director ~]# vim skp.sh
#!/bin/bash
#
vip=172.18.11.7
mask='255.255.255.255'

case $1 in
start)
     echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
     echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
     echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
     echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
     ifconfig lo:0 172.18.11.7 netmask $mask broadcast $vip up
     route add -host $vip dev lo:0
;;
stop)
     ifconfig lo:0 down
     echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
     echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
     echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
     echo 0 > /proc/sys/net/ipv4/conf/lo/arp_iannounce
     ifconfig lo:0 0
     ;;
*)
    echo "Usage $(basename $0) start|stop"
    exit 1
    ;; 
esac
[root@rs1 ~]# chmod +x skp.sh
[root@rs1 ~]# ./skp.sh start
[root@rs1 ~]# cat /proc/sys/net/ipv4/conf/all/arp_ignore
1
[root@rs1 ~]# cat /proc/sys/net/ipv4/conf/all/arp_announce
2
[root@rs1 ~]# scp skp.sh root@172.18.11.9:/root

在RS2主机运行

[root@rs2 ~]# ./skp.sh start
#!/bin/bash
#
vip='172.18.11.7'
iface='eno16777736:0'
mask='255.255.255.255'
port='80'
rs1='172.18.11.8'
rs2='172.18.11.9'
scheduler='rr'
type='-g'

case $1 in
start)
    ifconfig $iface $vip netmask $mask broadcast $vip up
    iptables -F
    
    ipvsadm -A -t ${vip}:${port} -s $scheduler
    ipvsadm -a -t ${vip}:${port} -r ${rs1} $type -w 1
    ipvsadm -a -t ${vip}:${port} -r ${rs2} $type -w 1
    ;;
stop)
    ipvsadm -C
    ifconfig $iface down
    ;;
*)
    echo "Usage $(basename $0) start|stop"
    exit 1
    ;;
esac    

fwm:FireWall Mark

lvs处理报文(图片来自于网络)

在netfilter上给报文打标记;在mangle表上实现;mangle表可以应用在5个链上;

在报文进入时,进行打标记,例如目标IP是VIP端口80,把这类报文分拣出来打标,标记一般为十六进制整数,例如标记1;在input链上定义集群服务时,就可判定如果防火墙标记为1,则为集群服务;把本来在input链上完成识别、定义集群服务分成了两步,识别在prerouting做,定义在ipvs(inputing)上实现;

打标使用iptables实现

在mangle表上的prerouting链上,目标ip(VIP)为172.18.11.7,目标端口为80,打标记为1;

[root@VM_0_2_centos ~]# iptables -t mangle -A PREROUTING -d 172.18.11.7 -p tcp --dport 80 -j MARK --set-mark 1

mark标记里包含了IP地址和端口;定义集群服务时使用mark即可;

[root@VM_0_2_centos ~]# ipvsadm -A -f 1 -s rr  定义mark标记为1的报文为集群服务,调度算法为rr;
[root@VM_0_2_centos ~]# ipvsadm -a -f 1 -r 172.18.11.8 -g -w 1  添加RS到mark标记为1的集群服务中,集群类型为lvs-dr,权重为1;
]# ipvsadm -a -f 1 -r 172.18.11.9 -g -w 1

防火墙标记好处:可以把2个服务打成一个标记;就可把2个服务当做一个集群来调度;

打标记的方法:
iptables -t mangle -A PREROUTING -d $vip -p $protocol --dport $clusterserverport -j MARK --set-mark #
#:代表十六进制整数;

打标作用:提供辅助持久连接功能;在多个端口定义服务时,可把相关作为一个集群来调度;

FWM示例

配置RS1:

[root@rs1 ~]# yum install -y nginx
[root@rs1 ~]# vim /etc/nginx/conf.d/https.conf
server {
        listen 443 ssl;
        ssl on;
        ssl_certificate /etc/nginx/nginx.crt;
        ssl_certificate_key /etc/nginx/nginx.key;

        ssl_session_timeout 5m;
}

[root@rs1 ~]# vim /usr/share/nginx/html/nginx.htm
<h1>This is RS1 172.18.11.8</h1> 

配置RS2:

[root@rs2 ~]# yum install -y nginx
[root@rs2 ~]# vim /etc/nginx/conf.d/https.conf
server {
        listen 443 ssl;
        ssl on;
        ssl_certificate /etc/nginx/nginx.crt;
        ssl_certificate_key /etc/nginx/nginx.key;

        ssl_session_timeout 5m;
}

[root@rs2 ~]# vim /usr/share/nginx/html/nginx.htm
<h1>This is RS1 172.18.11.9</h1> 

在Director创建CA:

[root@director ~]# (umask 077;openssl genrsa -out private/cakey.pem 2048)
[root@director ~]# openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 365
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:BJ
Organization Name (eg, company) [Default Company Ltd]:MageEdu
Organizational Unit Name (eg, section) []:Ops
Common Name (eg, your name or your server's hostname) []:ca.magedu.com
Email Address []:为空

[root@VM_0_2_centos ~]# touch index.txt
[root@VM_0_2_centos ~]# echo 01 > serial

在RS1主机:

[root@rs1~]# cd /etc/httpd
[root@rs1 ~]# mkdir ssl
[root@rs1 ~]# cd ssl
# 创建私钥及生成签证请求
[root@rs1 ~]# (umask 077;openssl genrsa -out httpd.key 1024)
[root@rs1 ~]# openssl req -new -key httpd.key -out httpd.csr
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:BJ
Organization Name (eg, company) [Default Company Ltd]:MageEdu
Organizational Unit Name (eg, section) []:Ops
Common Name (eg, your name or your server's hostname) []:www.stu11.com
Email Address []:留空

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:留空
An optional company name []:留空
# 传给CA签证
[root@rs1 ~]# scp httpd.csr root@172.18.11.121:/tmp

在CA服务上签证并传回给RS1:

[root@director ~]# openssl ca -in /tmp/httpd.csr -out /tmp/http.crt -days 365
[root@director ~]# cd /tmp
[root@director ~]# scp http.crt root@172.18.11.8:/etc/httpd/ssl

[root@rs1 ~]# cd /etc/httpd
# 把证书传另一RS2主机
[root@rs1 ~]# scp -rp ssl/ root@172.18.11.9:/etc/httpd/
[root@director ~]# vim conf.d/ssl.conf 
SSLCertificateFile /etc/httpd/ssl/http.crt
SSLCertificateKeyFile /etc/httpd/ssl/httpd.key

# 把配置好的ssl配置文件再传给另一RS
[root@director ~]# scp conf.d/ssl.conf root@172.18.11.9:/etc/httpd/conf.d/

在各RS主机重启web服务并查看443端口是否监听:

[root@rs1 ~]# systemctl restart httpd.service
[root@rs2 ~]# systemctl restart httpd.service

手动测试直接访问RS的IP:

[root@director ~]# curl -k https://172.18.11.8

测试请求,OK可以响应页面;-k表示可接受不受信任的页面响应;

单机测试ok,下面绑定80和443服务,打标记:

[root@director ~]# iptables -t mangle -A PREROUTING -d 172.18.11.7 -p tcp -m multiport --dports 80,443 -j MARK --set-mark 10

在Director查看:

[root@director ~]# iptables -t mangle -vnL

有报文进来,表示打标记成功的;

添加集群服务,不加-p不做持久连接,为轮询;

[root@director ~]# ipvsadm -A -f 10 -s rr 

在集群服务中添加2个RS

[root@director ~]# ipvsadm -a -f 10 -r 172.18.11.8 -m
[root@director ~]# ipvsadm -a -f 10 -r 172.18.11.9 -m

在客户端验证结果:

[root@client ~]# for i in {1..10};do curl http://172.18.11.7/nginx.html;done
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>

[root@client ~]# for i in {1..10};do curl -k  https://172.18.11.7/nginx.html;done
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>

注意:
如何能让ipvs规则下次,开机生效;

[root@director ~]# ipvsadm-save > /etc/sysconfig/ipvsadm

lvs persistence:持久连接

基于持久连接模板(就上一个哈希表),能实现无论使用任何算法调度,都能进行在一段时间内,将来自同一源IP的请求始终发往同一RS;
可定义持久连接时间、无论使用什么算法都能持久连接;还可将两个不同的服务绑在一块进行调度;

ipvs的持久类型

  • 每端口持久(PPC):per port connect
    来自于同一源IP的客户端请求不同的服务,当访问web的80端口时,就可绑定,访问数据库服务的3306端口时,则会重新进行调度;只持久单个服务;
  • 每客户端持久(PCC):per client conect
    同一个Director调度多个集群服务,多个集群服务由同一组RS提供即一个RS提供80,443,3306等服务;如果同一客户端请求,始终发往同一的RS响应;对所有服务同时持久;
  • 每FWM持久:
    只要是防火墙标记是一样的,就始终发往同一RS响应;只持久同一防火墙标记下的连接;

定义持久连接的方法:ipvsadm -A|E -t|u|f service-address [-s scheduler] -p [timeout]
默认持久连接时间为300秒;

指定持久连接时长为300秒

[root@director ~]# ipvsadm -E -f 1 -s rr -p 300
[root@director ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
FWM  1 rr persistent 300
  -> 172.18.11.8:0                Route   1      0          0         
  -> 172.18.11.9:0                Route   2      0          1

上述每个类型的配置格式如下:

演示每端口持久(PPC)连接
添加80端口为集群服务,使用rr调度算法

[root@director ~]# ipvsadm -A -t 172.18.11.7:80 -s rr -p 

演示每客户端持久(PCC)连接
添加集群服务,设置VIP、端口为0表示所有端口,集群调度使用rr算法,开启持久连接功能;

[root@VM_0_2_centos ~]# ipvsadm -A -t 172.18.11.7:0 -s rr -p 

演示每防火墙标记持久PFWM

[root@director ~]# ipvsadm -A -f 3 -s rr -p

接着我们在上面FWM的实例的director上启动持久连接测试其对应的效果:
修改director上的ipvs规则:

[root@director ~]# ipvsadm -E -f 1 -s rr -p 300
[root@director ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
FWM  1 rr persistent 300
  -> 172.18.11.8:0                Route   1      0          0         
  -> 172.18.11.9:0                Route   1      0          1     

客户端访问测试:

[root@client ~]# for i in {1..10};do curl http://172.18.11.7/nginx.html;done
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>

[root@client ~]# for i in {1..10};do curl -k  https://172.18.11.7/nginx.html;done
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>
<h1>This is RS2 172.18.11.9</h1>
<h1>This is RS1 172.18.11.8</h1>

RS在lvs-dr模型下:
要启动服务器、设置内核参数、配置VIP、添加路由等自动进行,就编写RS设置脚本实现:

考虑

(1)Director不可用时,整个系统不可用;单点故障SPOF;
解决方案:高可用
keepalived
heartbeat/corosync

(2)某RS不可用时,Director是否扔会向其调度;
解决方案:对各RS的健康状态做检查,失败时禁用,成功时启用;
keepalived
heartbeat/corosync, ldirectord
检查方式:
(a)网络层探测:ping命令
(b)传输层探测:nmap命令扫描端口,端口可用性探测,TCP_CHECK
(c)应用层探测:HTTP_GET,SSL_GET,SMTP_CHECK

ldirectord

ldirectord用来实现lvs负载均衡资源在主、备节点间的故障转移。在首次启动时,ldirectord可以自动创建ipvs表。此外,它还可以监控各RealServer的运行状态,一旦发现某RealServer运行异常时,还可以将其从ipvs表中移除。

ldirectord进程通过向RS的rip发送资源访问请求并通过由RS返回的响应信息来确定RS的运行状态。在Director上,每一个vip需要一个单独的ldirectord进程。如果RS不能正常响应Director上ldirectord的请求,ldirectord进程将通过ipvsadm命令将此RS从ipvs表中移除。而一旦RS再次上线,ldirectord会将其重新添加至ipvs表中。

下载https://fedora.pkgs.org/29/fedora-updates-x86_64/ldirectord-4.2.0-1.fc29.x86_64.rpm.html

Director主机上:

[root@director ~]# yum install ldirectord-4.2.0-1.fc29.x86_64.rpm -y
Loaded plugins: fastestmirror, langpacks
Repository epel is listed more than once in the configuration
Examining ldirectord-4.2.0-1.fc29.x86_64.rpm: ldirectord-4.2.0-1.fc29.x86_64
Marking ldirectord-4.2.0-1.fc29.x86_64.rpm to be installed
...
Complete!

[root@director ~]# rpm -ql ldirectord
/etc/ha.d
/etc/ha.d/resource.d
/etc/ha.d/resource.d/ldirectord
/etc/logrotate.d/ldirectord
/usr/lib/ocf/resource.d/heartbeat/ldirectord
/usr/lib/systemd/system/ldirectord.service
/usr/sbin/ldirectord
/usr/share/doc/ldirectord
/usr/share/doc/ldirectord/COPYING
/usr/share/doc/ldirectord/ldirectord.cf
/usr/share/man/man8/ldirectord.8.gz
[root@director ~]# cp /usr/share/doc/ldirectord/ldirectord.cf /etc/ha.d/
[root@director ~]# vim /etc/ha.d/ldirectord.cf
# Global Directives
checktimeout=20                    # ldirectord等待RealServer健康检查完成的时间,单位为秒;
checkinterval=5                    # 每次检查的时间间隔,即检查的频率;
autoreload=yes                     # 此项用来定义ldirectord是否每隔一段时间检查此配置文件是否发生改变并自动重新加载;
logfile="/var/log/ldirectord.log"  # 定义日志文件存放位置;
quiescent=yes                      # 当某台RealServer出现异常,此项可将其设置为静默状态(即其权重为"0")从而不再响应客户端的访问请求;

# Sample for an http virtual service
    virtual=192.168.101.168:80         # 此项用来定义LVS服务及其使用的VIP和PORT
    real=10.10.10.11:80 gate 100       # 定义RealServer,语法:real=RIP:port gate|masq|ipip [weight]
    real=10.10.10.12:80 gate 300
    fallback=127.0.0.1:80 gate         # 当IPVS表没有任何可用的RealServer时,此"地址:端口"作为最后响应的服务;
    service=http                       # 定义基于什么服务来测试RealServer;
    scheduler=wlc                      # 调度算法为wlc;
    #persistent=600                    # 持久连接超时时间;
    #netmask=255.255.255.255
    protocol=tcp                       # 定义此虚拟服务用到的协议;
    checktype=negotiate                # ldirectord进程用于监控RealServer的方法;{negotiate|connect|A number|off}
    checkport=80                       # 指健康检查使用的端口;
    request=".ldirectord.html"         # 检查RealServer用到的页面
    receive="Nice"                     # 检查RealServer用到的页面内容

[root@director ~]# yum install httpd -y
[root@director ~]# echo "404 Page." > /var/www/html/index.html
[root@director ~]# service httpd start

在RS主机上:
RS1、RS2提供".ldirectord.html"检测页面

[root@rs1 ~]# echo "Nice" > /var/www/html/.ldirectord.html
[root@rs1 ~]# service httpd stop   #模拟后端RS故障
[root@rs2 ~]# echo "Nice" > /var/www/html/.ldirectord.html
[root@rs2 ~]# service httpd stop   #模拟后端RS故障

Director查看ipvs信息,并使用浏览器访问http://172.18.11.7

[root@director ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP 172.18.11.7:80 wlc
  -> 172.18.11.8:80               Route   0      0          12        
  -> 172.18.11.9:80               Route   0      0          101       
  -> 127.0.0.1:80                 Local   1      0          0  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容