引言

Kubernetes要求集群中的每一个pod都具备惟一的,可路由的IP,Kubernetes自己不会分配IP,而是将任务留给第三方解决方案。node

本次课题的目标是找到具备最低延迟,最高吞吐量和最低安装成本的解决方案。 因为个人负载对延迟敏感,所以个人目的是在相对较高的网络利用率下测量较高的百分比延迟,特别是最大负载的30%到50%之间的性能,由于我认为这是最能表明非过载系统的最多见用例。git

竞争对手们

Docker with --net=host

这是咱们的一个参考设置,全部其余竞争对手都会与此设置进行比较。--net=host选项表示容器继承其主机的IP,即不涉及容器网络。github

根据先验原则,没有任何容器网络方案比其余的会有更好的表现,这就是为何使用此设置做为参考的缘由。docker

Flannel

Flannel是一个虚拟网络解决方案,由CoreOS维护,它是通过充分验证可当即投入生产的解决方案,所以安装成本最低。将带有Flannel的worker节点添加到k8s群集时,Flannel会作三件事:后端

使用etcd为新worker节点分配一个子网

在机器上建立虚拟网桥接口(称为docker0网桥)

设置数据包转发后端:

aws-vpc

在Amazon AWS实例表中注册机器子网,此表的记录数限制为50,即若是将Flannel布与aws-vpc一块儿使 用,则集群的节点数量不能超过50,此外,此后端仅适用于Amazon的AWS。

host-gw

经过远程主机IP建立到子网的IP路由。 须要运行Flannel的主机之间2层直连。

vxlan

建立一个虚拟VXLAN接口

因为Flannel使用网桥接口转发数据包,所以流量从一个容器到另外一个容器的过程当中,每一个数据包都会通过两个网络栈。服务器

IPvlan

IPvlan是Linux内核中的驱动程序,可以建立具备惟一IP的虚拟接口,而没必要使用网桥接口。网络

要将IP分配给具备IPvlan的容器,你必须:tcp

建立一个彻底没有网络接口的容器

在默认网络名称空间中建立ipvlan接口

将此接口移动到容器的网络命名空间中

IPvlan是一个相对较新的解决方案,所以没有现成的工具能够自动执行此过程。 这使得很难在许多服务器和容器中部署IPvlan,即部署成本很高。

可是,IPvlan不须要桥接接口,而是直接将数据包从NIC转发到虚拟接口,所以指望它的性能优于Flannel。工具

负载测试方案

对于每一个竞争对手,执行如下步骤:性能

在两台物理机上设置网络

在一台机器上的容器中运行tcpkali,让其以恒定速率发送请求

在另外一台计算机上的容器中运行Nginx,让它以固定大小的文件响应

捕获系统指标和tcpkali结果

咱们以每秒50,000至450,000个请求(RPS)的请求速率运行基准。

在每次请求时,Nginx都会响应一个固定大小的静态文件:350 B(内容为100 B,标题为250 B)或4 KB。

测试结果

结果显示IPvlan有着最低的延迟和最高的最大吞吐量,host-gw和aws-vpc的Flannel紧随其后,可是host-gw在最大负载下显示的结果更好。

使用vxlan的Flannel在全部测试中均显示最差的结果,可是,我怀疑99.999%ile测试结果的异常是由一个bug引发的。

4 KB响应的结果相似于350 B响应的结果,但有两个明显的区别:最大的RPS要低得多,由于在4 KB响应下仅需约270kRPS便可彻底加载10 Gbps NIC。

吞吐量测试中IPvlan无限接近--net=host。

咱们当前的选择是使用host-gw模式的Flannel,它没有太多的依赖关系(例如,不须要AWS或新的Linux版本),与IPvlan相比,它易于部署,而且具备足够的性能特性,IPvlan是备选方案,若是某个时候Flannel添加了IPvlan支持,咱们将会切换到它。

尽管aws-vpc的性能比host-gw稍好,但其50台计算机节点的局限性以及将其硬连线到Amazon的AWS的事实对咱们来讲都是一个障碍。

50,000 RPS, 350 B

1460000039980004

在每秒50,000个的请求速度下,全部候选者都表现出使人满意的性能,主要趋势是:IPVlan表现最佳,host-gw和aws-vpc紧随其后,vxlan表现最差。

150,000 RPS, 350 B

1460000039980005

1460000039980006

IPvlan略优于host-gw和aws-vpc,可是在99.99 %ile这个指标上是最差的,host-gw的性能略优于aws-vpc。

250,000 RPS, 350 B

1460000039980007

这种负载在生产中也很常见,所以这些结果尤其重要。

1460000039980008

IPvlan再次显示出最佳性能,可是在99.99和99.999 %ile这两个指标上aws-vpc更胜一筹,host-gw在95和99% %ile上优于aws-vpc。

350,000 RPS, 350 B

1460000039980009

在大多数状况下,延迟接近250,000 RPS(350 B状况),但在99.5 %ile以后迅速增加,这意味着咱们已经接近最大RPS。

450,000 RPS, 350 B

这是理论上能产生合理结果的最大RPS,IPvlan再次领先,延迟比--net-host差30%左右:

1460000039980010

1460000039980011

有趣的是,host-gw的性能比aws-vpc更好:

1460000039980012

500,000 RPS, 350 B

在500,000 RPS下,只有IPvlan仍然有效,表现甚至优于--net=host,可是延迟是如此之高,以致于咱们认为这对延迟敏感的程序毫无用处。

1460000039980013

50k RPS, 4 KB

1460000039980014

较大的响应会形成较高的网络使用率,但测试结果看起来与较小的响应几乎相同:1460000039980015

150k RPS, 4 KB

1460000039980016

Host-gw具备使人惊讶的99.999%ile,对于较低的百分位数也显示出良好的结果。

1460000039980017

250k RPS, 4 KB

1460000039980018

这是在大的请求响应下的最大RPS,与小的请求响应测试用例不一样,aws-vpc的性能比host-gw好得多,Vxlan再次从图中排除。

测试环境

背景

为了理解本文并重现咱们的测试环境,你应该熟悉有关高性能的基础知识。

这些文章提供了有关该主题的有用看法:

如何每秒接收一百万个数据包 by CloudFlare

扩展Linux网络堆栈 from the Linux kernel documentation

服务器规格清单

须要2台Amazon AWS EC2实例,系统版本为CentOS 7,实例规格为c4.8xlarge,两个实例均开启了加强联网功能。

每一个实例都有2个处理器的NUMA,每一个处理器有9个核心,每一个核心有2个超线程,这实际上容许在每一个实例上运行36个线程。

每一个实例都有一个10Gbps网络接口卡(NIC)和60 GB内存。

为了支持加强联网功能和IPvlan,已经安装了带有Intel ixgbevf驱动程序的Linux内核4.3.0版本。

安装部署

现代NIC经过多个中断请求(IRQ)线提供接收方扩展(RSS),EC2在虚拟化环境中仅提供两条中断线,所以咱们测试了几种RSS和接收数据包导向(RPS)接收数据包导向(RPS)配置,最终获得如下配置,部分由Linux内核文档提供:

IRQ

两个NUMA节点中的每一个节点上的第一个核都配置为接收来自NIC的中断。

使用lscpu将CPU与NUMA节点匹配:$ lscpu | grep NUMA

NUMA node(s): 2

NUMA node0 CPU(s): 0-8,18-26

NUMA node1 CPU(s): 9-17,27-35

这是经过将0和9写入/proc/irq//smp_affinity_list来实现的,其中IRQ编号是经过grep eth0 /proc/interrupts得到的:$ echo 0 > /proc/irq/265/smp_affinity_list

$ echo 9 > /proc/irq/266/smp_affinity_list

RPS

已测试了RPS的几种组合,为了提升延迟,咱们仅使用CPU 1–8和10–17减轻了IRQ处理处理器的负担。与IRQ的smp_affinity不一样,rps_cpus sysfs文件条目没有_list对应项,所以咱们使用位掩码列出RPS能够将流量转发到的CPU:$ echo "00000000,0003fdfe" > /sys/class/net/eth0/queues/rx-0/rps_cpus

$ echo "00000000,0003fdfe" > /sys/class/net/eth0/queues/rx-1/rps_cpus

Transmit Packet Steering (XPS)

将全部NUMA 0处理器(包括HyperThreading,即CPU 0-八、18-26)设置为tx-0,将NUMA 1(CPU 9-1七、27-37)设置为tx-12:$ echo "00000000,07fc01ff" > /sys/class/net/eth0/queues/tx-0/xps_cpus

$ echo "0000000f,f803fe00" > /sys/class/net/eth0/queues/tx-1/xps_cpus

Receive Flow Steering (RFS)

咱们计划使用60k常驻链接,官方文档建议将其四舍五入为最接近的2的幂:$ echo 65536 > /proc/sys/net/core/rps_sock_flow_entries

$ echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

$ echo 32768 > /sys/class/net/eth0/queues/rx-1/rps_flow_cnt

Nginx

Nginx使用18个worker,每一个worker都有本身的CPU(0-17),经过worker_cpu_affinity选项设置:**workers** 18;

**worker_cpu_affinity** 1 10 100 1000 10000 ...;

Tcpkali没有内置的CPU亲和性支持,为了利用RFS,咱们在任务集中运行tcpkali并调整调度程序,防止线程迁移的发生:$ echo 10000000 > /proc/sys/kernel/sched_migration_cost_ns

$ taskset -ac 0-17 tcpkali --threads 18 ...

与咱们尝试过的其余设置相比,此设置可以更均匀地在CPU内核之间分配中断负载,并以相同的延迟实现更好的吞吐量。

CPU 0和9专门处理NIC中断,不处理数据包,但它们还是最繁忙的:

1460000039980019

RedHat的调整也与网络延迟配置文件一块儿使用,为了最大程度地减小nf_conntrack的影响,添加了NOTRACK规则,内核参数已调整为支持大量tcp链接:fs.file-max = 1024000

net.ipv4.ip_local_port_range = "2000 65535"

net.ipv4.tcp_max_tw_buckets = 2000000

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_fin_timeout = 10

net.ipv4.tcp_slow_start_after_idle = 0

net.ipv4.tcp_low_latency = 1

脚注

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐