浅析kube-proxy中的IPVS模式

作者:马楠

1 本文背景

笔者在学习kubernetes的kube-proxy的时候,kube-proxy具有三种proxy mode:

  • userspace
  • iptables
  • ipvs

在Kubernetes v1.8.0-beta.0后引入的ipvs mode, 官方文档宣称其有更好的性能和更多的选项。但ipvs是什么呢,笔者作为网络方面的小白,这里并不打算恶补所有的网络知识,但ipvs不研究一下,后面也无法继续下去,所以本文是我学习ipvs的一个总结,可能类似的文章已经很多,能符合大家的期望最好,不到之处,也望各位看官一笑而过。

那什么是IPVS呢, IPVS(IP Virtual Server)是构建于Netfilter之上,作为Linux内核的一部分提供传输层负载均衡的模块。

提IPVS就不得不提LVS,IPVS模块是LVS集群的核心软件模块,它安装在LVS集群作为负载均衡的主节点上,虚拟出一个IP地址和端口对外提供服务, 把基于TCP或UDP的请求重定向到后面的真实的工作服务器。下文会对LVS, IPVS做比较详细的展开。

2 LVS是什么

LVS的英文全称是Linux Virtual Server,即Linux虚拟服务器, 该项目致力于为Linux构建一个高性能、高可用的集群服务。现在主要被用做IPVS(advanced IP load balancing software)。它是我们国家的章文嵩博士的一个开源项目。在linux内存2.6中,它已经成为内核的一部分,在此之前的内核版本则需要重新编译内核。 LVS一般用于实现四层的负载均衡集群。

3 什么是四层负载均衡

这里的“四层”指的是OSI七层模型中的第四层——传输层。 先看一下图吧:

img

如上图,一个数据从A节点传送到B节点,在A节点上的数据经过从第七层到第一层的层层封装,通过物理链路到达B节点后,再经过从第一层到第七层的层层解封后,最终为进程所用。

那么到底什么是四层负载均衡呢,上图只能解释OSI七层的工作模式,甚至连其中的网络层做什么都没有展现出来,再来看一下下图:

img

OSI模型是一个高阶模型,它指导着计算机节点间通讯所需遵循的基本原则,而在其具体实现——TCP/IP模型上,TCP/IP四层模型与之相对应,可以看到,工作在第四层的协议是TCP/UDP协议,也就是说四层负载均衡,是主要作用于TCP协议报文之上,基于IP+端口来判断需要重定向的报文,并修改报文中目标IP地址以进行重定向的负载均衡方式。

从第一张图可知,第四层的报文是看不到真正的数据内容的,所以此种负载不会考虑消息能容,例如无法根据不同的URL地址重定向到特定主机,相对的,其效率较高。

4 LVS相关术语

  • DS:Director Server。指的是前端负载均衡器节点。
  • RS:Real Server。后端真实的工作服务器。
  • VIP:向外部直接面向用户请求,作为用户请求的目标的IP地址。
  • DIP:Director Server IP,主要用于和内部主机通讯的IP地址。
  • RIP:Real Server IP,后端服务器的IP地址。
  • CIP:Client IP,访问客户端的IP地址。

5 LVS的三种工作模式

  • VS/NAT模式
  • VS/DR模式
  • VS/TUN模式

6 LVS的工作原理

6.1 VS/NAT模式的工作原理

6.1.1 原理简介

NAT(Network Address Translation)即网络地址转换,其作用是通过数据报头的修改,使得位于企业内部的私有IP地址可以访问外网,以及外部用用户可以访问位于公司内部的私有IP主机。 VS/NAT模式的工作原理是多目标DNAT,通过Director修改请求报文中的目标地址和端口为LVS挑选出来的某RS的RIP和PORT实现转发。

img

6.1.2 工作过程详解

img

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

6.1.3 特点

  • RIP和DIP必须在同一网络,且应该使用私网地址,RS的网关必须指向DIP
  • 支持端口映射
  • 请求报文和响应报文都经过Director转发,较高负载下,Director易成为系统性能瓶颈
  • RS可以使用任意操作系统

6.2 VS/DR模式的工作原理

6.2.1 原理简介

DR模式也叫直接路由模式,该模式中LVS依然仅承担数据的入站请求以及根据算法选出合理的真实服务器,最终由后端真实服务器负责将响应数据包发送返回给客户端。 此模式中Director为请求报文重新封装一个MAC首部进行转发,源MAC地址是DIP所在接口的MAC,目标MAC是挑选出来的的某RS的RIP接口所在的MAC,IP首部不会发生变化(CIP/VIP)

img

6.2.2 工作过程详解

img

(a). 客户请求在前端路由器发送ARP广播来获取Director的VIP所在网卡的MAC地址,获知后,在请求报文上封装MAC首部(源MAC是路由器接口的MAC,目标MAC是Director上VIP接口的MAC),保证将报文发送至Director (b). 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP,PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链 ©. IPVS比对数据包请求的服务是否为集群服务,若是,将请求报文(源地址CIP/目标地址VIP)再次封装一个MAC首部(源MAC是DIP的MAC/目标MAC是RIP的MAC),然后将数据包发至POSTROUTING链。 此时的源IP和目的IP均未修改,仅修改了源MAC地址为DIP的MAC地址,目标MAC地址为RIP的MAC地址 (d). 由于DS和RS在同一个网络中,所以是通过二层来传输。POSTROUTING链检查目标MAC地址为RIP的MAC地址,那么此时数据包将会发至Real Server (e). RS发现请求报文的MAC地址是自己的MAC地址,就接收此报文,拆了MAC首部,发现目标地址是VIP,于是继续向lo:0转发,最终到达用户空间的进程给予响应,开始构建响应报文,处理完成之后,将响应报文通过lo:0接口传送给eth0网卡然后向外发出。 此时的源IP地址为VIP,目标IP为CIP。此时可能需要另外一个路由器,如图vs/dr.png所示,RIP的网关指向此路由,向外转发 (f). 响应报文最终送达至客户端

6.2.3 VS/DR要点

  • 每个RS主机上都应有VIP,并且RIP配置在物理接口上,VIP配置在内置接口lo的别名上(lo:0),来自Director的请求报文进来时,经由RIP再到lo:0再到用户空间的进程,回去时控制响应报文先经过lo:0(此时源IP已封装成VIP)再由RIP离开,保证客户端接收到的报文源IP是VIP,目标IP是CIP
  • 让RS主机禁止响应ARP广播级别和通告级别
    • 响应级别(arpingore)设定目的:当客户端请求过来时,让Director上的VIP响应,而不是让RS上的VIP响应,保证请求报文一定走Director
    • 通告级别(arpannounce)设定目的:当Director向RS转发时,经由的是RIP的接口,由于RS和Director都有VIP,会造成地址冲突,通过设定ARP通告级别可让其总是避免向非本网络通告(经由的是RIP接口,不会向非RIP接口的网络通告),因此解决了地址冲突问题

有关arpingore和arpannounce的具体介绍可以参见 《Linux内核参数之arpignore和arpannounce》

6.2.4 特点

  • RS的RIP可以使用私网地址,也可以使用公网地址,如果使用公网地址,此时可以通过互联网对RIP进行直接访问
  • RS跟Director必须在同一物理网络(一旦隔开,MAC会变);RS的网关必须不能指向DIP
  • 不支持端口映射
  • 请求报文必须由Director调度,但响应报文必须不能经由Director
  • 缺陷:RS和DS必须在同一机房中

6.3 VS/TUN模式的工作原理

VS/TUN模式貌似并不是一个主要的负载均衡应用模式,笔者作为非网络专家,这里只罗列简单的调查内容,供用时参考。但是,前面两种模式VS/DR以及VS/NAT是应该掌握的基础知识。

6.3.1 原理简介

不修改请求报文的IP首部(源地址是CIP,目标地址是VIP),而是在原IP首部之外再封装一个IP首部(原地址是DIP,目标地址是挑选出来的RS的RIP)进行转发。

img

6.3.2 工作过程详解

img

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

6.3.3 特点

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

7 负载均衡调度算法

7.1 静态方法

仅依据算法本身进行轮询调度

  • RR: Round Robin,轮调, 一个接一个,自上而下
  • WRR: Weighted RR,加权论调, 加权,手动让能者多劳。
  • SH: SourceIP Hash,来自同一个IP地址的请求都将调度到同一个RealServer
  • DH: Destination Hash,不管IP,请求特定的东西,都定义到同一个RS上

7.2 动态方法

根据算法及RS的当前负载状态进行调度

  • LC: least connections(最小链接数) 链接最少,也就是Overhead最小就调度给谁。 假如都一样,就根据配置的RS自上而下调度。 overhead=active*256+inactiveconns
  • WLC: Weighted Least Connection (加权最小连接数) 这个是LVS的默认算法。 overhead=(activeconns*256+inactiveconns)/weight
  • SED: Shortest Expection Delay(最小期望延迟) WLC算法的改进。 overhead=(activeconns+1)*256/weight
  • NQ: Never Queue SED算法的改进。第一次均匀分配,后续SED
  • LBLC: Locality-Based Least-Connection,基于局部的的LC算法 正向代理缓存机制。访问缓存服务器,调高缓存的命中率。 和传统DH算法比较,考虑缓存服务器负载。可以看做是DH+LC 如果有两个缓存服务器
  • 只要调度到其中的一个缓存服务器,那缓存服务器内就会记录下来。下一次访问同一个资源的时候也就是这个服务器了。 (DH)
  • 有一个用户从来没有访问过这两个缓存服务器,那就分配到负载较小的服务器。LC
  • LBLCR: Locality-Based Least-Connection with Replication(带复制的lblc算法) 缓存服务器中的缓存可以互相复制。 因为即使没有,也能立即从另外一个服务器内复制一份,并且均衡负载

8 LVS软件组件

  • ipvsadm:用户空间的命令行工具,规则管理器,用于管理集群服务及RealServer
  • ipvs:工作于内核空间netfilter的INPUT钩子上的框架
    • 支持的协议: tcp udp ah_esp esp ah sctp

9 ipvsadm使用帮助

ipvsadm 用法同iptables
  管理集群服务 
    ipvsadm -A|E -t|u|f service-address [-s scheduler]  E 修改
    ipvsadm -D -t|u|f service-address
      service-address
        tcp: -t ip:port
        udp: -u ip:port
        fwm: -f mark    
      -s scheduler
  管理集群服务中的RS
    ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight]
    ipvsadm -d -t|u|f service-address -r server-address
      server-address
        ip:port
      lvs-type    要注意使用 什么模型
        -g gateway dr
        -i ipip tun
        -m masquerade,nat   
  清空和查看
    ipvsadm -C
    ipvsadm -L|l [options]
      -n numberic 基于数字格式显示地址和端口
      -c connetcion 显示ipvs连接
      --rate 速率
      --stats 统计数据
      --exact 精确值
  保存和重载
    ipvsadm -R
    ipvsadm -S [n]
  置零计数器
    ipvsadm -Z [-t|u|f service-address]

10 看懂ipvs规则

例:

Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
UDP  master.mike.com:domain rr
  -> 10.244.0.6:domain            Masq    1      0          0         
  -> 10.244.0.7:domain            Masq    1      0          0

对于UDP协议,有一个集群服务master.mike.com:domain,它有两个RS,分别为10.244.0.6和10.244.0.7, LVS是以轮询的方式把请求分配给这两台RS, 两台RS的工作模式是Masq,即VS/NAT

11 为什么要在Kubernetes中使用IPVS

随着Kubernetes使用率的增长,其资源的可扩展性变得越来越重要。特别是服务的可扩展性对于开发者和那些有高负载的公司对Kubernetes的接纳程度来说是非常重要的。

Kube-proxy作为服务路由(Service routing)的构建块一直依赖于久经沙场的iptables来实现对核心服务类型(ClusterIP和NodePort)的支持。但是,iptables在对10000以上的Service的扩展性支持上显得非常的挣扎,因为iptables本身是为防火墙而设计的,并基于内部的(in-kernel)规则列表。

在Kubernetes 1.6的时候, 它已经可以支持5000个节点,导致这个数量的实际瓶颈就是kube-proxy中的iptables。举例来说,在一个5000节点的集群中全部使用NodePort类型的的service,如果我们创建2000个services,每个service对应10个pods,这将使每个节点上生成至少20000条记录,从而导致内核相当繁忙。

相对来说,使用基于IPVS的集群服务负载均衡就对这种情景游刃有余的多了。IPVS是专门为负载均衡而设计的,并使用了更高效的数据结构(hash tables),从而在底层几乎具有无限的可扩展性。

12 Kubernetes中IPVS Service网络拓扑

当创建一个ClusterIP类型的Service时, IPVS proixer做了以下三件事:

  • 确保节点上存在虚拟接口,默认为kube-ipvs0

    [root@master ~]# ip addr
    ...
    8: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default 
    link/ether 4a:4e:8d:52:b0:3b brd ff:ff:ff:ff:ff:ff
    ...
    
  • 把Service IP绑定到虚拟接口上

    [root@master ~]# kubectl describe svc kubernetes
    Name:              kubernetes
    Namespace:         default
    Labels:            component=apiserver
                   provider=kubernetes
    Annotations:       <none>
    Selector:          <none>
    Type:              ClusterIP
    IP:                10.96.0.1
    Port:              https  443/TCP
    TargetPort:        6443/TCP
    Endpoints:         192.168.56.101:6443
    Session Affinity:  None
    Events:            <none>
    
    [root@master ~]# ip addr
    ...
    8: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default 
    link/ether 4a:4e:8d:52:b0:3b brd ff:ff:ff:ff:ff:ff
    inet 10.96.0.1/32 brd 10.96.0.1 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    ...
    
  • 为每个Service IP单独创建IPVS virtual servers

    [root@master ~]# ipvsadm -ln
    IP Virtual Server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
    -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
    ...
    TCP  10.96.0.1:443 rr
    -> 192.168.56.101:6443          Masq    1      4          0         
    ...
    

注意这里Kubernetes Service与IPVS virtual server的比例是1:N的关系。考虑一个kubernetes Service有多个IP的场景,比如,一个External IP类型的Service就含有两个IP —— Cluster IP 和 External IP,这时候IPVS proxier就会创建2个IPVS virtual servers——一个给Cluster IP,另一个给External IP。

13 参考资料

本文大量图文摘自以下文章,另附加作者自我总结,特此声明

  • LVS负载均衡(LVS简介、三种工作模式、十种调度算法)
  • linux负载均衡总结性说明(四层负载/七层负载)
  • 超详细!使用 LVS 实现负载均衡原理及安装配置详解
  • LVS原理介绍
  • LVS
  • IPVS-Based In-Cluster Load Balancing Deep Dive

14 作者介绍

马楠,曾就职于日资公司NTT DATA Beijing, 国企中体彩科技发展有限公司,现Oracle系统架构和性能服务团队成员。职场中扮演过多种角色,不会运维的程序员不是好的架构师。

本文分享自微信公众号 - 云服务与SRE架构师社区(ai-cloud-ops)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

TCP/IP负载均衡负载均衡缓存缓存

这些信息有用吗?
Do you have any suggestions for improvement?

Thanks for your feedback!