原文来自:
https://blog.fleeto.us/post/kubernetes-storage-performance-comparison/
本文展示了一个简单的存储对比,使用未经性能优化的多种存储提供的存储卷进行测试和比较。
忽略 Azure 的原生 PVC 或 hostPath
,我们可以得出如下测试结果:
如果你正在运行 Kubernetes,你可能正在使用,或者准备使用动态供给的块存卷 ,而首当其冲的问题就是为集群选择合适的存储技术。这个事情并不能用一个简单的测试来做出简单的回答,告诉你目前市面上最好的技术是什么。存储技术的选择过程中,集群上运行的负载类型是一个重要的输入。对于裸金属集群来说,需要根据实际用例进行选择,并集成到自己的硬件之中。公有云中的托管 K8s,例如 AKS、EKS 或者 GKE,都具有开箱可用的块存储能力,然而这也不见得就是最好的选择。有很多因素需要考虑,比如说公有云的 StorageClass 的故障转移时间太长。例如在 一个针对 AWS EBS 的故障测试中,加载了卷的 Pod 用了超过五分钟才成功的在另一个节点上启动。Portworx 或者 OpenEBS 这样的云原生存储产品,正在尝试解决这类问题。
本文的目标是使用最常见的 Kubernetes 存储方案,进行基本的性能对比。我觉得在 Azure AKS 上使用下列后端:
现在我们来介绍每种存储后端,并交代一下安装过程,然后进入 AKS 测试环境进行测试,最后得出结果。
这一节中介绍测试中用到的存储方案,包含安装过程以及该方案的优缺点。
我选择这一方案的动机是以此作为所有测试的基线。这个方案 应该 提供最佳性能。Azure 动态的创建托管磁盘,并把它们映射到 K8s 的虚拟机中,最终成为 Pod 的存储卷。
这个方案很方便,什么多余的步骤都不需要。创建一个新的 AKS 集群之后,就自动提供了两个预定义的 StorageClass,分别是 default
和 managed-premium
,premium 使用的是基于 SSD 的高性能低延迟磁盘。
$ kubectl get storageclasses
NAME PROVISIONER AGE
default(default) kubernetes.io/azure-disk 8m
managed-premium kubernetes.io/azure-disk 8m
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
dbench-pv-claim Bound pvc-e7bd34a4-1dbd-11e9-8726-ae508476e8ad 1000Gi RWO managed-premium 10s
$ kubectl get po
NAME READY STATUS RESTARTS AGE
dbench-w7nqf 0/1ContainerCreating029s
AKS 开箱即用。
故障转移非常缓慢,有时需要十分钟以后,存储卷才能重新挂载到不同节点上的 Pod 里。
对我来说 OpenEBS 是个全新事物,因此我很有兴趣做他的测试。他提出了一个新的 Container Attached Storage(容器挂载存储) 概念,这是一个基于微服务的存储控制器,以及多个基于微服务的存储副本。他和 Portworx 同样,属于云原生存储分类的成员。
它是一个完全开源的方案,目前提供两种后端——Jiva 和 cStor。我最开始选择的是 Jiva,后来切换到 cStor。cStor 有很多长处,例如他的控制器和副本被部署到单一的 OpenEBS 所在的命名空间之中,能够管理原始磁盘等。每个 K8s 卷都有自己的存储控制器,能在节点存储容量的许可范围内对存储进行扩展。
在 AKS 上的安装非常容易。
完成这些步骤之后,就可以用 K8s 的 PVC 来动态的创建存储卷了。
注:OpenEBS 团队对我的案例场景进行了调整:
https://github.com/kmova/openebs/tree/fio-perf-tests/k8s/demo/dbench
Portworx 是另一个面向 Kubernetes 的容器原生存储方案,它专注于高度分布式的环境。这是一个主机可寻址的存储,每个卷都直接映射到挂在的主机上。他提供了基于应用 I/O 类型的自动微调能力。 官方网站 提供了更多信息。不幸的是,它也是本文中唯一的非开源产品。然而它提供了 3 节点的免费试用。
在 AKS 上的安装同样简单,我用了他们 网站 提供的生成器。
azure0
$ kubectl get pods -o wide -n kube-system -l name=portworx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
portworx-g9csq 1/1Running014m10.0.1.66 aks-agentpool-20273348-2<none>
portworx-nt2lq 1/1Running014m10.0.1.4 aks-agentpool-20273348-0<none>
portworx-wcjnx 1/1Running014m10.0.1.35 aks-agentpool-20273348-1<none>
为 PVC 创建一个 StorageClass,定义高优先级,以及三个副本:
root@aks-agentpool-20273348-0:~# kubectl get storageclass -o yaml portworx-sc
apiVersion: storage.k8s.io/v1
kind:StorageClass
metadata:
creationTimestamp:2019-01-28T21:10:28Z
name: portworx-sc
resourceVersion:"55332"
selfLink:/apis/storage.k8s.io/v1/storageclasses/portworx-sc
uid:23455e40-2341-11e9-bfcb-a23b1ec87092
parameters:
priority_io: high
repl:"3"
provisioner: kubernetes.io/portworx-volume
reclaimPolicy:Delete
volumeBindingMode:Immediate
GlusterFS 是知名的开源存储方案,是由 Redhat 提供的开源存储方案。 Heketi 是 GlusterFS 的 RESTful 卷管理界面。它提供了易用的方式为 GlusterFS 卷提供了动态供给的功能。如果没有 Heketi 的辅助,就只能手工创建 GlusterFS 卷并映射到 K8s PV 了。关于 GlusterFS 的更多信息,请阅读 官方文档 。
根据 Heketi 的 快速入门 文档进行部署。
wipefs
为 glusterfs 进行清理。这个磁盘并未用过。
$ wipefs -a /dev/sdc /dev/sdc: 8 bytes were erased at offset 0x00000218 (LVM2_member): 4c 56 4d 32 20 30 30 31gk-deploy -g -t topology.json
,会在每个节点上运行 Heketi 控制器管理之下的 GlusterFS Pod。$ kubectl get po -o wide NAME READY STATUS RESTARTS IP NODE NOMINATED NODE glusterfs-fgc8f 1/1Running010.0.1.35 aks-agentpool-20273348-1 glusterfs-g8ht6 1/1Running010.0.1.4 aks-agentpool-20273348-0 glusterfs-wpzzp 1/1Running010.0.1.66 aks-agentpool-20273348-2 heketi-86f98754c-n8qfb 1/1Running010.0.1.69 aks-agentpool-20273348-2
然后我遇到了新问题。K8s 控制面无法使用 Heketi 的 restURL
。我测试了一下 kube dns 的记录,pod IP 和 svc IP 都没有生效。最后只能手工使用 Heketi CLI 来创建存储卷。 $ export HEKETI_CLI_SERVER=http://10.0.1.69:8080
$ heketi-cli volume create --size=10--persistent-volume --persistent-volume-endpoint=heketi-storage-endpoints | kubectl create -f -
persistentvolume/glusterfs-efb3b155 created
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
glusterfs-efb3b155 10Gi RWX RetainAvailable
然后把现存 PV 映射为 PVC,加载给测试 工具 进行测试。
kind:PersistentVolumeClaim
apiVersion: v1
metadata:
name: glusterfs-efb3b155
spec:
accessModes:
-ReadWriteMany
storageClassName:""
resources:
requests:
storage:10Gi
volumeName: glusterfs-efb3b155
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
glusterfs-efb3b155 Bound glusterfs-efb3b155 10Gi RWX 36m
Heketi 的更多输出:
$ gluster volume info vol_efb3b15529aa9aba889d7900f0ce9849
VolumeName: vol_efb3b15529aa9aba889d7900f0ce9849
Type:ReplicateVolume ID:96fde36b-e389-4dbe-887b-baae32789436
Status:StartedSnapshotCount:0Number of Bricks:1 x 3=3Transport-type: tcp
Bricks:Brick1:10.0.1.66:/var/lib/heketi/mounts/vg_5413895eade683e1ca035760c1e0ffd0/brick_cd7c419bc4f4ff38bbc100c6d7b93605/brick
Brick2:10.0.1.35:/var/lib/heketi/mounts/vg_3277c6764dbce56b5a01426088901f6d/brick_6cbd74e9bed4758110c67cfe4d4edb53/brick
Brick3:10.0.1.4:/var/lib/heketi/mounts/vg_29d6152eeafc57a707bef56f091afe44/brick_4856d63b721d794e7a4cbb4a6f048d96/brick
OptionsReconfigured:
transport.address-family: inet
nfs.disable: on
performance.client-io-threads: off
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
heketi ClusterIP192.168.101.75<none>8080/TCP 5h
heketi-storage-endpoints ClusterIP192.168.103.66<none>1/TCP 5h
$ kubectl get endpoints
NAME ENDPOINTS AGE
heketi 10.0.1.69:80805h
heketi-storage-endpoints 10.0.1.35:1,10.0.1.4:1,10.0.1.66:15h
kubernetes 172.31.22.152:4431d
root@aks-agentpool-20273348-0:~# kubectl get endpoints heketi-storage-endpoints -o yaml
apiVersion: v1
kind:Endpoints
metadata:
creationTimestamp:2019-01-29T15:14:28Z
name: heketi-storage-endpoints
namespace:default
resourceVersion:"142212"
selfLink:/api/v1/namespaces/default/endpoints/heketi-storage-endpoints
uid:91f802eb-23d8-11e9-bfcb-a23b1ec87092
subsets:- addresses:
- ip:10.0.1.35
- ip:10.0.1.4
- ip:10.0.1.66
ports:
- port:1
protocol: TCP
我在 OpenStack 私有云上尝试过安装和运行 Ceph。它需要为特定硬件定制参数,根据数据类型设计 pg 组、SSD 分区和 CRUSH 图等。所以第一次听说在 3 节点的 K8s 集群上运行 Ceph 的时候,我不太相信它能工作。结果 Rook 的编排工具让我印象深刻,它把所有的步骤和 K8s 的编排能力结合在一起,让安装变得非常简便。
Rook 的缺省安装无需任何特定步骤,如果没什么高级配置,会非常简单。
FLEXVOLUME_DIR_PATH
,这是因为它需要 /etc/kubernetes/volumeplugins/
,而不是 Ubuntu 中缺省的 /usr/libexec
,没有这个步骤,Kubelet 就 无法加载 PVC 了。~~~ diff –git a/cluster/examples/kubernetes/ceph/operator.yaml b/cluster/examples/kubernetes/ceph/operator.yaml index 73cde2e..33f45c8 100755 — a/cluster/examples/kubernetes/ceph/operator.yaml +++ b/cluster/examples/kubernetes/ceph/operator.yaml @@ -431,8 +431,8 @@ spec: # – name: AGENT_MOUNT_SECURITY_MODE # value: “Any” # Set the path where the Rook agent can find the flex volumes
deviceFilter
中指定要使用的设备,这里是 /dev/sdc
。~~~ diff –git a/cluster/examples/kubernetes/ceph/cluster.yaml b/cluster/examples/kubernetes/ceph/cluster.yaml index 48cfeeb..0c91c48 100755 — a/cluster/examples/kubernetes/ceph/cluster.yaml +++ b/cluster/examples/kubernetes/ceph/cluster.yaml @@ -227,7 +227,7 @@ spec: storage: # cluster level storage configuration and selection useAllNodes: true useAllDevices: false
ceph status
cluster:
id: bee70a10-dce1-4725-9285-b9ec5d0c3a5e
health: HEALTH_OK
services:
mon:3 daemons, quorum c,b,a
mgr: a(active)
osd:3 osds:3 up,3in
data:
pools:0 pools,0 pgs
objects:0 objects,0 B
usage:3.0GiB used,3.0TiB/3.0TiB avail
pgs:[root@aks-agentpool-27654233-0/]#[root@aks-agentpool-27654233-0/]#[root@aks-agentpool-27654233-0/]# ceph osd status
+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+| id | host | used | avail | wr ops | wr data | rd ops | rd data | state |+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+|0| aks-agentpool-27654233-0|1025M|1021G|0|0|0|0| exists,up ||1| aks-agentpool-27654233-1|1025M|1021G|0|0|0|0| exists,up ||2| aks-agentpool-27654233-2|1025M|1021G|0|0|0|0| exists,up |+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+
我用 3 个虚拟机创建了基本的 Azure AKS 集群。为了连接到 Premium SSD 上,我只能使用 type E 以上级别的虚拟机。因此我选择了 Standard_E2s_v3 ,其上配备了 2 vCPU 以及 16GB 的内存。
在 AKS 集群所在的资源足中,可以看到所有的虚拟机、网络接口等资源。在这里创建 3 个 1TB 的 Premium SSD 存储,并手工挂载到每个虚拟机上。
这样在每个实例上,我都有 1TB 的空磁盘。Azure 的页面上,根据我们选择的虚拟机和磁盘尺寸来看,性能应该有 5000 IOPS 以及 200MB/s 的吞吐量。最后一节会显示我们的真实结果。
注意:每种存储的结果并不能作为独立的评估结果,但是其比较情况是可以参考的。有很多种对比测试的方法,这是最简单的一种。
为了运行测试,我决定使用现成的测试工具 Dbench ,它是一个 k8s 的 YAML 文件,会使用 FIO 运行 8 个测试用例。可以在 Dockerfile 中 指定不同测试 :
所有测试的结果可以在 Github 上找到。
随机读写测试表明,GlusterFS、Ceph 以及 Portworx 的读取性能比 AWS 本地盘的 hostPath
快了几倍。读缓存是罪魁祸首。GlusterFS 和 Portworx 的写入更快,其效率直逼本地磁盘。
随机 IOPS 测试中,Portworx 和 Ceph 表现最好。Portworx 在写入方面获得了接近 Azure 原生 PVC 的 IOPS。
延迟测试的结果比较有趣,Azure 原生 PVC 比多数其它存储都差。Portworx 和 Ceph 表现最好。写入方面,GlusterFS 要优于 Ceph。OpenEBS 的延迟相对来说非常的高。
顺序读写的结果和前面的随机测试差不多,然而 Cpeh 在读取方面比 GlusterFS 快了一倍多。写入结果基本一致,只有 OpenEBS 表现奇差。
最后一个测试用例检查的是混合读写情况下的 IOPS,Portworx 和 Ceph 都给出了优于 Azure 原生 PVC 的结果。
本文展示了一个简单的存储对比,使用未经性能优化的多种存储提供的存储卷进行测试和比较。建议关注本文所述方法,不建议直接采用结果进行判断。
忽略 Azure 的原生 PVC 或 hostPath
,我们可以得出如下测试结果:
调整性能数据的测试规模应该会很有意思。另外值得关注的对比就是 CPU 和内存的消耗。我会持续关注,并分享更多。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。