lvs持久性工作原理和配置

LVS持久连接技术

lvs的持久性连接有两方面:

  1. 把同一个client的请求信息记录到lvs的hash表里,保存时间使用persistence_timeout控制,单位为秒。persistence_granularity 参数是配合persistence_timeout的,在某些情况特别有用,他的值是子网掩码,表示持久连接的粒度,默认是255.255.255.255,也就是单独的client ip,如果改成,255.255.255.0就是client ip一个网段的都会被分配到同一个real server。
  2. 一个连接创建后空闲时的超时时间,这个时间为3种
    • tcp的空闲超时时间
    • lvs收到客户端tcp fin的超时时间
    • udp的超时时间

如何查看这些值?

ipvsadm  # 可以查看连接空闲的超时时间(persistent 10)。

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  122.225.32.142:http rr persistent 10
-> 122.225.32.137:http          Route   1      0          1
-> 122.225.32.136:http          Route   1      0          0

ipvsadm -L -timeout  # 查看tcp tcpfin udp的超时时间

Timeout (tcp tcpfin udp): 900 120 300

他们是如何工作的?

ipvsadm -Lcn

IPVS connection entries
pro expire state       source             virtual            destination
TCP 00:57  NONE        110.184.96.173:0   122.225.32.142:80  122.225.32.136:80
TCP 01:57  FIN_WAIT    110.184.96.173:54568 122.225.32.142:80  122.225.32.136:80

当一个client访问vip的时候,ipvs或记录一条状态为NONE的信息,expire初始值是persistence_timeout的值,然后根据时钟主键变小,在以下记录存在期间,同一client ip连接上来,都会被分配到同一个后端。

FIN_WAIT的值就是tcp tcpfin udp的超时时间,当NONE的值为0时,如果FIN_WAIT还存在,那么NONE的值会从新变成60秒,再减少,直到FIN_WAIT消失以后,NONE才会消失,只要NONE存在,同一client的访问,都会分配到统一real server。

如何设置这些值?

lvs持久性用途

http://www.linuxvirtualserver.org/docs/persistence.html

有些Web服务可能用到HTTP Cookie,它是将数据存储在客户的浏览器来追踪和标识客户的机制。使用HTTP Cookie后,来同一客户的不同连接存在相关性,这些连接必须被发送到同一Web服务器。
另有些Web服务可能使用安全的HTTPS协议,它是HTTP协议加SSL协议。当客户访问HTTPS服务(HTTPS的缺省端口为 443)时,会先建立一个SSL连接,来交换对称公钥加密的证书并协商一个SSL Key,来加密以后的会话。
*在SSL Key的生命周期内,后续的所有HTTPS连接都使用这个SSL Key,所以同一客户的不同HTTPS连接也存在相关性。*
在C/S架构中,Client和Server间的多个连接有时存在着关联性。
比如FTP主动模式的20和21两个端口:21默认为监听端口、20则为数据传输端口。
20端口的开启是建立在21端口进行了有效的用户确认和文件交互确认后才会开启的,是Server主动连接Client所告知的端口。
但是在FTP的被动模式下,是Server主动将自己开放的随机数据端口告知Client,然后Client再去和Server的新端口建立新的TCP连接。
假如`persistence_timeout`该选项注释掉,那么Client和Server间建立的新的TCP连接有可能被负载到另外一台RealServer上去,引起失败。

针对这些需要,IPVS调度器提供了持久服务的功能,它可以使得在设定的时间内,来自同一IP地址的不同连接会被发送到集群中同一个服务器结点,可以很好地解决客户连接的相关性问题。

此选项对于连接关联性是一个很好的解决方案,但是会造成轻微的负载不均衡(官方原文:slight load imbalance)

当某些网络设置了代理服务,LVS看到Client均为同一来源IP地址,从而造成所有流量均转至同一RealSever问题。

应如何取值

那么应该如何配置persistence_timeout呢?你可能看过一些文章说这个超时时间最好配置成跟lvs_timeouts一致,当然这么配没什么问题,但其实二者没有必然的联系,lvs_timeouts想保护的是一个人(单一连接),而persistence_timeout想保护的是一类人(源自统一client ip的连接),根据实际情况将二者设置为不同值会更合理一些。

处于负载均衡的考虑,不建议将persistence_timeout配置的太大,这样可能会导致长时间client总是被转发到同一个real server。

而lvs_timeouts建议配置为 >7200。为什么呢?TCP的保活定时器默认时间是2小时,当保活定时器超时时:

lvs的持久连接

本文出自 “成长全记录” 博客,请务必保留此出处http://lymrg.blog.51cto.com/1551327/684681

由于HTTP是一种无状态协议,每次请求完毕之后就立即断开了,当用户浏览购物网站挑选商品的时候,看到一件商品加入购物车,此过程被重定向到了REALSERVER1上面来,当把第二件商品加入购物车又被重定向到了REALSERVER2上面,最后结账的时候在REALSERVER2上面,只有一件商品,这显然是用户无法接受的,此时就需要一种持久连接机制,来把同一用户的HTTP请求在超时时间内都重定向到同一台REALSERVER,超时时间可以自己定义,比如说2个小时,在超时时间内服务器会不断追踪用户的访问请求,把某一用户的所有请求都转发到同一台REALSERVER上面,如果超时时间过后用户依然在访问,则默认按照每次两分钟的方式无限加长

这里的所有操作都以DR模型为例,试验环境参见:http://lymrg.blog.51cto.com/1551327/660925

对于LVS的持久连接来说常见的分为三种PCC,PPC和基于防火墙标记的持久连接,下面我们就来分别讨论

PCC

PCC用来实现把某个用户的所有访问在超时时间内定向到同一台REALSERVER,这种方式在实际中不常用

ipvsadm -A -t 192.168.0.1:0 -s wlc -p 600(单位是s)
ipvsadm -a -t 192.168.0.1:0 -r 192.168.1.2 -w 4 -g
ipvsadm -a -t 192.168.0.1:0 -r 192.168.1.3 -w 2 -g

此时测试一下会发现通过HTTP访问VIP和通过SSH登录VIP的时候都被定向到了同一台REALSERVER上面了

PPC

PPC用来把某个用户对同一服务的访问在超时时间内定向到同一台REALSERVER

ipvsadm -A -t 192.168.0.1:80 -s wlc -p 600
ipvsadm -a -t 192.168.0.1:80 -r 192.168.1.2 -w 4 -g
ipvsadm -a -t 192.168.0.1:80 -r 192.168.1.3 -w 2 -g

ipvsadm -A -t 192.168.0.1:22 -s wlc -p 300
ipvsadm -a -t 192.168.0.1:22 -r 192.168.1.2 -g
ipvsadm -a -t 192.168.0.1:22 -r 192.168.1.3 -g

此时再测试会发现某个用户在超时时间内对于某个服务的访问都会被重定向到同一台REALSERVER上面

防火墙标记

基于防火墙标记的持久连接

对于电子商务网站来说,用户在挑选商品的时候使用的是80端口来浏览的,当付款的时候则是通过443的ssl加密的方式,当然当用户挑选完商品付款的时候我们当然不希望https的443跳转到另外一台REALSERVER,很显然应该是同一REALSERVER才对,这时候就要用到基于防火墙标记的持久连接,通过定义端口的姻亲关系来实现

  1. 首先两个REALSERVER要配置SSL,很明显证书应该也是一样的
  2. 定义端口的姻亲关系,给80和443端口打上同样的防火墙标记
  3. 配置实现基于防火墙标记的LVS

yum install mod_ssl 两个服务器上面都安装一下

在REALSERVER1上面。也就是192.168.1.2上面如下操作

cd /etc/pki/tls/certs/
make httpd.pem  #此种SSL证书的生成方式只为测试,在实际操作中构建

SSL参见我博客前面的完整步骤

填写相关信息,主机名称一定要和VIP在互联网上面解析的DNS名称一致

cp httpd.pem /etc/httpd/
vi /etc/httpd/conf.d/ssl.conf

# 找到如下行启用并且修改
DocumentRoot "/var/www/html"
ServerName www.test.org:443   #这里修改为你得服务器名称

# 修改证书路径
SSLCertificateFile /etc/httpd/httpd.pem
SSLCertificateKeyFile /etc/httpd/httpd.pem

scp httpd.pem 192.168.1.3:/etc/httpd
scp /etc/httpd/conf.d/ssl.conf 192.168.1.3:/etc/httpd/conf.d/

防火墙添加mark

iptables -t mangle -A PREROUTING -d 192.168.0.1 -p tcp --dport 80 -j MARK --set-mark 10 (0-99范围)
iptables -t mangel -A PREROUTING -d 192.168.0.1 -p tcp --dport 443 -j MARK --set-mark 10
ipvsadm -A -f 10 -s wlc -p 600
ipvsadm -a -f 10 -r 192.168.1.2 -g -w 4
ipvsadm -a -f 10 -r 192.168.1.3 -g -w 2

本文出自 “成长全记录” 博客,请务必保留此出处http://lymrg.blog.51cto.com/1551327/684681

关于arp_announce和arp_ignore

http://lymrg.blog.51cto.com/1551327/660925

VS/DR或VS/TUN应用的一种模型中(所有机器都在同一个物理网络),所有机器(包括Director和RealServer)都使用了一个额外的IP地址,即VIP。

当一个客户端向VIP发出一个连接请求时,此请求必须要连接至Director的VIP,而不能是RealServer的。因为,LVS的主要目标就是要Director负责调度这些连接请求至RealServer的。因此,在Client发出至VIP的连接请求后,只能由Director将其MAC地址响应给客户端(也可能是直接与Director连接的路由设备),而Director则会相应的更新其ipvsadm table以追踪此连接,而后将其转发至后端的RealServer之一。

如果Client在请求建立至VIP的连接时由某RealServer响应了其请求,则Client会在其MAC table中建立起一个VIP至RealServer的对就关系,并以至进行后面的通信。此时,在Client看来只有一个RealServer而无法意识到其它服务器的存在。

为了解决此问题,可以通过在路由器上设置其转发规则来实现(静态的MAC-IP绑定)。当然,如果没有权限访问路由器并做出相应的设置,则只能通过传统的本地方式来解决此问题了。 这些方法包括:

  1. 禁止RealServer响应对VIP的ARP请求;
  2. 在RealServer上隐藏VIP,以使得它们无法获知网络上的ARP请求;
  3. 基于“透明代理(Transparent Proxy)”或者“fwmark (firewall mark)”;
  4. 禁止ARP请求发往RealServers;

传统认为,解决ARP问题可以基于网络接口,也可以基于主机来实现。Linux采用了基于主机的方式,因为其可以在大多场景中工作良好,但LVS却并不属于这些场景之一,因此,过去实现此功能相当麻烦。现在可以通过设置arp_ignore,arp_announce,这变得相对简单的多了。

Linux 2.2和2.4(2.4.26之前的版本)的内核解决“ARP问题”的方法各不相同,且比较麻烦。幸运的是,2.4.26和2.6的内核中引入了两个新的调整ARP栈的标志(device flags):arp_announce和arp_ignore。基于此,在DR/TUN的环境中,所有IPVS相关的设定均可使用arp_announce=2和arp_ignore=1/2/3来解决“ARP问题”了。以下是官方说明:

arp_annouce:Define different restriction levels for announcing the local source IP address from IP packets in ARP requests sent on interface;
0 - (default) Use any local address, configured on any interface.
1 - Try to avoid local addresses that are not in the target's subnet for this interface. 
2 - Always use the best local address for this target.

arp_ignore: Define different modes for sending replies in response to received ARP requests that resolve local target IP address.
0 - (default): reply for any local target IP address, configured on any interface.
1 - reply only if the target IP address is local address configured on the incoming interface.
2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender's IP address are part from same subnet on this interface.
3 - do not reply for local address configured with scope host,only resolutions for golbal and link addresses are replied.
4-7 - reserved
8 - do not reply for all local addresses

arp_announce

定义了网卡在向外宣告自己的MAC-IP时候的限制级别,有三个值:

arp_ignore

定义了网卡在响应外部ARP请求时候的响应级别,这里有8个值,但我们只使用了2个

在RealServers上,VIP配置在本地回环接口lo上。如果回应给Client的数据包路由到了eth0接口上,则arp通告或请应该通过eth0实现,因此,需要在sysctl.conf文件中定义如下配置:

vim /etc/sysctl.conf
net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.eth0.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2

以上选项需要在启用VIP之前进行,否则,则需要在Drector上清空arp表才能正常使用LVS。

关于连接追踪

到达Director的数据包首先会经过PREROUTING,而后经过路由发现其目标地址为本地某接口的地址,因此,接着就会将数据包发往INPUT(LOCAL_IN HOOK)。此时,正在运行内核中的ipvs(始终监控着LOCAL_IN HOOK)进程会发现此数据包请求的是一个集群服务,因为其目标地址是VIP。于是,此数据包的本来到达本机(Director)目标行程被改变为经由POSTROUTING HOOK发往RealServer。这种改变数据包正常行程的过程是根据IPVS表(由管理员通过ipvsadm定义)来实现的。

如果有多台Realserver,在某些应用场景中,Director还需要基于“连接追踪”实现将由同一个客户机的请求始终发往其第一次被分配至的Realserver,以保证其请求的完整性等。其连接追踪的功能由Hash table实现。Hash table的大小等属性可通过下面的命令查看:

ipvsadm -Lcn

为了保证其时效性,Hash table中“连接追踪”信息被定义了“生存时间”。LVS为记录“连接超时”定义了三个计时器:

  1. 空闲TCP会话;
  2. 客户端正常断开连接后的TCP会话;
  3. 无连接的UDP数据包(记录其两次发送数据包的时间间隔);

上面三个计时器的默认值可以由类似下面的命令修改,其后面的值依次对应于上述的三个计时器:

ipvsadm --set 28800 30 600

数据包在由Direcotr发往Realserver时,只有目标MAC地址发生了改变(变成了Realserver的MAC地址)。Realserver在接收到数据包后会根据本地路由表将数据包路由至本地回环设备,接着,监听于本地回环设备VIP上的服务则对进来的数据库进行相应的处理,而后将处理结果回应至RIP,但数据包的原地址依然是VIP。

DIP要配置在接口上,VIP要配置在接口别名上

RIP要配置在接口上,VIP要配置在lo的别名上

定义内核参数,禁止响应对VIP的ARP广播请求

echo 1>/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 1>/proc/sys/net/ipv4/conf/all/arp_ignore
echo 2>/proc/sys/net/ipv4/conf/lo/arp_announce
echo 2>/proc/sys/net/ipv4/conf/all/arp_announce

配置VIP

ifconfig lo:0 $192.168.0.1 broadcast $192.168.0.1 netmask 255.255.255.255 up
route add -host 192.168.0.1 dev lo:0 # 确保如果请求的目标IP是$VIP,那么让出去的数据包的源地址也显示为$VIP

在前端服务器配置并启动服务

ipvsadm -A -t 192.168.0.1:80 -s wlc 
ipvsadm -a -t 192.168.0.1:80 -r 192.168.1.2 -g -w 4 
ipvsadm -a -t 192.168.0.1:80 -r 192.168.1.3 -g -w 2
ipvsadm -L -n

ab -c -n 10000 http://192.168.0.1/index.html 
watch -n 1 'ipvsadm -L -n'