腾讯云容器网络 vpc 对比 vxlan 性能测试

前言

在腾讯云基于VPC(虚拟私有网络)的CVM上使用k8s集群,有两种方式:

  • 使用腾讯云官方容器服务CCS
  • 自己搭建k8s集群

使用腾讯云官方容器服务CCS时, 会使用专有的VPC容器网络, 节点上会给容器分配一个跟VPC CIDR不重叠的容器网段(用户可配置),由CCS负责向VPC网络注册容器网段的路由,容器之间,容器跟节点之间,在用户看来都是直接路由的。

自己搭建k8s集群的话, 常用的容器网络方案是vxlan。

为了弄清楚这两种网络方案下, 容器网络的性能情况,笔者设计并执行了一个简单的对比测试, 对比了吞吐量和时延。

本文不介绍vxlan和vpc网络原理,只呈现一个可复现的详细测试流程,并附上典型测试结果。 只关心测试结果的话,直接看最后一节。

测试流程简介

通过腾讯云容器服务(CCS)创建一个两节点的集群。

通过CCS(或kubectl)创建两个POD, 分布在两个节点上。这两个POD使用的是VPC容器网络。后面简称这两个POD为VPC POD。

通过flannel给两个节点分配另一个虚拟网段,并创建vxlan设备。通过本地docker run命令在两个节点个运行一个docker container, 这两个docker container使用的是flannel管理的vxlan虚拟网络,后面简称这两个容器为vxlan容器

测试容器到容器(c2c)的网络性能对比

在两个VPC POD间运行qperf测试(走的是VPC容器网络), 在两个vxlan 容器之间运行qperf测试(走的是vxlan网络), 然后进行对比。

测试容器到其他节点(c2n)的网络性能对比

从节点二的VPC POD和vxlan容器分别访问节点一, 通过qperf测试性能对比。

关于测试流程的问题

如何屏蔽母机网络负载的影响?

测试使用的节点是CVM, 不可避免收到母机上其他CVM的影响。 为了尽量排除这一影响, 让两个网络下的qperf测试,在同样两台CVM节点上,先后进行(间隔在一分钟之内)。

为了排除两次测试收到母机网络负载的波动影响,每间隔半小时,重复执行一遍对比测试,测试多次。最后取平均值来对比。

为什么不分别创建一个CCS 集群和一个使用flannel网络插件的k8s集群来对比?

参考上一问题的答案。

第一步 申请一个包含两个节点的容器集群

首先创建一个VPC(虚拟私有网络)

https://console.cloud.tencent.com/vpc

CIDR选择 172.31.0.0/16

创建一个k8s集群

https://console.cloud.tencent.com/ccs/cluster

容器网络CIDR选择 10.0.0.0/14

节点配置选择1核CPU, 1G内存

操作系统选择Ubuntu 16.04 64位

等几分钟,两个节点的状态为“健康”以后,说明节点和集群都已经初始化完成了。

两个节点分配到的IP分别为(后面分别记为节点一和节点二):

  • 节点一 172.31.0.5
  • 节点二 172.31.0.16

检查集群的状态

查看节点的内网IP和状态

root@VM-0-5-ubuntu:~# kubectl get nodes
NAME          STATUS    AGE       VERSION
172.31.0.16   Ready     14d       v1.7.8-qcloud
172.31.0.5    Ready     12d       v1.7.8-qcloud

查看CCS(腾讯云容器服务)给每个节点分配的容器网段

# kubectl get node/172.31.0.5  -o jsonpath={.spec.podCIDR}
10.0.1.0/24

kubectl get node/172.31.0.16  -o jsonpath={.spec.podCIDR}
10.0.0.0/24

第二步 安装和配置flannel

在节点上下载flannel

wget https://github.com/coreos/flannel/releases/download/v0.9.1/flannel-v0.9.1-linux-amd64.tar.gz
tar -xzf flannel-v0.9.1-linux-amd64.tar.gz

搭建etcd集群

为了简单,只在节点172.31.0.5上安装和运行etcd:

apt install etcd
systemctl start etcd

这样两个节点上都可以通过 http://172.31.0.5:4001 来访问这个只有一个实例的etcd集群

往etcd配置flannel网络

etcdctl --endpoint http://172.31.0.5:4001 set /flannel/net/config '{"NetWork":"192.168.0.0/16","SubnetLen": 24, "Backend": {"Type": "vxlan"}}'

在两个节点上启动flanneld

./flanneld -etcd-endpoints=http://172.31.0.5:4001 -etcd-prefix=/flannel/net -iface=eth0 &

查看etcd数据可以看到两个节点上的flanneld各自分配到的网段:

# etcdctl --endpoint http://172.31.0.5:4001 ls /flannel/net/subnets          
/flannel/net/subnets/192.168.24.0-24
/flannel/net/subnets/192.168.81.0-24

# etcdctl --endpoint http://172.31.0.5:4001 get /flannel/net/subnets/192.168.24.0-24
{"PublicIP":"172.31.0.5","BackendType":"vxlan","BackendData":{"VtepMAC":"6a:7d:68:63:b4:d1"}}

# etcdctl --endpoint http://172.31.0.5:4001 get /flannel/net/subnets/192.168.81.0-24
{"PublicIP":"172.31.0.16","BackendType":"vxlan","BackendData":{"VtepMAC":"7e:f8:6a:92:eb:a8"}}

flanneld还会在本地生成一个文件/run/flannel/subnet.env。例如在节点172.31.0.5上:

# cat /run/flannel/subnet.env
FLANNEL_NETWORK=192.168.0.0/16
FLANNEL_SUBNET=192.168.24.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=false

修改dockerd启动参数

停止dockerd

systemctl stop dockerd

修改/usr/lib/systemd/system/dockerd.service, 如下所示,增加"EnvironmentFile=-/run/flannel/subnet.env", 并修改ExecStart定义

EnvironmentFile=-/run/flannel/subnet.env
ExecStart=/usr/bin/dockerd ${LOG_LEVEL} --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} ${STORAGE_DRIVER} ${REGISTRY_MIRROR}

重新启动dockerd

systemctl start dockerd

第三步 运行两个使用VPC容器网络的POD

通过kubectl create -f命令创建一个deployment。 所用yaml文件内容如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    qcloud-app: nginx
  name: nginx
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      qcloud-app: nginx
  template:
    metadata:
      labels:
        qcloud-app: nginx
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "qcloud-app"
                    operator: In
                    values: 
                    - nginx
              topologyKey: "kubernetes.io/hostname"
      containers:
      - image: nginx:alpine
        imagePullPolicy: Always
        name: nginx
      imagePullSecrets:
      - name: qcloudregistrykey
      restartPolicy: Always

这个yaml文件中通过podAntiAffinity来确保两个POD被调度到两个不同的节点。

(这一步也可以通过控制台来完成: https://console.cloud.tencent.com/ccs/service)

然后检查pod状态

# kubectl get pod -o wide
NAME                     READY     STATUS    RESTARTS   AGE       IP          NODE
nginx-2438677318-d9jv7   1/1       Running   0          3m        10.0.1.10   172.31.0.5
nginx-2438677318-jc4b1   1/1       Running   0          3m        10.0.0.26   172.31.0.16

可以看到,两个POD分布在两个节点, IP分别为10.0.1.10 和 10.0.1.26, 属于之前配置的VPC容器网络10.0.0.0/14。

第四步 运行两个使用flannel网络的容器(后面简称flannel容器)

docker run -d nginx:alpine

第五步 获取四个POD/容器的pid和IP

获取POD和vxlan容器的IP。 以节点一上的VPC POD为例:

# kubectl get pod/nginx-2438677318-d9jv7 -o jsonpath={.status.containerStatuses[0].containerID}
docker://a1173da42e8b395a1b72e9ffe9dad43a135826e32dedc9202acc717d63b21967

# docker inspect --format '{{.State.Pid}}' a1173da42e8b395a1
17694

最终两个VPC POD和vxlan容器的IP, pid如下表所示:

节点

POD

容器

容器IP

pid

172.31.0.5

nginx-2438677318-d9jv7

a1173da42e8b

10.0.1.11

17694

172.31.0.5

---

8b610711dc45

192.168.24.2

28611

172.31.0.16

nginx-2438677318-jc4b1

461b98c72697

10.0.1.30

6512

172.31.0.16

---

5a56b09429b

192.168.81.2

18172

第六步 运行qperf测试

安装qperf

ubuntu下安装qperf:

wget https://www.openfabrics.org/downloads/qperf/qperf-0.4.9.tar.gz
tar -xzvf qperf-0.4.9.tar.gz
cd qperf-0.4.9
/config
make

centos下直接yum install qperf 即可

在节点一上启动三个qperf server

在host, VPC POD, vxlan容器三个不同的网络namespace中启动qperf server。

1) host网络

qperf &

2) VPC POD

# 其中17694是节点一上VPC POD的pid
nsenter -t 17694 -n qperf &

3) vxlan容器

# 其中28611是节点一上vxlan容器的pid
nsenter -t 28611 -n qperf &

测试两个VPC POD之间的网络性能

在172.31.0.16上,运行

# 其中10.0.1.11是远端POD的IP
nsenter -t 6512 -n qperf 10.0.1.11 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vpc-c2c.raw

测试两个vxlan容器之间的网络性能

在172.31.0.16上,运行

# 其中192.168.24.2是远端vxlan容器的IP
nsenter -t 18172 -n qperf 192.168.24.2 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vxlan-c2c.raw

测试VPC POD访问另一个节点

在172.31.0.16上,运行

nsenter -t 6512 -n qperf 172.31.0.5 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vpc-c2n.raw

测试vxlan容器访问另一个节点

在172.31.0.16上,运行

nsenter -t 18172 -n qperf 172.31.0.5 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vxlan-c2n.raw

测试节点二访问节点一

qperf 172.31.0.5 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > n2n.raw

处理原始数据生成对比图表

下载qperf-plot工具: https://github.com/honkiko/qperf-plot

把原始qperf报告转换为plot数据文件

cat vxlan-c2c.raw | ./qperf-parse.py > vxlan-c2c
cat vpc-c2c.raw | ./qperf-parse.py > vpc-c2c
cat vxlan-c2n.raw | ./qperf-parse.py > vxlan-c2n
cat vpc-c2n.raw | ./qperf-parse.py > vpc-c2n
cat n2n.raw | ./qperf-parse.py > n2n

生成对比图表

gnuplot -c qperf-plot.plt vpc-c2c vxlan-c2c

会在当前目录生成bw-[vpc-c2c]-vs-[vxlan-c2c].png和lat-[vpc-c2c]-vs-[vxlan-c2c].png

gnuplot -c qperf-plot.plt vpc-c2n vxlan-c2n

会在当前目录生成bw-[vpc-c2n]-vs-[vxlan-c2n].png和lat-[vpc-c2n]-vs-[vxlan-c2n].png

测试环境和结果

节点配置: 腾讯云北京一区 标准型S1 1核1G

节点操作系统: Ubuntu 16.04.1 LTS

节点内核版本: 4.10.0-32-generic

qperf版本: qperf 0.4.9

flannel版本: v0.9.1

容器到容器(c2c)

以上5个qperf测试(vpc-c2c, vxlan-c2c, vpc-c2n, vxlan-c2n, n2n),重复5轮, 每轮之间间隔两分钟。5轮测试结果取平均值。结果如下。

容器到容器的对比

加入节点到节点(n2n)的曲线(图中紫色曲线)作为参照

容器到其他节点的对比

加入节点到节点(n2n)的曲线(图中紫色曲线)作为参照

CPU占用率的对比

吞吐率方面,VPC容器网络要比vxlan高40%, 是不是消耗了特别多的CPU资源换来的呢。为此笔者专门做了一个对比测试。

两种网络模式下,使用固定msg_size=1440, 执行qperf tcp_bw测试, 时长60秒, 同时通过mpstat每秒采集一次CPU利用率指标。 重复执行10轮测试,取平均值。结果如下:

同样的msg_size, 吞吐率大40%, 也意味着同样时间的发包数量多40%, 从而send系统调用次数也多40%。 因此mpstat统计出来的VPC容器网络下sys要高。 vxlan的封包解包是在软中断中执行的,所以即使多发送了40%的报文, VPC容器网络模式下, mpstat统计出来的softirq CPU占用反而还比vxlan要低。

进行吞吐率测试时, usr和sys这两个CPU消耗,肯定是随着每秒发包数量(pps, PacketPerSecond)增加而增加的。但是softirq的消耗对比, 则体现出了vxlan模式下额外的封包解包带来的额外CPU开销。

结论

容器到容器,VPC容器网络是直接路由,无论是吞吐率还是时延,都很接近节点到节点通信的性能;

而vxlan需要多一层隧道封装,因此带来了很大的开销。

吞吐率方面,VPC容器网络要比vxlan高40%,时延要小5%~10%。

容器到其他节点, VPC容器网络仍然是直接路由,而vxlan容器则是通过iptables规则实现的NAT来完成通信,因此性能损耗不算大。但是不得不面对NAT带来的各种复杂性。

因此,想要在腾讯云上使用k8s, 建议还是选择官方CCS。官方CCS由专业团队来提供保障和服务,在网络性能上也有巨大的优势。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏乐享123

从MongoDB迁移到TokuMx

1778
来自专栏Android 开发者

[译] 如何用 Android vitals 解决应用程序的质量问题

对于一个应用开发者来说,没有比开心的用户更好的衡量成功的标准,而且最好是有很多这样的用户。实现这一目标的最佳方式是拥有一个人人都想用的优秀应用,不过我们所说的“...

1021
来自专栏散尽浮华

云计算和虚拟机基础梳理

云计算介绍 云计算是一种按使用量付费的模式,这种模式提供可用的、便捷的、按需的网络访问,进入可配置的计算资源共享池,(资源包括网络、服务器、存储、应用软件、服务...

2576
来自专栏Albert陈凯

Spark运行机制与原理详解目录Spark Internals

https://github.com/JerryLead/SparkInternals Spark Internals Spark Version: 1.0.2...

4326
来自专栏大魏分享(微信公众号:david-share)

Java系微服务,谁主沉浮?| 通过MicroProfile实施微服务 | 微服务系列第七篇

首先,Spring Boot其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配...

813
来自专栏CDN及云技术分享

我是怎么一步步用go找出压测性能瓶颈

笔者要在线上服务器load日志并且重放来测一些机器性能指标。模拟机器资源比较少,相对的被模拟的线上机器日志量大,假设线上单机qps有1w,那么5台机器组成的集群...

1.6K35
来自专栏云计算D1net

为什么Docker会受欢迎?看完这些才恍然大悟

Docker不是唯一的容器平台,也不是第一个推出的。其他框架,如OpenVZ和LXC,从20世纪20年代中期诞生。而其他类似容器的技术,如FreeBSD更进一步...

3196
来自专栏瓜大三哥

Sdram控制器(三)

1836
来自专栏技术翻译

用于在所有级别上构建微服务的29个顶级工具

关于微服务有很多很棒的文章。对于那些一直没有接受微服务的人,或者新手,本文是为了提供顶级开源工具的整合。微服务架构,或仅微服务,是用于开发软件系统的高度可扩展的...

772
来自专栏技术翻译

推荐|50+有用的Kubernetes工具

在短短两年的时间里,Kubernetes在集装箱管道战场上给其竞争对手带来了浪费。令人遗憾的是,Docker Swarm自2016年以来并未成为主要的竞争者,并...

280

扫码关注云+社区