支持NVMe(Non-Volatile Memory Express)协议的ESSD云盘称为NVMe云盘。NVMe云盘支持多重挂载能力,最多可以同时挂载到16个ECS实例上;同时也基于多重挂载实现了符合NVMe协议规范的Reservation功能。这些特性可以帮助您实现应用的多个副本间的数据共享以提升数据读写性能。本文通过简单的示例介绍如何在ACK集群中使用NVMe云盘多重挂载及Reservation功能。
阅读前提示
为了让您更好地使用NVMe云盘多重挂载及Reservation功能,建议您在阅读本文档之前,了解以下内容:
应用场景
云盘多重挂载主要有以下应用场景:
使用限制
单个NVMe云盘支持同时挂载到同一可用区内的最多16个ECS实例。
ACK仅支持通过volumeDevices的方式挂载可从多个节点读写的云盘,即不能通过文件系统访问。
更多使用限制,请参见多重挂载使用限制。
前提条件
已创建ACK托管集群,且集群为1.20及以上版本。具体操作,请参见创建ACK托管集群。
已安装csi-plugin和csi-provisioner组件,且组件为v1.24.10-7ae4421-aliyun及以上版本。关于csi-plugin和csi-provisioner组件的升级操作,请参见管理CSI组件。
集群至少包含2个在同一可用区的且支持使用多重挂载功能的节点,支持的实例规格族详见多重挂载使用限制。
已准备好业务应用且符合以下要求,然后将应用打包至容器镜像中用于在ACK集群中部署。
应用支持同时从多个副本中访问同一云盘中的数据。
应用能自行通过标准的NVMe Reservation等功能确保数据的一致性。
计费说明
云盘多重挂载功能不会产生额外费用,支持NVMe协议的相关资源仍保持各资源原有的计费方式。关于云盘相关计费的更多信息,请参见计费说明。
应用示例
本文使用下方应用示例的源代码和Dockerfile,将其构建后上传至镜像仓库以便后续在集群中部署。该示例应用中的多个副本共同管理一个租约,但仅有一个副本持有该租约。若该副本无法正常工作,其他副本将自动抢占该租约。编写应用注意事项如下:
示例中使用
O_DIRECT
打开块设备进行读写,避免任何缓存对测试的影响。示例中使用Linux内核提供的Reservation简化接口,应用也可使用以下两种方法执行与Reservation相关的命令,以下方法需要特权。
C代码:
ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
命令行工具:
nvme-cli
关于NVMe Reservation功能的详细信息,请参见NVMe Specification。
步骤一:部署应用并配置多重挂载
创建名为alicloud-disk-shared的StorageClass,并开启云盘的多重挂载功能。
创建名为data-disk的PVC,并设置accessModes
为ReadWriteMany
;volumeMode
为Block
。
创建名为lease-test的StatefulSet应用,使用本文应用示例的镜像。
使用以下内容,创建lease.yaml文件。
请将以下YAML中容器镜像地址替换为您实际应用的镜像地址。
重要由于NVMe Reservation在节点维度生效,同一节点上的多个Pod可能会互相干扰,所以本示例中通过
podAntiAffinity
以避免多个Pod调度到同一个节点上。如果您的集群中包括其他不使用NVMe协议的节点,您需要自行设置亲和性,以确保将Pod调度到使用NVMe协议的节点上。
参数
使用多重挂载功能配置说明
普通挂载配置说明
StorageClass
parameters.multiAttach
设置为true,以开启云盘的多重挂载功能。
无需配置
PVC
accessModes
ReadWriteMany
ReadWriteOnce
volumeMode
Block
Filesystem
存储卷挂载方式
volumeDevices:直接通过块设备访问云盘中的数据。
volumeMounts:主要用于挂载文件系统类型的Volume。
执行以下命令,部署应用。
kubectl apply -f lease.yaml
步骤二:验证多重挂载及Reservation效果
为了确保NVMe云盘的数据一致性,您可以在应用中通过Reservation控制读写权限,如果一个Pod进行写操作,其他Pod就只能进行读操作。
多个节点可读写同一个云盘
执行以下命令,查看Pod日志。
kubectl logs -l app=lease-test --prefix -f
预期输出:
[pod/lease-test-0/lease] Register as key 4745d0c5cd9a2fa4
[pod/lease-test-0/lease] Refreshed lease
[pod/lease-test-0/lease] Refreshed lease
[pod/lease-test-1/lease] Remote lease-test-0 refreshed lease
[pod/lease-test-0/lease] Refreshed lease
[pod/lease-test-1/lease] Remote lease-test-0 refreshed lease
[pod/lease-test-0/lease] Refreshed lease
[pod/lease-test-1/lease] Remote lease-test-0 refreshed lease
[pod/lease-test-0/lease] Refreshed lease
[pod/lease-test-1/lease] Remote lease-test-0 refreshed lease
预期输出表明,Pod lease-test-1可以即时读取到Pod lease-test-0的写入的内容。
NVMe Reservation创建成功
执行以下命令,获取云盘ID。
kubectl get pvc data-disk -ojsonpath='{.spec.volumeName}'
登录两个节点中的任意一个节点,执行以下命令确认NVMe Reservation是否创建成功。
请替换以下代码中
2zxxxxxxxxxxx
为您上一步获取到的云盘ID中d-
之后的内容。nvme resv-report -c 1 /dev/disk/by-id/nvme-Alibaba_Cloud_Elastic_Block_Storage_2zxxxxxxxxxxx
预期输出:
NVME Reservation status: gen : 3 rtype : 1 regctl : 1 ptpls : 1 regctlext[0] : cntlid : ffff rcsts : 1 rkey : 4745d0c5cd9a2fa4 hostid : 4297c540000daf4a4*****
预期输出表明,NVMe Reservation已创建成功。
通过Reservation可阻断异常节点的写入IO
登录Pod lease-test-0所在的节点上执行以下命令,暂停该进程用于模拟故障场景。
pkill -STOP -f /usr/local/bin/lease
等待30秒后,执行以下命令,再次查看日志。
kubectl logs -l app=lease-test --prefix -f
预期输出:
[pod/lease-test-1/lease] Remote lease-test-0 refreshed lease [pod/lease-test-1/lease] Remote is dead, preempting [pod/lease-test-1/lease] Register as key 4745d0c5cd9a2fa4 [pod/lease-test-1/lease] Refreshed lease [pod/lease-test-1/lease] Refreshed lease [pod/lease-test-1/lease] Refreshed lease
预期输出表明,此时Pod lease-test-1已接管,持有租约成为服务的主节点。
再次登录Pod lease-test-0所在的节点上执行以下命令,恢复之前暂停的进程。
pkill -CONT -f /usr/local/bin/lease
执行以下命令,再次查看日志。
kubectl logs -l app=lease-test --prefix -f
预期输出:
[pod/lease-test-0/lease] failed to write lease: Invalid exchange
预期输出表明,Pod lease-test-0将无法再写入该云盘,容器lease自动重启。说明其写入IO的操作已成功被Reservation阻断。
相关文档
如果您的NVMe云盘空间不满足要求或磁盘已满,请参见扩容云盘存储卷。