标签:linux lvs
Linux Virtual Server, 章文嵩所开发。
lvs又称为layer4 router和layer4 switch,它是根据目标地址和端口作出转发与否的决策,根据调度方法作出转发至哪一个后端的决策。
lvs组成部分:ipvs, ipvsadm。ipvs工作在内核,ipvsadm工作在应用层。它们之间的关系就相当于netfilter和iptables。同时,ipvs是工作在netfilter之上的。
netfilter五个链:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING。ipvs就工作于netfilter的INPUT链。
用户的请求本来是通过INPUT链,送往用户空间的进程的。但工作在input链上的ipvs却会检查此请求,一旦发现请求端口是被定义为集群服务,它就会强行将此报文的地址改为挑选出的后端主机的地址,扔到FORWARD链。通过POSTROUTING链发往后端。
ipvsadm用于在ipvs上定义集群服务,同时也得定义此集群服务对应于有哪个后端主机可用。
ipvs如何挑选后端主机呢?根据所指定的调度方法(算法)作出调度决策。
支持的协议(就是四层协议):TCP, UDP, SCTP, AH, ESP, AH_ESP
主机相关:
Director:调度器
Real Server:RS,后端真正提供服务的主机。
IP地址相关:
Client:CIP,客户端IP
Director Virtual IP:VIP,调度器面向客户端的IP。由于调度器会成为单点,因此需要对调度器做高可用。由此,如果A调度器故障了,此地址是要转移到B调度器上的。
Director IP:DIP,调度器面向后端的IP
Real IP:RIP,后端服务器的IP
1、lvs-nat又称为masquerade,因为这是通过地址伪装实现的。
2、lvs-dr,direct routing,又称为dr类型。
3、lvs-tun,tunneling隧道,基于ip隧道
4、lvs-fullnat,完全nat,既改目标地址又改源地址。
类似于DNAT, 但支持多目标转发。用户请求到达调度器后,经过ipvs的改写,将请求发给后端某一主机。此时,该请求的源地址依然为CIP,但目标地址就改为了RIP。后端RS收到后进行响应,响应报文的源地址为RIP,目标地址为CIP。
但问题是CIP并没有访问RIP啊?因此,此响应报文还得经过调度器。通过调度器net的追踪机制,发现其实用户访问的是VIP。由此,响应报文的源IP便会被改为VIP,而后扔给客户端。
它通过修改请求报文的目标地址为根据调度算法所挑选出的某RS的RIP来进行转发。
架构特性:
(1) RS应该使用私有地址,即RIP应该为私有地址,各RS的网关必须指向DIP。
(2) 请求和响应报文都经由Director转发,高负载场景中,Director易于成为系统瓶颈。
(3) 支持端口映射
(4) RS可以使用任意类型的OS
(5) RS的RIP必须与Director的DIP在同一网络,因此,无法跨网络。
架构类型:
用户请求不管从哪来,最终总会到达我们的网关,而后到达交换机,调度器和各RS都连接在此交换机之上。用户的请求会先到达调度器,而后由调度器调度至各RS。但RS的响应报文,不经过调度器而直接发给客户端。
那这是怎么实现的呢?首先用户请求的源IP是CIP,目标地址是VIP。但经由调度器内的ipvs改写发往RS时,源ip为CIP,目标依然为VIP。因为如果不是VIP如何能够直接响应客户端呢?但目标IP是自己,报文怎么可能送出去呢?这是因为每个RS上都有VIP。
但是这样一来路由器怎么知道此请求就是发给调度器上的VIP,而不是其他RS上的呢?报文外面还有一层源目MAC,ipvs直接将目的MAC地址改为挑选出来的RS的MAC地址后,扔给交换机。交换机正好是通过MAC地址来定位主机的,这就妥了。RS收到后,请求是CIP,本地又有VIP,于是直接响应客户端。
那DIP在哪呢?在dr类型下,所有地址都不能少。事实上,调度器的接口上配置的是DIP,但是在网卡上定义的别名为VIP。那RS的VIP定义在哪呢?定义在回环地址的别名上。但回环地址是无法和外部通信的,因此,响应报文还是会经过RIP接口出去的。
完整过程:
用户请求到达路由器时,就会做ARP地址解析,因为本地网络通信依靠的不是IP而是MAC。路由器会广播VIP对应的MAC地址,但是现在拥有VIP的不止一个。那怎么办呢?很简单,让RS收到广播后不予响应或者不让响应报文出去。这样就能保证请求报文会发送到调度器。
调度器收到后,ipvs要将地址改为挑选出的RS的MAC地址,但是它怎么获得RS的MAC地址呢?通过广播,因此,此时又需要RS能够响应调度器的ARP广播。这样,报文就顺利的到达了RS。
Linux有个特性:报文从哪个网卡出去,那么此报文的源IP就必须为此网卡的IP。RS发现响应的目标是CIP,如果响应报文直接从RIP网卡出去的话,源IP就不再是VIP,这样客户端是不会接受的。那如何是好?当调度器将请求发送到RS后,必然会到达VIP所在的lo接口。我们就可以强行让响应报文经过lo接口,并且通过FORWARD链转发至RIP网卡,再从此网卡出去就OK。
调度器和RS可以不在同一个网段,那就是RS网关指向的是路由器的另一个接口,此接口也连至交换机。还可以是RS的网关指向另一个路由器,但此路由器也连接到交换机。
总结:Director在实现转发时不修改请求的IP首部,而是通过直接封装MAC首部完成转发。目标MAC是Director根据调度方法挑选出某RS的MAC地址,拓扑结构有别有NAT类型。
架构特性:
1、保证前端路由器将目标地址为VIP的请求报文,通过ARP地址解析后送往Director。解决方案有三种。
(1) 静态绑定:在前端路由直接将VIP对应的目标MAC静态配置为Director的MAC地址。
(2) arptables:红帽提供,在各RS上,通过arptables规则拒绝其响应对VIP的ARP广播请求。
(3) 内核参数:在RS上修改内核参数,并结合地址的配置方式实现拒绝响应对VIP的ARP广播请求。这才是经常使用的。
2、RS的RIP可以使用私有地址,但也可以使用公网地址。此时可通过互联网上的主机直接对此RS发起管理操作,但同时也给了其他人可乘之机。
3、请求报文必须经由Director调度,但响应报文必须不能经由Director。这样一来,大大减轻了Director的压力,使Director很难成为性能的瓶颈了。
4、各RIP必须与DIP在同一个物理网络中,意思是不能通过路由器转发。因为调度器和RS通信是靠MAC地址的,而MAC地址只会依赖本地网络。
5、不支持端口映射,因为是由RS响应的,地址和端口都不能改变。
6、RS可以使用大多数的OS
7、RS的网关一定不能指向Director
nat和dr类型限制了调度器和各RS之间不能距离太远,这样就无法做到异地容灾。lvs-tun存在的意义就是突破前两种的限制。
lvs-tun中调度器和各RS可以不在同一个网络,甚至可以跨越千山万水。而调度器上的VIP,是唯一地址。当用户请求在到达调度器上时,此调度器上的ipvs需要将请求发给后端的RS,但DIP和RIP并不在同一个网络。RS收到报文后,需要直接响应给客户端,响应客户端的源地址和目标地址为CIP和VIP。因此,RS本地必须具有VIP。
tun利用IP隧道来传输IP报文,模拟出一个隧道,让两个点能够在隧道中进行传输,也可以构建二层链路层隧道。因此,当用户请求到达调度器时,请求的源目地址分别为CIP和VIP。ipvs将请求转发至挑选出的RS,此时报文的源目IP依然为CIP和VIP,但是会在此报文的基础上再加一个IP首部,最外层IP首部的源目IP分别为DIP和RIP。
但RS必须支持基于IP的隧道报文。RS收到报文,将最外层的首部拆掉后,就会将内层的源目IP当做请求者和响应者。再经过本地的VIP,将响应报文发给CIP。
总结:不修改请求报文IP首部,而是通过IP隧道机制在原有的IP报文之外再封装IP首部,经由互联网把请求报文交给选定的RS。
架构特性:
1、RIP, DIP, VIP都是公网地址。
2、RS的网关不能、也不可能指向DIP。
3、请求报文由Director分发,但响应报文直接由RS响应给Client。
4、不支持端口映射,所有响应报文不经过Director的,都不支持端口映射。
5、RS的OS必须得支持IP隧道
fullnat无非就是nat,但DIP和RIP之间可以经过路由进行转发。当请求到来时,源目IP分别为CIP和VIP。到达调度器后,还是由ipvs挑选一台主机,但由于DIP和RIP并不在同一个网段,所以ipvs会将请求的报文源目IP分别改为DIP和RIP。RS收到报文后,就会将响应报文发给DIP,这是毋庸置疑的。调度器在收到报文,通过在内部追踪nat表以后,将响应报文的源目IP分别改为VIP和CIP,于是报文就发给客户端。这种源目IP都进行修改的LVS类型就是fullnat。
总结:通过请求报文的源地址为DIP,目标为RIP来实现转发。对于响应报文而言,修改源地址为VIP,目标地址为CIP来实现转发。
架构特性:
1、1RIP,DIP可以使用私有地址。
2、RIP和DIP可以不在同一个网络中,且RIP的网关未必需要指向DIP。
3、支持端口映射
4、RS的OS可以使用任意类型
5、请求报文经由Director,响应报文经由Director。
因此,此架构能扛住每秒20W的并发,如果对并发要求不是特别的高,但又希望使用更复杂的内网模型,fullnat是一个不错的选择。但内核不支持fullnat,并且ipvsadm也不知写这样的规则。
调度方法,调度方法一般分为静态和动态两类。
centos 6在内核编译中已经支持LVS
[root ~]# grep -i ipvs /boot/config-2.6.32-504.el6.x86_64 # IPVS transport protocol load balancing support # IPVS scheduler # IPVS application helper [root ~]# grep -A 10 scheduler /boot/config-2.6.32-504.el6.x86_64 # 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
仅根据算法本身实现调度。
1、RR:round-robin, 轮询、轮叫、轮调、轮流。最简单的调度方式
2、WRR:weighted round-robin, 加权轮询,给每个RS一个权重。权重越大,承载能力越强。如果一个RS的权重是2,另一个权重是1,那么RS1将承载2/3的请求,RS2则为1/3,因为总权重为3。这种算法简单粗暴。
3、SH:Source ip Hashing,源地址哈希。当请求到达调度器时,调度器会在内存中找一段空间,将请求中的源地址抽取出来,做哈希计算。如果该用户是第一次请求,它会通过算法挑一台后端RS,并将这台RS和用户请求的哈希计算的结果对应起来,保存在哈希表中。所以,当用户请求到达时,会先查这张表。因此,它会将来自同一个地址请求,统统定向至此前选定的RS。这是一种反负载均衡的算法。那这种算法意义何在?会话保持。防止购物车中的信息刷新后没了。
4、DH:Destination ip Hashing, 目标地址哈希。特殊场景中才会用到,比如一个公司内部的出口有多个。为了防止内部的用户,请求通过第一个防火墙出去,但响应是通过第二个防火墙进来,但防火墙只允许通过它出去的响应报文才能进来,导致用户无法收到响应报文的情况。因此在公司内部搞一个调度器,将用户请求为某目标的,比如百度,统统经过固定的防火墙出去。可以增加缓存的命中率,这种场景很少见。
静态方法有极大的缺陷,因为它不管后端的负载情况。虽然静态方法可以保证每台RS分配的请求都是一样,但请求也是有区别的,有的请求花的时间长,而有的花的时间短。所以,静态方法只能保证起点公平,而无法保证结构公平。
根据算法及后端RS当前的负载状况实现调度。动态算法会给每个正在调度的RS,一个计算当前负载的值Overhead,数字越小的将被当做下一个调度的目标,因为数字小表示负载低。
1、LC:least connection,最少连接,谁的连接少下次就分给谁。
公式:Overhead=Active*256+Inactive
2、WLC:weighted least connection,加权最小连接。但是这样就会造成当活动连接都相等时,下一个连接会分配给排在第一位,而不是权重最高的RS。
公式:Overhead=(Active*256+Inactive)/weight
3、SED:Shorted Expection Delay,最短期望延迟,弥补WLC的缺陷。但是缺陷在于,当各RS权重过大时,前几个连接都给了权重最大的那个。
公式:Overhead=(Active+1)*256/weight
4、NQ:Never Queue,永不排队。上来就给每一台RS分配一个连接。如果再来新连接就根据SED算法计算。
5、LBLC:Local-Based Least Connection,基于本地的最小连接。动态方式的DH算法,当某个RS负载过大时,就会进行调度,但是会降低缓存命中率。
6、LBLCR:Replicated LBLC,带复制的LBLC。假设各RS之间能够进行通信,直接就能复制缓存。
针对负载计算的公式:
Active:活动连接状态,表示正在传数据的。
Inactive:非活动连接状态,类似于保持连接状态,传输已经完成,但是连接并未断开。
weight:权重,权重越大,承载能力越强。
因为活动连接占用资源多,占用的比重大,所以*256。
如果刚开始,各RS都为0,或者多台RS的值都一样时,那怎么挑选?按次序进行。使用ipvsadm定义时,会按先后次序添加。排在第一位的优先。
wlc被视为默认调度算法,要考虑session的话,就只能使用SH了。因为lvs工作在四层,所以无法基于cookie做调度。而正因为lvs工作在四层,所以它的连接数不受套接字的限制,才能有那么好的性能。
session是服务器端的应用程序,为每一个客户端在服务器上活动时,记录下来活动的行为,比如向购物车中添加商品。
1、SH调度算法,但是此方法是反负载均衡的,效果不行。
2、将后端的RS做多播会话共享集群,session复制集群。这个集群缺点在于,后端每台RS都要维护RS数量倍数的会话,RS数量越多,RS的压力就越大。好处是就算有RS宕机了,会话也不会丢失。
3、通过专门的存储来储存这些会话。当用户的请求到达时,会话信息会直接保存至后端的如memcached缓存服务器中。这样一来,任何RS在追踪会话时,都不会在本地内存中找,而是查找对应的服务器。缺点是:后端存储需要做高可用;后端存储的性能要好,可能需要做分布式。
4、基于cookie而不再是IP做调度。用户在访问服务器时,服务器会给客户端发一个瘦cookie,而后将每个cookie和session的对应关系,保存在一个表中。此后客户端请求时,服务器通过追踪客户端提交的cookie来关联它的session。由于LVS工作在4层而不是应用层,因此不支持。因此haproxy和Nginx便有了用武之地。
一般来讲,iptables最好不要和lvs一起使用。
ipvsadm大体分为几类:
管理集群服务:创建、修改、删除
管理集群服务的RS:添加、修改、移除
查看:统计数据和速率。
创建或修改:ipvsadm -A|E -t|u|f service-address [-s scheduler]
-A:添加
-E:修改
-t:承载的应用层协议为基于TCP协议提供服务的协议。其service-address的格式为“VIP:PORT”,如“172.16.100.6:80”。
-u:承载的应用层协议为基于UDP协议提供服务的协议。其service-address的格式为“VIP:PORT”,如“172.16.100.6:53”。
-f:承载的应用层协议为基于TCP或UDP协议提供服务的协议,但此类报文会经由iptables/netfilter打标记,即为防火墙标记。为什么打标记呢?是为了将多个端口标记为同一个服务。其service-address的格式为“FWM”,例如“10”。
-s scheduler:指明调度方法,默认为wlc。
[root ~]# ipvsadm -A -t 172.16.250.130:80 [root ~]# 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.250.130:80 wlc
删除:ipvsadm -D -t|u|f service-address,此时就不需要指明调度方法了。
[root ~]# ipvsadm -D -t 172.16.250.130:80 [root ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn
添加或修改:ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight]
-r server-address:指明RS,server-address格式一般为“IP[:PORT]”。注意,只支持端口映射的lvs类型中才应该定义此处端口。例如:-r 192.168.10.7:80
[-g|i|m]:指明lvs类型,默认为dr类型。
-g:gateway, 意为dr类型。
-i:ipip, 意为tun类型。
-m:masquerade, 意为nat类型。
[-w weight]:当前RS的权重。
仅对于支持加权调度的scheduler,也就是动态方法,权重才有意义。
[root ~]# ipvsadm -A -t 172.16.45.1:80 [root ~]# ipvsadm -a -t 172.16.45.1:80 -r 172.16.45.10:8080 -m -w 2 [root ~]# ipvsadm -a -t 172.16.45.1:80 -r 172.16.45.2 -m -w 3 [root ~]# 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.45.1:80 wlc -> 172.16.45.2:80 Masq 3 0 0 -> 172.16.45.10:8080 Masq 2 0 0
删除:ipvsadm -d -t|u|f service-address -r server-address
清空所有集群服务的定义:ipvsadm -C
ipvsadm -L|l [options]
-c:列出当前所有connection
--stats:列出统计数据
--rate:列出速率,每秒
-n|--numeric:数字格式显示IP及端口
--exact:精确值,不进行单位换算。
[root@localhost ~]# ipvsadm -ln --stats IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes -> RemoteAddress:Port TCP 172.16.45.10:80 12 36 0 2112 0 -> 172.16.45.1:8000 4 12 0 704 0 -> 172.16.45.2:80 8 24 0 1408 0 # Conns:连接数 # InPkts:入站请求报文 # OutPkts:出站响应 # InBytes:入站字节 # OutBytes:出站字节
[root@localhost ~]# ipvsadm -ln --rate IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port CPS InPPS OutPPS InBPS OutBPS # CPS:每秒连接数 # InPPS:每秒入站报文数 # InBPS:每秒入站字节数
清空计数器:ipvsadm -Z [-t|u|f service-address],清除以上的。
保存集群服务及RS的定义:
ipvsadm -S > /etc/sysconfig/ipvsadm
ipvsadm-save > /etc/sysconfig/ipvsadm
service ipvsadm save
恢复集群服务及RS的定义:
ipvsadm -R < /etc/sysconfig/ipvsadm
ipvsadm-restore < /etc/sysconfig/ipvsadm
service ipvsadm restart
仅主机是在虚拟机内部用软件虚拟了一台交换机,当有一台虚拟机网络也选择仅主机,就相当于此虚拟机接了根网线到交换机上。virtualbox在安装时,会在物理机上生成一个仅主机的网卡,此网卡可以和所有连接方式为仅主机的虚拟主机进行通信。
桥接是在虚拟机内部虚拟了一台交换机,物理机的物理网卡和所有虚拟机的网卡接口都接到此交换机上。这样一来,虚拟机就可以通过物理机的物理网卡同外部进行通信。
内部网络也是虚拟了一个虚拟交换机,都使用内部网络连接方式的虚拟机之间可以相互通信,但无法和物理机通信。
NAT网络也是虚拟了一个虚拟交换机,但是物理机上会有vmnet8的虚拟网卡,也就是说物理机可以通过此网卡,和其他使用NAT连接方式的虚拟机进行通信。不仅如此,NAT模型还会在虚拟机中虚拟一台NAT服务器。可以想象成一台拥有两个网卡的Linux主机,上面还添加了iptables的SNAT规则。NAT服务器的一个网卡连接vmnet8,另一个网卡连接物理机的物理网卡。如果虚拟机的网关指向vmnet8,那么虚拟机就能通过vmnet8转发到NAT服务器,经过地址转化后,从物理网卡和外部网络进行通信。SNAT规则是如何转化的呢?将请求报文的源地址改为物理网卡的地址。这样一来,虚拟主机可以访问外部主机,但外部主机无法访问内部的虚拟机,除非做DNAT。NAT比桥接更安全。
规划:三台虚拟机
director调度器:eth0为172.16.45.10,eth1为192.168.45.1
RS1:192.168.45.2:8000
RS2:192.168.45.3
物理机扮演客户端
DIP,RIP1,RIP2为网络连接为仅主机,VIP为桥接。
三台虚拟机的iptables没有规则,selinux未启用。
1、使用director测试两个RS的web服务
[root@localhost ~]# curl 192.168.45.2:8000 <h1>RS1</h1> [root@localhost ~]# curl 192.168.45.3 <h1>RS2</h1>
2、将两台RS的网关指向DIP,如果没指,RS是ping不同外网地址的。
[root@localhost ~]# route add default gw 192.168.45.1 # 临时生效
3、写LVS的nat规则
[root@localhost ~]# ipvsadm -A -t 172.16.45.10:80 -s rr [root@localhost ~]# ipvsadm -a -t 172.16.45.10:80 -r 192.168.45.2:8000 –m # 对于rr来说,权重没有作用 [root@localhost ~]# ipvsadm -a -t 172.16.45.10:80 -r 192.168.45.3 -m [root@localhost ~]# ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.16.45.10:80 rr -> 192.168.45.2:8000 Masq 1 0 0 -> 192.168.45.3:80 Masq 1 0 0
4、打开内核转发功能
[root@localhost ~]# echo 1 > /proc/sys/net/ipv4/ip_forward # 临时生效
5、使用ab测试
[root@localhost ~]# ab -c 1000 -n 10000 http://172.16.45.10/index.html [root@localhost ~]# ipvsadm -ln --stats IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes -> RemoteAddress:Port TCP 172.16.45.10:80 10537 63922 54927 5474067 6565384 -> 192.168.45.2:8000 5268 30558 28868 2861484 3760199 -> 192.168.45.3:80 5269 33364 26059 2612583 2805185
标签:linux lvs
原文地址:http://10042224.blog.51cto.com/10032224/1654783