前言
“鸿蒙初判陶镕铁,大禹神人亲所设。湖海江河浅共深,曾将此棒知之切。开山治水太平时,流落东洋镇海阙。日久年深放彩霞,能消能长能光洁。老孙有分取将来,变化无方随口诀。要大弥于宇宙间,要小却似针儿节。棒名如意号金箍,天上人间称一绝。重该一万三千五百斤,或粗或细能生灭。也曾助我闹天宫,也曾随我攻地阙。伏虎降龙处处通,炼魔荡怪方方彻。举头一指太阳昏,天地鬼神皆胆怯。混沌仙传到至今,原来不是凡间铁。”
--《西游记》
从自研的分布式文件系统 “盘古” 开天辟地之后,阿里云经过 10 年的发展已经在 IaaS+PaaS 产品能力排名上位居东半球第一,世界第三,在计算、存储、网络、安全等方面已经处于领先水平。而云计算区别于传统服务器架构除了成本和可靠性以外,弹性能力也是一个突出的优势。恰如有万千变化的金箍棒一样,与计算的弹性能力为用户提供随心顺意的业务扩展能力,助客户从容面对各种业务伸缩场景。
2021年7月27日,在可信云大会上,中国信息通信研究院发布了《虚拟化云平台性能评估方法》,并宣布阿里云成为首个通过“虚拟化云平台性能测试(大规模)”的云厂商,获得“2021可信云技术服务大规模最佳实践”的称号。在本次测试的弹性模块中,在信通院工作人员的见证下,阿里云使用弹性伸缩工具,在 1106秒(约18分)内完成了1万台(日常使用场景单次扩容峰值)云服务器的扩容【6】。
图一 虚拟化云平台性能测试通过证书
像如意金箍棒需要在老君炉内的不断历练一样,块存储极致的弹性能力也经历了多次迭代才至臻完善。本文会结合业务场景讲述块存储弹性能力这根金箍棒背后的技术和故事。
弹性伸缩的需求
基于互联网的应用有很多共性的特点会对云计算有弹性伸缩的需求:
-
业务规模大 用户可以利用互联的普及和快速传播的特点,可以快速实现业务规模的扩展。同时会带来更多的计算和存储资源需求。现在诸如 12306 铁路购票系统、微博等新媒体、淘宝购物、短视频和本地生活等业务越来越多地实现了云化部署。因此对云计算有快速、规模化部署的需求
-
突发流量大 互联网业务极易产生热点访问,比如春运和黄金周等时段数以亿计地对火车票的操作需求、微博和短视频的热点搜索访问,以及 6.18、双十一等商业大促行为都会对既有的互联网业务有快速扩展的需要。同时热点过后,回归正常业务流量之后也需要对业务进行缩容,避免闲置,降低企业运营成本。因为对云计算有快速扩容、缩容的弹性需求
综上,业务的弹性伸缩能力在云计算的场景有一个递进式的需求:
-
业务的弹性能力
业务自身需要能够根据业务的流量情况调整自身业务的规模,包括业务关联的多个应用的弹性伸缩调整
-
应用的弹性能力
应用的弹性依赖于自身的快速部署、启动以及流量切流的能力
-
服务器的弹性能力
不论基于 ECS 实例还是容器,都是对底层服务器弹性伸缩能力的需求,即资源的快速申请和释放、快速启动和实例化等。
阿里云提供的弹性能力包含两个典型的架构:基于 IaaS 的 ECS 实例【5】和基于 PaaS 的 ECI 实例。这两种架构的弹性伸缩能力最本质的是对底层云服务器的扩容和缩容。对于块存储来说,这个弹性能力就是从镜像按需为这些服务器批量创建块设备-云盘,典型场景如下:
-
ECS实例快速启动
-
云游戏和离线计算场景数据盘批量创建和挂载
-
ECI 容器批量启动
图二 实例和容器场景下弹性能力的需求转化为底层服务器云盘的弹性能力
极致弹性背后的技术
阿里云快照技术
快照业务简介
快照作为云盘的增值服务为云盘提供某一时刻的静态数据备份。快照的存储方式分为集群本地存储和对象存储(OSS)。快照提供丰富的业务生态,包括数据备份、回滚、克隆(创建云盘)、 DevOps、安全扫描、无代理备份以及快照直接读写等。同时快照作为阿里云弹性计算(ECS)镜像的底层实现,支持镜像的导入、导出以及虚拟机启动、容器扩容和云盘批量克隆等功能。
图三 快照业务简介
快照的原理
块存储快照是基于数据版本和数据差异来实现。对云盘逻辑空间按照固定的大小进行分块(Block)后为每一个 Block 分配一个标号(Block ID)。同时每一个 Block 具有一个版本号(Version)用于记录 Block 数据的修改版本。当云盘上的 Block 被修改之后存储端会记录该 Block 状态为脏(Dirty),而快照作为云盘某个时间点数据的备份就是对这些标脏的 Block 进行备份并提升这些 Block 的 Version。具有相同 Version 的 Block 属于同一个快照一致性点。
块存储快照分为全量快照和增量快照。全量快照为快照一致性点时云盘上所有非空 Block 的集合,而增量快照包含相对于父快照的差异 Block,即快照一致性点时云盘上所有与父快照 Block 版本号不相同的 Block 集合。同时增量快照中与父快照相同的 Block 通过引用的方式构建出完整的逻辑地址空间视图。
下图显示了不同快照类型中数据版本与数据块的引用关系。
图四 快照的原理
ECS 镜像原理
底层数据采用快照格式进行存储,同时在管控层面附加诸如大小、格式等镜像元数据信息来实现。因此我们也支持从快照直接转换为镜像,对镜像的操作基本等同于快照操作。
快照的存储方式
阿里云块存储是构建在更底层的分布式文件系统(盘古)之上,所有的数据以盘古文件的方式进行存储。从云盘层面看数据是按照一定大小分成若干个区域(Segment)进行组织。根据逻辑空间按照 Segment 大小将云盘划分为 N 个 Segment,并且多个 Segment 按照一定的条带配置构成条带组(如2MB*4,即条带宽度 2MB,4 个 Segment 一组)。在同一个条带组中的 Segment 按条带依次写入。一块云盘Segment 的主要文件包括两大类:数据文件(Data File)和索引文件(Index File),其中数据文件用于存储实际的云盘数据,而索引文件用于映射云盘 LBA(逻辑地址空间 Logical Block Address)在数据文件中位置和大小。
快照创建的原理是通过 Hark Link 的方式使快照与云盘共享数据文件,并且通过一个快照的索引文件(Index File)记录快照数据 LBA 在数据文件(Data File)中的位置。此时所有快照的数据均位于存储集群内(本地快照副本,Snapshot Copy)。与此同时,我们对快照的逻辑空间按照固定大小进行分块后离线上传到对象存储(OSS)中独立的 Object 文件进行备份(OSS 快照)。
图五 快照的存储方式
Lazyload 技术
传统的虚拟机技术,镜像数据要存储虚拟机的宿主机本地,之后虚拟机通过本地的镜像数据进行启动。虚拟机挂载的数据盘也是类似情况,数据需要存储于宿主机本地才能正常工作。
阿里云块存储采用延迟加载(Lazyload)技术实现数据按需读取和后台下载,使从镜像/快照创建的云盘在创建操作完成之后立即进行读写,这样可以无延迟地快速启动虚拟机或使用新创建的云盘。
镜像数据 Lazyload 是对快照空间按照固定数据块大小分块后下载的,分为两种类型:
-
后台下载 云盘创建完成后拉起的后台数据下载任务,顺序从 OSS 下载非空的数据块到集群本地来创建快照副本(Snapshot Copy),并在后端服务保存 LRU 的数据块缓存。
-
Lazyload Read 由云盘的读 IO 触发的下载请求。此时待读取的云盘 LBA 所在的数据块还没有通过后台任务下载过,因此会高优先级地从 OSS 拉取对应的数据块,并加入到 LRU 缓存
图六 快照 Lazyload 技术
快照克隆原理
从镜像/快照/备份创建新的云盘的实现原理可以划分为以下两种:
图七 快照克隆技术原理
Solution 1 |
Solution 2 |
|
实现原理 |
每块云盘从对象存储或者冷存储单独下载快照数据 |
同一个快照集群内只下载一份数据并创建为快照副本。所有云盘通过 Hard Link 方式实现对快照副本数据共享 |
数据下载流量 |
从对象存储或冷存储直接读取,总流量为快照有效数据量与云盘数量乘积 |
整个集群最多只从对象存储下载一份数据。创盘时如果有本地副本则不再下载。总流量为快照有效数据量 |
集群本地存储 |
各云盘数据独立,集群占用容量与云盘数量成正比 |
多云盘共享同一快照副本数据 |
相关产品 |
EBS 1.0 |
EBS 2.0 |
通过上面的快照克隆方案的对比可知,阿里云块存储新版本的克隆方案创新地通过快照副本共享的方式为所有云盘提供数据,使从快照批量创盘对网络流量的占用从与云盘数量成线性关系变为常量,以数个数量级地减少了对存储集群 NC 网络的冲击。同时也极大地节省了存储集群的空间,特别是针对以读为主的批量计算云盘和容器镜像缓存用途的云盘创建场景。
批量克隆能力优化
快照下载速度
从前面的介绍可知,快照在 OSS 是按照固定大小的数据块进行存储的,在快照下载时为了提高下载速度以达到缩短对云盘 IO 毫秒级影响的目的,我们对快照数据采用多任务并行下载的方式拉取快照数据到集群本地副本中。 每个下载任务可以提供至少 20MB/s 的下载带宽,并发任务的上限为 64 个,单快照的下载速度可以达到 1.28 GB/s。阿里云典型的镜像大小为 20~60 GB,基本上数据下载时间 16~47 秒。
快照格式转换
云盘和快照数据都是按照 Segment 来组织的,但是快照和云盘出于不同的考虑,比如多任务并发下载快照数据,导致快照的 Segment 大小远小于云盘的 Segment 大小。因此集群中快照副本的 Segment 没有办法直接进行转换为云盘的 Segment,需要一次数据导入(Import)将快照数据导入到云盘中。
快照数据导入的方式是通过 Load 快照 Segment 后分析快照 LBA 与数据文件存储的对应关系来确定哪些数据文件是云盘 Segment 所需,之后通过 Hard Link 的方式把快照 Segment 下的数据文件 Link 到云盘 Segment 中的。由于在分布式文件系统-盘古上诸如 Hard Link 之类的文件 Meta 操作是通过集群单点 Master 来处理的,如果每个云盘在导入快照数据的时候都进行如此多的文件 Meta 操作会打爆 Master 的处理能力,进而造成整个集群的 Meta 处理时延变长,大量积压的数据 Import 请求造成批量创盘长尾和创盘时间过长。
考虑到所有云盘共享共一个快照副本数据,各云盘的 Segment 与快照 Segment 数据文件的对应关系是相同的,所以我们只需要为一个云盘计算映射关系,其他云盘直接复用就可以。因此我们在快照数据下载完成之后把快照的格式按照目标云盘的格式进行转换,是快照和云盘 Segment 变成一一对应的关系。再有快照数据为只读数据,很多针对于云盘设计的校验可以跳过,这样就大大减少了文件 Meta 操作数量,以及整体 import 的性能。
经过格式转换,我们的文件 Meta 操作数量减少了 70%,Segment数据导入的平均时间缩短了一半以上,因此单快照在单集群的每分钟创盘数量提高了 6 倍以上。
图八 快照副本格式转换
快照副本数据打散
由于多个云盘共享同一份快照副本数据,所有云盘对相同 LBA 的读取会转换为对快照副本某个 LBA 的读取请求。按照之前的介绍,快照和云盘都是按照条带写入的,以 2MB 宽的条带为例,该条带内的数据一定会包含在同一个快照 Segment 的数据文件中,而默认的快照文件副本数为 3 个,因此一个 2MB 范围内的数据访问默认只能从 3 个副本文件中进行读取,这样就在负责 3 个副本文件 Chunk 读写的的盘古服务角色 ChunkServer 上造成读热点。直观的结果会导致 Slow IO 或者 IO hang。
为了解决这个问题,我们需要对快照数据进行进一步打散。在不改变 2MB 条带宽度的情况下,我们在写入 2MB 数据到快照 Segment 的时候采用 Round-Robin 的方式分别写入 8 个数据文件,因此同一个 2MB 范围数据可以有 8 * 3 = 24 个副本可供数据读取,在原来基础上打散效果提升了 8 倍。
除此之外,我们还会有另外两中手段对快照数据副本进行打散:
-
根据单快照创盘数量调整快照数据文件副本数量
-
根据单快照创盘数量新增快照本集群副本(Snapshot Copy)与新创建云盘共享数据
图九 快照副本数据打散
块存储弹性能力的最佳实践
ECI容器业务批量启动
现在越来越多的互联网业务已经从传统的通过虚拟机形式部署转变为利用容器技术进行部署。企业对云计算的弹性能力的需求也从对云盘批量克隆的需求转换为对容器实例的弹性能力的需求。如何从同一个镜像快速启动容器实例也就成体现弹性能力的关键。本节会介绍块存储弹性能力如何助力阿里云 ECI 快速启动的最佳实践。
相关产品详见参考文献【2】。
容器启动过程分析
容器部署业务的一大优势就是容器实例化的速度比重新拉起一台 ECS 实例更快速,但是这个启动过程包含两种情况:利用 Host 本地镜像实例化容器和从 Registry 现拉取镜像文件到本地后实例化容器,下面从操作启动和容器实例化的过程对启动分析的耗时进行分析。
操作系统启动分析
我们对主流的操作系统和阿里云使用量最大的镜像进行了ECS 实例启动的测试,分析的 IO Pattern 如下:
-
Linux 操作系统启动读取数量为 200MB 左右
-
Windows 操作系统启动读取数据量为 380MB 左右
-
读 IO 的大小以 2 ~ 64KB 为主 (2KB/4KB/16KB/32KB/64KB)
-
读 IO 分布 2MB 范围内的集中读(占比 20%),和1GB 范围内的离散读(占比 80%)
详细的测试结果如下:
镜像 |
Linux |
Windows |
||
CentOS 8.3 x64 |
AliLinux 3.2104 x64 |
Window 2019 x64 |
Windows 2016 x64 |
|
镜像大小 |
20GB |
20GB |
40GB |
40GB |
数据读取量 |
184.8MB |
208MB |
377.2MB |
367.5MB |
LInux 启动需要 200MB 左右(SSH 成功) |
Windows 启动需要 380MB 左右(RDP 成功) |
|||
Offset 访问分布 |
||||
IO Pattern |
|
|
|
|
|
容器镜像启动数据
根据 Tyler Harter(University of Wisconsin—Madison) 等人对容器启动过程的分析【1】可知容器启动过程中 76%的时间用于镜像拉取和解压缩镜像分层数据,而与此同时镜像文件中只有的 6% 是容器启动所必须的。这个数据与我们实测的结果也是比较接近的。
图十 容器启动过程数据量和时间占比和镜像启动容器测试结果
启动分析结论
综上,原生的容器启动过程需要把容器镜像拉取到本地之后实例化容器,而镜像中真正用于启动的数据量很小。业界对于容器启动加速的办法都是对镜像进行缓存来实现。下面我们介绍下块存储实现容器镜像缓存的方案。
块存储的镜像缓存方案
行业内镜像缓存方案的核心思路是实现对镜像的按需读取之后缓存镜像数据,比较成熟的方案有 Nydus【3】,DADI【4】等,他们是通过自定义镜像格式实现数据按需读取。而阿里云的快照技术本就是 ECS 实例启动所需镜像的底层实现,我们可以利用快照技术把容器的镜像转化为快照,之后通过快照按需快速创建大量云盘提供的弹性能力在容器大批量启动时挂载包含镜像数据的云盘到容器作为镜像目录启动。
块存储的云盘随机访问能力和延迟加载(Lazyload)技术可以天然的实现对容器镜像文件的按需读取。同时块设备的数据存储于存储端,既无需在计算端进行数据缓存,也不需要在计算端按照额外组件。此外,由于在镜像制作的时候已经完成了对镜像数据的解压缩和合并,对于计算端的 CPU 等资源几乎是没有任何依赖。
以下是块存储的镜像缓存方案与原生镜像拉取方式的对比:
方案 |
容器社区方案 |
块存储镜像缓存 |
架构图 |
||
原理 |
|
|
按需读取 |
否 |
是 |
计算端缓存数据 |
是 |
否 |
计算端解压缩 |
是 |
否 |
计算端侵入组件 |
是 |
否 |
优化效果
ECI 的镜像缓存最终采用的是块存储的镜像缓存方案,并且经过对快照批量创建云盘能力的提升后作为容器启动的主要优化点助力 ASK+ECI 方案在与友商的直接对话中获胜并赢得了新媒体领先企业的弹性扩容订单。
图十一 容器 POD 启动时间优化效果
未来展望
容器业务场景下更强的弹性能力
阿里云块存储会对 ECI 容器镜像缓存的方案做进一步优化。在坚持对计算端无侵入和无额外的计算资源需求的前提下进一步优化镜像创建云盘时所需的 Meta 操作,提高容器启动时从容器镜像批量创建云盘的弹性能力,为容器业务提供更快速、更强大的业务弹性能力。
极速可用的弹性伸缩
利用本地快照实现镜像极速可用
当前不论是 ECS 实例镜像还是 ECI 容器镜像的制作都是依赖于 OSS 快照来作为底层存储。镜像数据需要上传到 OSS 完成之后才可以进行批量创建云盘或者容器启动。镜像的制作过程根据镜像数据多少往往需要较长的时间。因此需要在进行弹性伸缩之前提前预留镜像制作时间。
从前面的快照技术的介绍可知,本地快照通过 Hardlink 的方式来实现,快照数据存储于集群本地,无需等待数据上传到 OSS,整个创建过程秒级完成。同时本地快照可以在后台离线转换为 OSS 快照,在满足极速可用的同时仍然可以利用快照的复制功能实现多 Region 间的镜像分发和共享能力。因此我们利用本地快照作为镜像底层数据存储可以实现镜像极速可用,实现镜像制作和快照创盘弹性伸缩能力的无缝衔接。
利用镜像预热实现大量云盘快速创建
当前快照创建云盘通过数据共享的方式实现,单快照创建云盘数量超过阈值时会带来单一数据副本访问流量集中的热点问题,并且同一快照无法创建不同类型云盘(加密/非加密,不同条带)。此外,新创建云盘在各个存储集群内由于实际库存情况影响无法做到根据快照引用数量进行均衡调度。
未来我们会提供云盘预热的功能,即预先下载快照数据并在各存储集群内根据快照创盘的数量调整快照副本数量,使批量创建的云盘在集中读数据的时候可以有效地进行流量打散。并且我们可以在预热时调整集群的库存来对新创建云盘进行均衡调度,提高并发创盘的数量。同时我们的镜像预热可以根据目标云盘的类型为同一个快照创建不同类型的副本。因此,利用镜像预热功能我们可以实现单一可用区从一个快照快速创建数万云盘,并且支持多种不同类型的云盘。
参考文献
【2】ECI 镜像缓存 https://help.aliyun.com/document_detail/273116.html
【3】Nydus 镜像加速 https://developer.aliyun.com/article/776458
【4】DADI 镜像加速 https://developer.aliyun.com/article/783266
【5】什么是云服务器 ECS https://help.aliyun.com/document_detail/25367.html
【6】https://blog.csdn.net/weixin_46593167/article/details/119151112