Lvs之NAT、DR、TUN三种模式的应用配置案例

首先声明文章出处:《Lvs之NAT、DR、TUN三种模式的应用配置案例 》是由helloworld发表于速学堂的一篇文章,感谢helloworld的分享,内容非常全面充实,因此转载作为复习资料。

LVS

一、LVS简介

    LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟服务器集群系统。本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件之一。

二、LVS的分类

LVS-NAT:地址转换

LVS-DR: 直接路由

LVS-TUN:隧道

三、ipvsadm用法

其实LVS的本身跟iptables很相似,而且连命令的使用格式都很相似,其实LVS是根据iptables的框架开发的,那么LVS的本身分成了两个部分,第一部分是工作在内核空间的一个IPVS的模块,其实LVS的功能都是IPVS模块实现的,,第二部分是工作在用户空间的一个用来定义集群服务的一个工具ipvsadm, 这个工具的主要作用是将管理员定义的集群服务列表传送给工作在内核空间中的IPVS模块,下面来简单的介绍下ipvsadm命令的用法

ipvsadm组件定义规则的格式:
1.定义集群服务格式:
(1).添加集群服务:
ipvsadm -A|E -t|u|f service-address [-s scheduler]
              [-p [timeout]] [-M netmask]
-A:                  表示添加一个新的集群服务
-E:                  编辑一个集群服务
-t:                  表示tcp协议
-u:                  表示udp协议
-f:                  表示firewall-Mark,防火墙标记
service-address:     集群服务的IP地址,即VIP
-s                    指定调度算法
-p                    持久连接时长,如#ipvsadm -Lcn ,查看持久连接状态
-M                    定义掩码
ipvsadm -D -t|u|f service-address      删除一个集群服务
ipvsadm -C                             清空所有的规则
ipvsadm -R                             重新载入规则
ipvsadm -S [-n]                        保存规则


2.向集群服务添加RealServer规则:
(1).添加RealServer规则
ipvsadm -a|e -t|u|f service-address -r server-address
              [-g|i|m] [-w weight]
-a                 添加一个新的realserver规则
-e                 编辑realserver规则
-t                 tcp协议
-u                 udp协议
-f                 firewall-Mark,防火墙标记
service-address    realserver的IP地址
-g                 表示定义为LVS-DR模型
-i                 表示定义为LVS-TUN模型
-m                 表示定义为LVS-NAT模型
-w                 定义权重,后面跟具体的权值
ipvsadm -d -t|u|f service-address -r server-address          --删除一个realserver
ipvsadm -L|l [options]                                       --查看定义的规则
如:#ipvsadm -L -n  
ipvsadm -Z [-t|u|f service-address]                          --清空计数器

四、lvs的10种调度算法

可以分为两大类 

 
LVS Scheduling Method LVS的调度方法:

1.Fixed Scheduling Method  静态调服方法
<span style="white-space:pre">	</span>(1).RR     轮询
<span style="white-space:pre">	</span>(2).WRR    加权轮询
<span style="white-space:pre">	</span>(3).DH     目标地址hash
<span style="white-space:pre">	</span>(4).SH     源地址hash

2.Dynamic Scheduling Method 动态调服方法
<span style="white-space:pre">	</span>(1).LC     最少连接
<span style="white-space:pre">	</span>(2).WLC    加权最少连接
<span style="white-space:pre">	</span>(3).SED    最少期望延迟
<span style="white-space:pre">	</span>(4).NQ     从不排队调度方法
<span style="white-space:pre">	</span>(5).LBLC   基于本地的最少连接
<span style="white-space:pre">	</span>(6).LBLCR  带复制的基于本地的最少连接
 


LVS-NAT

一、架构平台环境

系统平台:CentOS 6.4 64bit 内核:2.6.32
相关服务和专有名词定义
Director:负责调度集群的主机;也简称调度器、分发器
VIP:Virtual IP 向外提供服务的IP;通常此IP绑定域名
DIP:与内部主机RIP通信的IP,在Director主机上
RIP:RealServer IP;内部真正提供服务的主机
CIP:客户端IP

二、LVS-NAT架构



三、LVS-NAT模型实现负载均衡的工作方式

NAT模型其实就是通过网络地址转换来实现负载均衡的,它的工作方式几乎跟DNAT一模一样的,目前的DNAT只能转发到一个目标地址,早期的DNAT是可以将请求转发到多个目标的,在LVS出现之后就将此功能从DNAT种去掉了,下面来说说NAT模型的工作方式或者说NAT模型是怎么实现负载均衡的,根据上图

1.用户请求VIP(也可以说是CIP请求VIP)

2,Director Server 收到用户的请求后,发现源地址为CIP请求的目标地址为VIP,那么Director Server会认为用户请求的是一个集群服务,那么Director Server 会根据此前设定好的调度算法将用户请求负载给某台Real Server ;假如说此时Director Server 根据调度算法的结果会将请求分摊到RealServer1上去,那么Director Server 会将用户的请求报文中的目标地址,从原来的VIP改为RealServer1的IP,然后再转发给RealServer1

3,此时RealServer1收到一个源地址为CIP目标地址为自己的请求,那么RealServer1处理好请求后会将一个源地址为自己目标地址为CIP的数据包通过Director Server 发出去,
4.当Driector Server收到一个源地址为RealServer1 的IP 目标地址为CIP的数据包,此时Driector Server 会将源地址修改为VIP,然后再将数据包发送给用户。


四、LVS-NAT的性能瓶颈

在LVS/NAT的集群系统中,请求和响应的数据报文都需要通过负载调度器(Director),当真实服务器(RealServer)的数目在10台和20台之间时,负载调度器(Director)将成为整个集群系统的新瓶颈。大多数Internet服务都有这样的特点:请求报文较短而响应报文往往包含大量的数据。如果能将请求和响应分开处理,即在负载调度器(Director)中只负责调度请求而响应直接(RealServer)返回给客户,将极大地提高整个集群系统的吞吐量。


五、部署环境

1、准备工作 

    (1)关闭所有节点的iptables和selinux服务
setenforce 0
service iptables stop && chkconfig iptables off

    (2)HA中所有节点尽可能保证时间是一致的,方法是时间同步+任务计划同步时间;
注意:对于LB来说时间的影响不是很大,但是对于HP来说各节点之间的时间偏差不应该超出一秒钟:
ntpdate -u asia.pool.ntp.org


2、拓扑图地址规划

<span style="font-size:18px;color:#ff0000;">LVS Director机器:</span>

公网地址:vip
主机名:lvs
vip地址: 192.168.0.200
子网掩码:255.255.255.0
网关:    192.168.0.1 
网络连接方式:Bridge
 
私网地址:dip
主机名:lvs
dip地址: 172.16.100.1
子网掩码:255.255.0.0
网关:    不指定网关
网络连接方式:Host-Only
 
<span style="font-size:18px;color:#ff0000;">RealServer机器:</span>

私网地址:rip1
主机名:web1
rip1地址:172.16.100.10 
子网掩码:255.255.0.0   
网关:    172.16.100.1 
网络连接方式:Host-Only
 
私网地址:rip2
主机名:web2
rip1地址:172.16.100.11
子网掩码:255.255.0.0   
网关:    172.16.100.1 
网络连接方式:Host-Only

3、在RealServer上部署httpd服务并测试
安装httpd服务,创建httpd测试页面,启动httpd服务
[root@web1 ~]# yum -y install httpd
[root@web1 ~]# service httpd start
[root@web1 ~]# echo "RS1-web1 Allentuns.com" > /var/www/html/index.html
[root@web2 ~]# yum -y install httpd
[root@web2 ~]# echo "RS2-web2 Allentuns.com" > /var/www/html/index.html
[root@web2 ~]# service httpd start
 
测试httpd服务是否OK!
[root@web1 ~]# curl http://localhost
RS1-web1 Allentuns.com
[root@web1 ~]# curl http://172.16.100.11
RS2-web2 Allentuns.com

4、在Director上部署ipvs服务并测试

(1)确定本机ip_vs模块是否加载,也就是是否支持lvs,2.4.2后都支持了;然后安装ipvsadm 用户操作命令
[root@LVS ~]# grep -i "ip_vs" /boot/config-2.6.32-358.el6.x86_64 
CONFIG_IP_VS=m   #将ipvs定义成模块
CONFIG_IP_VS_IPV6=y
# CONFIG_IP_VS_DEBUG is not set
CONFIG_IP_VS_TAB_BITS=12
CONFIG_IP_VS_PROTO_TCP=y  #IPVS支持哪些集群服务
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
CONFIG_IP_VS_RR=m   #ipvs支持的十种调度算法
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
CONFIG_IP_VS_FTP=m  #支持代理ftp协议的
 
(2)安装ipvsadm
[root@LVS ~]# yum -y install ipvsadm
 
(3)添加集群服务
[root@LVS ~]# ipvsadm -A -t 192.168.0.200:80 -s rr               #定义一个集群服务
[root@LVS ~]# ipvsadm -a -t 192.168.0.200:80 -r 172.16.100.10 -m  #添加RealServer并指派调度算法为NAT
[root@LVS ~]# ipvsadm -a -t 192.168.0.200:80 -r 172.16.100.11 -m  #添加RealServer并指派调度算法为NAT
[root@LVS ~]# ipvsadm -L -n                                     #查看ipvs定义的规则列表
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.0.200:80 rr
  -> 172.16.100.10:80             Masq    1      0          0         
  -> 172.16.100.11:80             Masq    1      0          0   
[root@LVS ~]# cat /proc/sys/net/ipv4/ip_forward                    #查看Linux是否开启路由转发功能
0
[root@LVS ~]# echo 1 > /proc/sys/net/ipv4/ip_forward               #启动Linux的路由转发功能
[root@LVS ~]# cat /proc/sys/net/ipv4/ip_forward 
1
 
(4)测试访问http页面
[root@LVS ~]# curl http://192.168.0.200/index.html
RS2-web2 Allentuns.com  #第一次是web2
[root@LVS ~]# curl http://192.168.0.200/index.html
RS1-web1 Allentuns.com  #第二次是web1
[root@LVS ~]# curl http://192.168.0.200/index.html
RS2-web2 Allentuns.com  #第三次是web1
[root@LVS ~]# curl http://192.168.0.200/index.html
RS1-web1 Allentuns.com  #第四次是web2
 
(5)更改LVS的调度算并压力测试,查看结果
[root@LVS ~]# ipvsadm -E -t 192.168.0.200:80 -s wrr
[root@LVS ~]# ipvsadm -e -t 192.168.0.200:80 -r 172.16.100.10 -m -w 3
[root@LVS ~]# ipvsadm -e -t 192.168.0.200:80 -r 172.16.100.11 -m -w 1
[root@LVS ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.0.200:80 wrr
  -> 172.16.100.10:80             Masq    3      0          2         
  -> 172.16.100.11:80             Masq    1      0          2  
   
[root@LVS ~]# curl http://192.168.0.200/index.html
RS1-web1 Allentuns.com
[root@LVS ~]# curl http://192.168.0.200/index.html
RS1-web1 Allentuns.com
[root@LVS ~]# curl http://192.168.0.200/index.html
RS1-web1 Allentuns.com
[root@LVS ~]# curl http://192.168.0.200/index.html
RS2-web2 Allentuns.com
[root@LVS ~]# curl http://192.168.0.200/index.html
RS1-web1 Allentuns.com 
 
(6)永久保存LVS规则并恢复
第一种方法:
[root@LVS ~]# service ipvsadm save
ipvsadm: Saving IPVS table to /etc/sysconfig/ipvsadm:      [确定]
第二种方法:
[root@LVS ~]# ipvsadm -S > /etc/sysconfig/ipvsadm.s1
 
模拟清空ipvsadm规则来恢复
[root@LVS ~]# ipvsadm -C
[root@LVS ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
[root@LVS ~]# ipvsadm -R < /etc/sysconfig/ipvsadm.s1 
[root@LVS ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.0.200:80 wrr
  -> 172.16.100.10:80             Masq    3      0          0         
  -> 172.16.100.11:80             Masq    1      0          0

六、LVS-NAT服务控制脚本部署在Director上

#!/bin/bash
#
# chkconfig: - 88 12
# description: LVS script for VS/NAT
#
. /etc/rc.d/init.d/functions
#
VIP=192.168.0.200
DIP=172.16.100.1
RIP1=172.16.100.10
RIP2=172.16.100.11
#
case "$1" in
start)           
 
# /sbin/ifconfig eth1:0 $VIP netmask 255.255.255.0 up
 
# Since this is the Director we must be able to forward packets
  echo 1 > /proc/sys/net/ipv4/ip_forward
 
# Clear all iptables rules.
  /sbin/iptables -F
 
# Reset iptables counters.
  /sbin/iptables -Z
 
# Clear all ipvsadm rules/services.
  /sbin/ipvsadm -C
 
# Add an IP virtual service for VIP 192.168.0.219 port 80
# In this recipe, we will use the round-robin scheduling method. 
# In production, however, you should use a weighted, dynamic scheduling method. 
  /sbin/ipvsadm -A -t $VIP:80 -s rr
 
# Now direct packets for this VIP to
# the real server IP (RIP) inside the cluster
  /sbin/ipvsadm -a -t $VIP:80 -r $RIP1 -m
  /sbin/ipvsadm -a -t $VIP:80 -r $RIP2 -m
   
  /bin/touch /var/lock/subsys/ipvsadm.lock
;;
 
stop)
# Stop forwarding packets
  echo 0 > /proc/sys/net/ipv4/ip_forward
 
# Reset ipvsadm
  /sbin/ipvsadm -C
 
# Bring down the VIP interface
  ifconfig eth1:0 down
   
  rm -rf /var/lock/subsys/ipvsadm.lock
;;
 
status)
  [ -e /var/lock/subsys/ipvsadm.lock ] && echo "ipvs is running..." || echo "ipvsadm is stopped..."
;;
*)
  echo "Usage: $0 {start|stop}"
;;
esac

七、分享LVS-NAT一键安装脚本
#!/bin/bash
#
# 一键安装lvs-nat脚本,需要注意的是主机名成和ip的变化稍作修改就可以了 
 
HOSTNAME=`hostname`
 
Director='LVS'
VIP="192.168.0.200"
RIP1="172.16.100.10"
RIP2="172.16.100.11"
RealServer1="web1"
RealServer2="web2"
Httpd_config="/etc/httpd/conf/httpd.conf"
 
 
#Director Server Install configure ipvsadm
if [ "$HOSTNAME" = "$Director" ];then
ipvsadm -C
yum -y remove ipvsadm
yum -y install ipvsadm
/sbin/ipvsadm -A -t $VIP:80 -s rr
/sbin/ipvsadm -a -t $VIP:80 -r $RIP1 -m
/sbin/ipvsadm -a -t $VIP:80 -r $RIP2 -m
 
echo 1 > /proc/sys/net/ipv4/ip_forward
 
echo "========================================================"
echo "Install  $Director sucess   Tel:13260071987 Qq:467754239"
echo "========================================================"
fi
 
 
 
 
#RealServer Install htpd
 
if [ "$HOSTNAME" = "$RealServer1" ];then
yum -y remove httpd
rm -rf /var/www/html/index.html
yum -y install httpd
echo "web1 Allentuns.com" > /var/www/html/index.html
sed -i '/#ServerName www.example.com:80/a\ServerName localhost:80' $Httpd_config
service httpd start
 
 
echo "========================================================"
echo "Install $RealServer1 success Tel:13260071987 Qq:467754239"
echo "========================================================"
fi
 
if [ "$HOSTNAME" = "$RealServer2" ];then
yum -y remove httpd
rm -rf /var/www/html/index.html
yum -y install httpd
echo "web2 Allentuns.com" > /var/www/html/index.html
sed -i '/#ServerName www.example.com:80/a\ServerName localhost:80' $Httpd_config
service httpd start
echo "Install $RealServer2"
 
 
echo "========================================================="
echo "Install $RealServer1 success Tel:13260071987 Qq:467754239"
echo "========================================================="
fi

LVS-DR

一、LVS-DR架构




二、DR模型实现负载均衡的工作方式,
       
 上面说了NAT模型的实现方式,那么NAT模型有个缺陷,因为进出的每个数据包都要经过Director Server,当集群系统负载过大的时候Director Server将会成为整个集群系统的瓶颈,那么DR模型就避免了这样的情况发生,DR模型在只有请求的时候才会经过Director Server, 回应的数据包由Real Server 直接响应用户不需要经过Director Server,其实三种模型中最常用的也就是DR模型了,下面来说DR模型具体是怎么实现负载均衡的,根据上图。

1, 首先用户用CIP请求VIP

2, 根据上图可以看到,不管是Director Server还是Real Server上都需要配置VIP,那么当用户请求到达我们的集群网络的前端路由器的时候,请求数据包的源地址为CIP目标地址为VIP,此时路由器会发广播问谁是VIP,那么我们集群中所有的节点都配置有VIP,此时谁先响应路由器那么路由器就会将用户请求发给谁,这样一来我们的集群系统是不是没有意义了,那我们可以在网关路由器上配置静态路由指定VIP就是Director Server,或者使用一种机制不让Real Server 接收来自网络中的ARP地址解析请求,这样一来用户的请求数据包都会经过Director Servre

3,当Director Server收到用户的请求后根据此前设定好的调度算法结果来确定将请求负载到某台Real Server上去,假如说此时根据调度算法的结果,会将请求负载到Real Server 1上面去,此时Director Server 会将数据帧中的目标MAC地址修改为Real Server1的MAC地址,然后再将数据帧发送出去

4,当Real Server1 收到一个源地址为CIP目标地址为VIP的数据包时,Real Server1发现目标地址为VIP,而VIP是自己,于是接受数据包并给予处理,当Real Server1处理完请求后,会将一个源地址为VIP目标地址为CIP的数据包发出去,此时的响应请求就不会再经过Director Server了,而是直接响应给用户 

编辑DR有三种方式
第一种方式:在路由器上明显说明vip对应的地址一定是Director上的MAC,只要绑定,以后再跟vip通信也不用再请求了,这个绑定是静态的,所以它也不会失效,也不会再次发起请求,但是有个前提,我们的路由设备必须有操作权限能够绑定MAC地址,万一这个路由器是运行商操作的,我们没法操作怎么办?第一种方式固然很简便,但未必可行。
 
第二种方式:在给别主机上(例如:红帽)它们引进的有一种程序arptables,它有点类似于iptables,它肯定是基于arp或基于MAC做访问控制的,很显然我们只需要在每一个
real server上定义arptables规则,如果用户arp广播请求的目标地址是本机的vip则不予相应,或者说相应的报文不让出去,很显然网关(gateway)是接受不到的,也就是
director相应的报文才能到达gateway,这个也行。第二种方式我们可以基于arptables。
 
第三种方式:在相对较新的版本中新增了两个内核参数(kernelparameter),第一个是arp_ignore定义接受到ARP请求时的相应级别;第二个是arp_announce定义将自己地址向
外通告是的通告级别。【提示:很显然我们现在的系统一般在内核中都是支持这些参数的,我们用参数的方式进行调整更具有朴实性,它还不依赖于额外的条件,像arptables,
也不依赖外在路由配置的设置,反而通常我们使用的是第三种配置】
 
arp_ignore:定义接受到ARP请求时的相应级别
     0:只要本地配置的有相应地址,就给予响应。
     1:仅在请求的目标地址配置请求到达的接口上的时候,才给予响应
     2:只回答目标IP地址是来访网络接口本地地址的ARP查询请求,且来访IP必须在该网络接口的子网段内
     3:不回应该网络界面的arp请求,而只对设置的唯一和连接地址做出回应
     4-7:保留未使用
     8:不回应所有(本地地址)的arp查询
      
arp_ignore 
设置为1,当别人的arp请求过来的时候,如果接收的设备上面没有这个ip,就不响应,默认是0,只要这台机器上面任何一个设备上面有这个ip,就响应arp请求,并发送MAC地址应答。
      arp_announce:定义将自己地址向外通告是的通告级别;
         0: 将本地任何接口上的任何地址向外通告
         1:试图仅想目标网络通告与其网络匹配的地址
         2:仅向与本地借口上地址匹配的网络进行通告

 补充LVS-DR原理......

无论是学习一门编程语言也好,学习一门专业也好,在或者是学习一门手艺也罢!

记得!!!

学习的基础就是理论,理论是非常重要的,在几年的运维中,我一直都把理论放在第一位、说不上为什么,可能是几年的额感悟吧!

言归正传,学习lvs最好的方法就是学习它的工作原理,学习它的内部架构等等,lvs的部署是很简单的,但是在原理和理解方面往往都会有很大的偏差。在这里,我相信如果大家把这篇博文仔仔细细的看一遍,对lvs一定会有一个深入的体会和了解,中秋三天送给博友的礼物!哈哈 咱就不提月饼了。嘿嘿  同时也祝自己面试成功 夜已黑 2014-09-09 01:45:00


所有的Director和RealServer都在同一个物理网络中(交换机)并且都只有一块网卡,交换机前面有个路由器,这个路由器可能是我们机房内部的,也有可能是网络运行商的。
 
当客户端的请求被送到R2和Switch之间的时候,这个时候源ip是cip,目标地址是vip。vip一定在Director上是毋庸置疑的,所以这个报文就背送到Director的vip网卡上。
当客户端的请求被送到Switch和Director之间的时候,这个时候源ip仍然是cip,目标地址是vip。Director发现当前本机配置的有vip地址,所以请求的一定是当前主机
所以报文经过Prerouting链到达Input链,而监控在Input链上的ipvs规则发现请求的是一个集群服务,比如监听在80端口的web集群服务。这个时候lvs要根据ipvs规则
等等要修改报文了,在LVS-DR模型下报文送到Director上的时候,Director不会拆它的IP首部,也不会拆它的TCP首部,Director只要将MAC地址或者帧首部拆掉了。
为什么Director要拆开帧首部MAC地址呢?因为报文的目的地址就是Director本地主机,只要到达目的主机,网卡就会拆开帧首部的。因为目标MAC就是本地主机。
拆掉帧首部以后,查看IP首部和TCP首部,它发现请求的报文访问的是一个集群服务。
因此为了实现LVS-DR模型的效果,在源有的IP首部之上(切记源IP、目标IP、源端口、目标端口等等没有动),仅仅是在原有的报文外面又重新封装了一个MAC地址帧首部
帧首部有源MAC和目标MAC,这个时候发送的主机是Director。于是Director把本地网卡的MAC地址作为整个报文的源MAC地址,而目的MAC就是选择的后端某台RealServer
[选择后端的某台RealServe是Director根据它的一些调度算法(rr,wrr...)选择的]。假如选择的是RealServer2,那么会找到RealServer2 IP对应的MAC地址,于是找到了
RealServer2网卡对应的MAC地址,它是通过ARP地址解析找到的RealServer2对应的MAC地址。
那么Director到RealServer2之间的报文传送是源MAC地址是Director网卡对应的MAC地址,目标MAC地址是RealServer2网卡对应的MAC地址。
RealServer2接收到报文以后,发现请求的报文真的是自已,于是拆掉了MAC的帧首部,拆掉后发现请求的报文源地址是cip,目标地址是VIP。如果RealServer2上没有VIP
,那么RealServer2是不会接受这个报文的,因此必须在每个RealServer上配置VIP地址。因为RealServer2上有VIP地址,报文被接收下来,拆掉了IP首部,发现了报文
请求的是一个服务,比如80 因为传输层没有做任何修改,用户请求的是80服务,那么RealServer2接收到的报文也是请求的80服务。如果RealServer2上有80服务,于是
RealServer2把这个请求转交给用户空间的进程,由用户空间处理完成后,向外响应的。而请求报文的源地址是CIP,目标地址是VIP。那么尽可能让它使用CIP是目标地址
VIP是源地址,于是这个响应报文直接被发送到了交换机上。
 
当RealServer2响应报文到达Switch的时候,这个时候源地址是VIP,目标地址是CIP。
因为目标地址是CIP,假如VIP和CIP不在同一个网段当中,这个时候要根据目标地址CIP做路由选择,比如默认路由,网关才能响应CIP的报文请求
大家都知道目标地址CIP是互联网地址,那么每个RealServer的网关要指向哪呢??????
要指向能够访问互联网的设备,不应该指向Director的DIP地址。而是直接指向了能够访问互联网的路由设备。所有(很有可能)指向的是R2路由的私有地址做网关。
为什么是很有可能而不是说一定呢????
 
 
当报文被送到Switch和R2的时候,这个时候的源地址是VIP,目标地址是CIP。那么这个时候报文被送到R2网关的时候,R2发现目标地址是互联网的地址CIP,它会通过
路由NAT然后被送到CIP上的。
 
 
 
这里要考虑一个问题,为了实现每台RealServer在向外发送响应报文的时候,可以把VIP作为源地址,因此我们在每台RealServer上配置了VIP地址。
 
假如客户端发送请求报文被送到R2路由器的时候,那么R2路由器会拆开客户端的请求报文发现源地址是CIP,目标地址是VIP;无论是将请求送给Director还是RealServer,必须要根据
MAC地址向内转发,因为在同一网段,那么它怎么知道VIP对应的MAC地址是什么呢????
那么将进行广播说:‘我知道有一个家伙的VIP地址,那么请告诉我它对应的MAC地址’,那么它发送的广播请求,同一网段的所有主机都能收到,于是配置有VIP地址的所有主机都进行相应并告诉自已的MAC地址,那么如果所有的主机都进行相应,那么前端的路由设备就混乱了,它就无法分辨谁才是VIP对应的MAC地址。
默认情况下,谁相应的快,就会把客户端的请求报文发送给那台主机,如果被送到RealServer2 那么就不符合我们负载均衡的条件了。
那么我们在这里需要做一个非常重要的事情,就是每台配置有RealServer的VIP地址不给予ARP响应。那么我们如果屏蔽它不能响应呢?
那么所有的RealServer上都要关闭对ARP广播的响应。 
要达到的目的:让我们的前端路由或者网关,实现报文发送的时候,仅仅能够将报文对目标IP为VIP发送给Director?
实现的方式有以下三种:
1、在R2路由器的内部接口上手动绑定一个静态的解析地址,明确指明目标是VIP的MAC一定是Director的MAC
   那么以后发送报文的时候就不用再次请求了,可以由指定的静态解析地址直接发送给Director
   这个绑定是静态的也不会失效
   缺点:
   R2路由是内部路由器,那么VIP是私有地址;如果R2是网络运营商提供的路由设备,也就是VIP是公网地址,我们就无法再R2上进行静态绑定了。
2、arptables:
   基于MAC地址做访问控制的,我们只需要在每台RealServer上定义arptables规则,如果用户的arp广播请求的目标地址是本机的VIP则不给予响应或者响应的报文不出去。
   那么这个情况所有的RealServer上不响应arp广播请求,只有Director响应给路由则报文就必然被发送给Director。
3、kernel paramter:
    arp_ignore
    arp_announce
    作用:限定我们的Linux主机对arp广播请求的响应级别,以及向外通告自已ip地址的通告级别的。

三、配置集群服务

1、在Real Server1 和Real Server2上做以下配置 

# 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 
以上命令需填加到/etc/rc.local文件中让其开机自动生效 
# vim /etc/sysconfig/network-scripts/ifcfg-lo:0 内容如下 
DEVICE=lo:0 
IPADDR=172.16.100.100
NETMASK=255.255.255.255 
BROADCAST=172.16.100.100
ONBOOT=yes 
NAME=loopback 
  
# ifdown lo:0
# ifup lo:0
# route add -host 172.16.100.100 dev lo:0
# echo "route add -host 172.16.100.100 dev lo:0" >> /etc/rc.local

2、在Director Server上做以下配置
# vim /etc/sysconfig/network-scripts/ifcfg-eth2:0  内容如下  
DEVICE=eth2:0  
IPADDR=172.16.100.100  
NETMASK=255.255.255.255  
BROADCAST=172.16.100.100  
ONBOOT=yes  
# ifdown eth2:0 
# ifup eth2:20
# route add -host 172.16.100.100 dev eth2:0 
# echo "route add -host 172.16.100.100 dev eth2:0" >> /etc/rc.local 
# echo "1" > /proc/sys/net/ipv4/ip_forward 
# echo "echo "1" > /proc/sys/net/ipv4/ip_forward" >> /etc/rc.local 
# ipvsadm -A -t 172.16.100.100:80 -s wlc
# ipvsadm -a -t 172.16.100.100:80 -r 172.16.100.10 -g -w 2
# ipvsadm -a -t 172.16.100.100:80 -r 172.16.100.11 -g -w 1

3、浏览器访问测试



四、分享脚本

Director脚本: 

#!/bin/bash
#
# LVS script for VS/DR
#
. /etc/rc.d/init.d/functions
#
VIP=172.16.100.100
RIP1=172.16.100.10
RIP2=172.16.100.11
PORT=80
 
#
case "$1" in
start)
 
  /sbin/ifconfig eth2:0 $VIP broadcast $VIP netmask 255.255.255.255 up
  /sbin/route add -host $VIP dev eth2:0
 
# Since this is the Director we must be able to forward packets
  echo 1 > /proc/sys/net/ipv4/ip_forward
 
# Clear all iptables rules.
  /sbin/iptables -F
 
# Reset iptables counters.
  /sbin/iptables -Z
 
# Clear all ipvsadm rules/services.
  /sbin/ipvsadm -C
 
# Add an IP virtual service for VIP 192.168.0.219 port 80
# In this recipe, we will use the round-robin scheduling method. 
# In production, however, you should use a weighted, dynamic scheduling method. 
  /sbin/ipvsadm -A -t $VIP:80 -s wlc
 
# Now direct packets for this VIP to
# the real server IP (RIP) inside the cluster
  /sbin/ipvsadm -a -t $VIP:80 -r $RIP1 -g -w 1
  /sbin/ipvsadm -a -t $VIP:80 -r $RIP2 -g -w 2
 
  /bin/touch /var/lock/subsys/ipvsadm &> /dev/null
;;
 
stop)
# Stop forwarding packets
  echo 0 > /proc/sys/net/ipv4/ip_forward
 
# Reset ipvsadm
  /sbin/ipvsadm -C
 
# Bring down the VIP interface
  /sbin/ifconfig eth2:0 down
  /sbin/route del $VIP
 
  /bin/rm -f /var/lock/subsys/ipvsadm
 
  echo "ipvs is stopped..."
;;
 
status)
  if [ ! -e /var/lock/subsys/ipvsadm ]; then
    echo "ipvsadm is stopped ..."
  else
    echo "ipvs is running ..."
    ipvsadm -L -n
  fi
;;
*)
  echo "Usage: $0 {start|stop|status}"
;;
esac

RealServer脚本:

#!/bin/bash
#
# Script to start LVS DR real server.
# description: LVS DR real server
#
.  /etc/rc.d/init.d/functions
 
VIP=172.16.100.100
host=`/bin/hostname`
 
case "$1" in
start)
       # Start LVS-DR real server on this machine.
        /sbin/ifconfig lo down
        /sbin/ifconfig lo 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
 
        /sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
        /sbin/route add -host $VIP dev lo:0
 
;;
stop)
 
        # Stop LVS-DR real server loopback device(s).
        /sbin/ifconfig lo:0 down
        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
 
;;
status)
 
        # Status of LVS-DR real server.
        islothere=`/sbin/ifconfig lo:0 | grep $VIP`
        isrothere=`netstat -rn | grep "lo:0" | grep $VIP`
        if [ ! "$islothere" -o ! "isrothere" ];then
            # Either the route or the lo:0 device
            # not found.
            echo "LVS-DR real server Stopped."
        else
            echo "LVS-DR real server Running."
        fi
;;
*)
            # Invalid entry.
            echo "$0: Usage: $0 {start|status|stop}"
            exit 1
;;
esac
 


LVS-TUN

TUN的工作机制跟DR一样,只不过在转发的时候,它需要重新包装IP报文。这里的real server(图中为RIP)离得都比较远。用户请求以后,到director上的VIP上,它跟DR模型一样,每个realserver上既有RIP又有VIPDirector就挑选一个real server进行响应,但是directorreal server并不在同一个网络上,这时候就用到隧道了,director进行转发的时候,一定要记得CIPVIP不能动。我们转发是这样的,让它的CIPVIP不动,在它上面再加一个IP首部,再加的IP首部源地址是DIP,目标地址的RIPIP地址。收到报文的RIP,拆掉报文以后发现了里面还有一个封装,它就知道了,这就是隧道。


其实数据转发原理和DR是一样的,不过这个我个人认为主要是位于不同位置(不同机房);LB是通过隧道进行了信息传输,虽然增加了负载,可是因为地理位置不同的优势,还是可以参考的一种方案;

优点:负载均衡器只负责将请求包分发给物理服务器,而物理服务器将应答包直接发给用户。所以,负载均衡器能处理很巨大的请求量,这种方式,一台负载均衡能为超过100台的物理服务器服务,负载均衡器不再是系统的瓶颈。使用VS-TUN方式,如果你的负载均衡器拥有100M的全双工网卡的话,就能使得整个Virtual Server能达到1G的吞吐量。

不足:但是,这种方式需要所有的服务器支持"IP Tunneling"(IP Encapsulation)协议;


LVS的健康状态检查

在LVS模型中,director不负责检查RS的健康状况,这就使得当有的RS出故障了,director还会将服务请求派发至此服务器,这种情况对用户、企业都是很不爽的,哪个用户倒霉说不定就遇到类似了,为了让director更人性化、可靠还要给director提供健康检查功能;如何实现?Director没有自带检查工具,只有手动编写脚本给director实现健康状态检查功能! 

#!/bin/bash
#
VIP=172.16.100.100
CPORT=80
FAIL_BACK=127.0.0.1
RS=("172.16.100.10" "172.16.100.11")
declare -a RSSTATUS
RW=("2" "1")
RPORT=80
TYPE=g
CHKLOOP=3
LOG=/var/log/ipvsmonitor.log
addrs() {
ipvsadm -a -t $VIP:$CPORT -r $1:$RPORT -$TYPE -w $2
[ $? -eq 0 ] && return 0 || return 1
}
delrs() {
ipvsadm -d -t $VIP:$CPORT -r $1:$RPORT
[ $? -eq 0 ] && return 0 || return 1
}
checkrs() {
local I=1
while [ $I -le $CHKLOOP ]; do
if curl --connect-timeout 1 http://$1 &> /dev/null; then
return 0
fi
let I++
done
return 1
}
initstatus() {
local I
local COUNT=0;
for I in ${RS[*]}; do
if ipvsadm -L -n | grep "$I:$RPORT" && > /dev/null ; then
RSSTATUS[$COUNT]=1
else
RSSTATUS[$COUNT]=0
A++
Dir[0]=$A
fi
let COUNT++
done
}
initstatus
while :; do
let COUNT=0
for I in ${RS[*]}; do
if checkrs $I; then
if [ ${RSSTATUS[$COUNT]} -eq 0 ]; then
addrs $I ${RW[$COUNT]}
[ $? -eq 0 ] && RSSTATUS[$COUNT]=1 && echo "`date +'%F %H:%M:%S'`, $I is back." >> $LOG
fi
else
if [ ${RSSTATUS[$COUNT]} -eq 1 ]; then
delrs $I
[ $? -eq 0 ] && RSSTATUS[$COUNT]=0 && echo "`date +'%F %H:%M:%S'`, $I is gone." >> $LOG
fi
fi
let COUNT++
done
sleep 5
done

LVS持久连接

一、定义

持久连接是指无论LVS使用什么算法,LVS持久都能实现在一定时间内,将来自同一个客户端请求派发至此前选定的RS

二、原理

    无论使用LVS任何调度算法,LVS持久连接都能实现在一定时间内,将来自同一个客户端请求派发至此前选定的服务器;当一个新的客户端请求连接时,LVS就会在内存的缓冲区内记录客户端的IP以及所选的服务器,在一定时间内用户再次访问时,LVS会通过内存缓冲区来查找是否有此用户记录,如果有将直接连接到已选定的服务器上,否则记录IP及连接的服务器;这个内存缓冲区称之为持久连接模板,它存储了每一个客户端,及分配给它的RS的映射关系。

    持久连接在一定环境下还是非常有用的,由于在SSL会话中,比如当用户和服务器好不容易建立了SSL会话,用户一不小心刷新了页面,director有给用户分发了一个新的服务器,用户还要从新建立SSL连接请求,这是很不爽的!这种连接方式称为持久端口连接(PPC),将来自于同一个客户端对同一个集群服务的请求,始终定向至此前选定的RS。

    持久连接还会将同个用户的其他服务请求连接到已建立连接的服务器上,比如当用户访问web服务时,还要能实现https认证,如果访问web时,分配了一个RS,要通过https认证则又分配了一个RS;这样就产生了矛盾,它认证的不是一个RS,使得访问无法安全进行;因此持久连接是必不可少的,这种称为持久客户端连接(PCC),将来自于同一个客户端对所有端口的请求,始终定向至此前选定的RS;把所有端口统统定义为集群服务,一律向RS转发!

    持久防火墙标记连接(PNMPP):定义端口间的姻亲关系,将特定端口定义在同一个RS上。这是通过在防火墙内部PREROUTING链上,将规定的端口打上标记;比如:80端口标记为10,23端口也标记为10;这样在写规则时只需将端口该为10即可,80和23端口就会在同一个RS上响应了


三、持久连接的分类

1、PPC 将来自于同一个客户端对同一个集群服务的请求,始终定向至此前选定的RS;  持久端口连接

2、PCC 将来自于同一个客户端对所有端口的请求始终定向至此前选定的RS            持久客户端连接

把所有端口统统定义为集群服务,一律向RS转发:

定义所有的服务

3、PNMPP 持久防火墙标记连接

定义部分服务


四、持久连接的命令

ipvsadm -A|E ... -p timeout:

timeout:持久连接时长,默认300秒:单位是秒

五、额外的补充


持久连接模板(内存缓冲区)
持久连接模板记录了:每一个客户端IP及分配给它的RS的映射关系
查看持久连接模板 
ipvsadm -L -c  #显示当前的每一个连接模板
ipvsadm -L --persistent-conn #显示当前的持久连接数
{
[root@LVS ~]# ipvsadm -L -c
IPVS connection entries
pro expire state       source             virtual            destination
 
[root@LVS ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.100.100:80 wlc
  -> 172.16.100.10:80             Route   1      0          0         
  -> 172.16.100.11:80             Route   2      0          0   
}
 
PNMPP的语法
PREROUTING
    80:标记10
    23:标记10
语法:
/sbin/iptables -F -t mangle
/sbin/iptables -A PREROUTING -i eth0 -t mangle -p tcp -d 172.16.100.6 --dport 80 -j MARK -set-mark 1
/sbin/iptables -A PREROUTING -i eth0 -t mangle -p tcp -d 172.16.100.6 --dport 443 -j MARK -set-mark 1
         
/sbin/ipvsadm -A -f 1 -s rr -p 3600
/sbin/ipvsadm -a -f 1 -r 172.16.100.10 -g -w 2
/sbin/ipvsadm -a -f 1 -r 172.16.100.11 -g -w 1
 

六、部署 
假如后端有多台RS;同时定义了两个集群服务,web服务和telnet服务
目的:前端用户访问80端口的时候会同时负载后端的多台RS上,并且23号端口的访问也会同时负载到多台RS上。
描述:后端有多台RS。每台RS上同时提供web服务和telnet服务。我们希望前端用户访问的时候,对80端口发起的访问请求会分别负载到多台RS上。
同时对23号端口的访问也会负载到多台RS上。所以说,它们同时提供了两类集群服务,那么就是Dirctor同时提供两种集群服务的负载均衡。
 
结论:
持久连接有这种功能
比如,user1访问80端口服务的时候,Director把报文转发RS1上;当user1下次在访问23号端口的时候,Director还是会把报文转发RS1上的。
 
 
1、ipvsadm轮询算法rr
[root@LVS ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.100.100:80 rr
  -> 172.16.100.10:80             Route   1      0          0         
  -> 172.16.100.11:80             Route   2      0          0 
结论:通过上面的轮询算法rr;用浏览器访问的结果是
第一次被定向到RS1上面
第二次被定向到RS2上面
第三次被定向到RS1上面
第四次被定向到RS2上面
......
 
2、ipvsadm的持久连接web服务(PPC)
[root@LVS ~]# ipvsadm -E -t 172.16.100.100:80 -s rr -p 600
[root@LVS ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.100.100:80 rr persistent 600
  -> 172.16.100.10:80             Route   1      0          0         
  -> 172.16.100.11:80             Route   2      0          0  
结论:通过上面的持久连接;用浏览器访问的结果是
如果此时定向到RS1上,那么刷新页面之后被定向到RS2上,以后你无论怎么刷新都被定向到RS2上面。
 
[root@LVS ~]# ipvsadm -L --persistent-conn
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port            Weight    PersistConn ActiveConn InActConn 
  -> RemoteAddress:Port
TCP  172.16.100.100:http rr persistent 600
  -> 172.16.100.10:http           1         0           0          0         
  -> 172.16.100.11:http           2         1           0          16        
[root@LVS ~]# ipvsadm -L -c
IPVS connection entries
pro expire state       source             virtual            destination
TCP 00:00  FIN_WAIT    172.16.100.2:52083 172.16.100.100:http 172.16.100.11:http
TCP 00:10  FIN_WAIT    172.16.100.2:52086 172.16.100.100:http 172.16.100.11:http
TCP 00:00  FIN_WAIT    172.16.100.2:52071 172.16.100.100:http 172.16.100.11:http
TCP 00:00  FIN_WAIT    172.16.100.2:52085 172.16.100.100:http 172.16.100.11:http
TCP 08:00  NONE        172.16.100.2:0     172.16.100.100:http 172.16.100.11:http
TCP 00:00  FIN_WAIT    172.16.100.2:52084 172.16.100.100:http 172.16.100.11:http
 
 
3、ivpsadm的持久连接telnet服务(PPC)
注意:telnet是不允许超级管理员root直接远程登陆的
 
{
#安装、启动telnet服务
# yum -y install telnet-server
# chkconfig --add telnet
# chkconfig telnet on
 
# useradd jerry
# passwd jerry
 
# netstat -tnlp |grep :23
}
 
{
#定义telnet集群服务
ipvsadm -C
ipvsadm -A -t 172.16.100.100:23 -s rr
ipvsadm -a -t 172.16.100.100:23 -r 172.16.100.10 -g -w 2
ipvsadm -a -t 172.16.100.100:23 -r 172.16.100.11 -g -w 1
 
测试1
Xshell:\> telnet 172.16.100.100
login: jerry
Password: jerry
[jerry@web2 ~]$  #RS2
看主机名称可以辨别出连接的是哪一台RS,然后退出后在此登陆
Xshell:\> telnet 172.16.100.100
login: jerry
Password: jerry
[jerry@web1 ~]$  #RS1
 
 
支持持久连接的telnet服务
[root@LVS ~]# ipvsadm -E -t 172.16.100.100:23 -s rr -p 3600
[root@LVS ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.100.100:23 rr persistent 3600
  -> 172.16.100.10:23             Route   2      0          0         
  -> 172.16.100.11:23             Route   1      0          1  
测试2 
Xshell:\> telnet 172.16.100.100
login: jerry
Password: jerry
[jerry@web1 ~]$  #RS1
退出后再次登陆
Xshell:\> telnet 172.16.100.100
login: jerry
Password: jerry
[jerry@web1 ~]$  #RS1
结论:telnet集群服务的持久连接成功
}
 
 
4、ipvsadm持久连接(PCC)
{
#把0端口定义成集群服务,这意味所有的端口都是集群服务
ipvsadm -C
ipvsadm -A -t 172.16.100.100:0 -s rr -p 600
ipvsadm -a -t 172.16.100.100:0 -r 172.16.100.10 -g -w 2
ipvsadm -a -t 172.16.100.100:0 -r 172.16.100.11 -g -w 1
 
测试 浏览器、telnet、ssh
浏览器访问被定向到比如RS2
 
telnet测试被定向到RS2
Xshell:\> telnet 172.16.100.100
login: jerry
Password: jerry
[jerry@web2 ~]$  #RS2
 
ssh 172.16.100.100
[root@web2 ~]# 
 
看下连接的模板
[root@LVS ~]# ipvsadm -L -c
IPVS connection entries
pro expire state       source             virtual            destination
TCP 14:32  ESTABLISHED 172.16.100.2:52735 172.16.100.100:ssh 172.16.100.11:ssh
TCP 00:09  NONE        172.16.100.2:0     172.16.100.100:0   172.16.100.11:0
TCP 04:11  NONE        172.16.100.2:0     172.16.100.100:telnet 172.16.100.10:telnet
TCP 14:55  ESTABLISHED 172.16.100.2:52499 172.16.100.100:telnet 172.16.100.11:telnet
}
 
 
5、ivpsadm持久连接(PCC)
现在把23端口和80端口的定义成一个集群服务
      22端口的是另外一个集群服务
ipvsadm -C
service ipvsadm restart
ipvsadm -L -n
 
iptables -A PREROUTING -i eth2 -t mangle -p tcp -d 172.16.100.100 --dport 80 -j MARK --set-mark 8
iptables -A PREROUTING -i eth2 -t mangle -p tcp -d 172.16.100.100 --dport 23 -j MARK --set-mark 8   
     
ipvsadm -A -f 8 -s rr [-p 600]
ipvsadm -a -f 8 -r 172.16.100.10 -g -w 2
ipvsadm -a -f 8 -r 172.16.100.11 -g -w 1    
 
结论:
由于22端口的ssh服务没有被定义成集群服务,所以在登陆的时候是Director来响应
Xshell:\> ssh 172.16.100.100
[root@LVS ~]# 
 
由于80服务和23服务都被定义集群服务,所以在访问的时候应该是调度算法轮询来响应的
Xshell:\> telnet 172.16.100.100
login: jerry
Password: 
[jerry@web2 ~]$ 
退出再次访问
Xshell:\> telnet 172.16.100.100
login: jerry
Password: 
[jerry@web1 ~]$ 
 
 
浏览器访问也是一样的,轮询这响应请求
第一次响应的是RS1
第二次响应的是RS2
第三次响应的是RS1
第四次响应的是RS2

文章最后又出现了这个—— 本文出自 “郑彦生” 博客,请务必保留此出处

http://467754239.blog.51cto.com/4878013/1549699 

 好吧,你们都是原作者。








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值