现现在CPU的计算能力和磁盘的访问延迟之间的差距逐渐扩大,使得用户云主机的磁盘IO常常成为严重的性能瓶颈,云计算环境下更加明显。针对机械盘IO性能低下的问题,咱们经过自研的云主机IO加速方案,使4K随机写的最高性能由原来的300 IOPS提高至4.5W IOPS,提升了150倍,即用机械盘的成本得到了SSD的性能。13年上线至今,该方案已历经五年的运营实践,并成功应用于全网93%的标准型云主机,覆盖12.7万台实例,总容量达26PB。算法
一.为何须要IO加速网络
传统的机械磁盘在寻址时须要移动磁头到目标位置,移动磁头的操做是机械磁盘性能低下的主要缘由,虽然各类系统软件或者IO调度器都致力于减小磁头的移动来提升性能,但大部分场景下只是改善效果。通常,一块SATA机械磁盘只有300左右的4K随机IOPS,对于大多数云主机来讲,300的随机IOPS哪怕独享也是不够的,更况且在云计算的场景中,一台物理宿主机上会有多台云主机。所以,必需要有其余的方法来大幅提高IO性能。app
早期SSD价格昂贵,采用SSD必然会带来用户使用成本的提高。因而,咱们开始思考可否从技术角度来解决这个问题,经过对磁盘性能特性的分析,咱们开始研发第一代IO加速方案。即便今天SSD愈来愈普及,机械盘凭借成本低廉以及存储稳定的特色,仍然普遍应用,而IO加速技术能让机械盘知足绝大多数应用场景的高IO性能需求。运维
二.IO加速原理及第一代IO加速模块化
咱们知道机械磁盘的特性是随机IO性能较差,但顺序IO性能较好,如前文中提到的4K随机IO只能有300 IOPS的性能,但其顺序IO性能能够达到45000 IOPS。性能
IO加速的基本原理就是利用了机械磁盘的这种性能特性,首先系统有两块盘:一块是cache盘,它是容量稍小的机械盘,用来暂时保存写入的数据;另外一块是目标盘,它是容量较大的机械盘,存放最终的数据。测试
1. IO的读写优化
写入时将上层的IO顺序的写入到cache盘上,由于是顺序的方式写入因此性能很是好,而后在cache盘空闲时由专门的线程将该盘的数据按照写入的前后顺序回刷到目标盘,使得cache盘保持有必定的空闲空间来存储新的写入数据。云计算
为了作到上层业务无感知,咱们选择在宿主机内核态的device mapper层(简称dm层)来实现该功能,dm层结构清晰,模块化较为方便,实现后对上层体现为一个dm块设备,上层不用关心这个块设备是如何实现的,只须要知道这是一个块设备能够直接作文件系统使用。线程
按照上述方式,当新的IO写入时,dm层模块会将该IO先写入cache盘,而后再回刷到目标盘,这里须要有索引来记录写入的IO在cache盘上的位置和在目标盘上的位置信息,后续的回刷线程就能够利用该索引来肯定IO数据源位置和目标位置。咱们将索引的大小设计为512字节,由于磁盘的扇区是512字节,因此每次的写入信息变成了4K数据+512字节索引的模式,为了性能考虑,索引的信息也会在内存中保留一份。
读取过程比较简单,经过内存中的索引判断须要读取位置的数据是在cache盘中仍是在目标盘中,而后到对应的位置读取便可。
写入的数据通常为4K大小,这是由内核dm层的特性决定的,当写入IO大于4K时,dm层默认会将数据切分,好比写入IO是16K,那么就会切分红4个4K的IO;若是写入数据不是按照4K对齐的,好比只有1024字节,那么就会先进行特殊处理,首先检查该IO所覆盖的数据区,若是所覆盖的内存区在cache盘中有数据,那么须要将该数据先写入目标盘,再将该IO写入目标盘,这个处理过程相对比较复杂,但在文件系统场景中大部分IO都是4K对齐的,只有极少数IO是非对齐的,因此并不会对业务的性能形成太大影响。
2. 索引的快速恢复与备份
系统在运行过程当中没法避免意外掉电或者系统关闭等状况发生,一个健壮的系统必须可以在遇到这些状况时依然能保证数据的可靠性。当系统启动恢复时,须要重建内存中的索引数据,这个数据在cache盘中已经和IO数据一块儿写入了,但由于索引是间隔存放的,若是每次都从cache盘中读取索引,那么,数据的恢复速度会很是慢。
为此,咱们设计了内存索引的按期dump机制,每隔大约1小时就将内存中的索引数据dump到系统盘上,启动时首先读取该dump索引,而后再从cache盘中读取dump索引以后的最新1小时内的索引,这样,就大大提高了系统恢复的启动时间。
依据上述原理,UCloud自研了第一代IO加速方案。采用该方案后,系统在加速随机写入方面取得了显著效果,且已在线上稳定运行。
三.第一代IO加速方案存在的问题
但随着系统的运行,咱们也发现了一些问题。
1)索引内存占用较大
磁盘索引由于扇区的缘由最小为512字节,但内存中的索引其实没有必要使用这么多,过大的索引会过分消耗内存。
2)负载高时cache盘中堆积的IO数据较多
IO加速的原理主要是加速随机IO,对顺序IO由于机械盘自己性能较好不须要加速,但该版本中没有区分顺序IO和随机IO,全部IO都会统一写入cache盘中,使得cache堆积IO过多。
3)热升级不友好
初始设计时对在线升级的场景考虑不足,因此第一代IO加速方案的热升级并不友好。
4)没法兼容新的512e机械磁盘
传统机械磁盘物理扇区和逻辑扇区都是512字节,而新的512e磁盘物理扇区是4K了,虽然逻辑扇区还可使用512字节,但性能降低严重,因此第一代IO加速方案的4K数据+512字节索引的写入方式须要进行调整。
5)性能没法扩展
系统性能取决于cache盘的负载,没法进行扩展。
四.第二代IO加速技术
上述问题都是在第一代IO加速技术线上运营的过程当中发现的。而且在对新的机械磁盘的兼容性方面,由于传统的512字节物理扇区和逻辑扇区的512n类型磁盘已经逐渐再也不生产,若是不对系统作改进,系统可能会没法适应将来需求。所以,咱们在第一代方案的基础上,着手进行了第二代IO加速技术的研发和优化迭代。
1. 新的索引和索引备份机制
第一代的IO加速技术由于盘的缘由没法沿用4K+512Byte的格式,为了解决这个问题,咱们把数据和索引分开,在系统盘上专门建立了一个索引文件,由于系统盘基本处于空闲状态,因此不用担忧系统盘负载高影响索引写入,同时咱们还优化了索引的大小由512B减小到了64B,而数据部分仍是写入cache盘,以下图所示:
其中索引文件头部和数据盘头部保留两个4K用于存放头数据,头数据中包含了当前cache盘数据的开始和结束的偏移,其后是具体的索引数据,索引与cache盘中的4K数据是一一对应的关系,也就是每一个4K的数据就会有一个索引。
由于索引放在了系统盘,因此也要考虑,若是系统盘发生了不可恢复的损坏时,如何恢复索引的问题。虽然系统盘发生损坏是很是小几率的事件,但一旦发生,索引文件将会彻底丢失,这显然是没法接受的。所以,咱们设计了索引的备份机制,每当写入8个索引,系统就会将这些索引合并成一个4K的索引备份块写入cache盘中(具体见上图中的紫色块),不满4K的部分就用0来填充,这样当系统盘真的发生意外也能够利用备份索引来恢复数据。
在写入时会同时写入索引和数据,为了提升写入效率,咱们优化了索引的写入机制,引入了合并写入的方式:
当写入时能够将须要写入的多个索引合并到一个4K的write buffer中,一次性写入该write buffer,这样避免了每一个索引都会产生一个写入的低效率行为,同时也保证了每次的写入是4K对齐的。
2. 顺序IO识别能力
在运营第一代IO加速技术的过程当中,咱们发现用户在作数据备份、导入等操做时,会产生大量的写入,这些写入基本都是顺序的,其实不须要加速,但第一代的IO加速技术并无作区分,因此这些IO都会被写入在cache盘中,致使cache盘堆积的IO过多。为此,咱们添加了顺序IO识别算法,经过算法识别出顺序的IO,这些IO不须要经过加速器,会直接写入目标盘。
一个IO刚开始写入时是没法预测此IO是顺序的仍是随机的,通常的处理方式是当一个IO流写入的位置是连续的,而且持续到了必定的数量时,才能认为这个IO流是顺序的,因此算法的关键在于如何判断一个IO流是连续的,这里咱们使用了触发器的方式。
当一个IO流开始写入时,咱们会在这个IO流写入位置的下一个block设置一个触发器,触发器被触发就意味着该block被写入了,那么就将触发器日后移动到再下一个block,当触发器被触发了必定的次数,咱们就能够认为这个IO流是顺序的,固然若是触发器被触发后必定时间没有继续被触发,那么咱们就能够回收该触发器。
3. 无感知热升级
第一代的IO加速技术设计上对热升级支持并不友好,更新存量版本时只能经过热迁移而后重启的方式,整个流程较为繁琐,因此在开发第二代IO加速技术时,咱们设计了无感知热升级的方案。
因为咱们的模块是位于内核态的dm层,一旦初始化后就会生成一个虚拟的dm块设备,该块设备又被上层文件系统引用,因此这个模块一旦初始化后就不能卸载了。为了解决这个问题,咱们设计了父子模块的方式,父模块在子模块和dm层之间起到一个桥梁的做用,该父模块只有很是简单的IO转发功能,并不包含复杂的逻辑,所以能够确保父模块不须要进行升级,而子模块包含了复杂的业务逻辑,子模块能够从父模块中卸载来实现无感知热升级:
上图中的binlogdev.ko就是父模块,cachedev.ko为子模块,当须要热升级时能够将cache盘设置为只读模式,这样cache盘只回刷数据再也不写入,等cache盘回刷完成后,能够认为后续的写入IO可直接写入目标盘而不用担忧覆盖cache盘中的数据,这样子模块就能够顺利拔出替换了。
这样的热升级机制不只实现了热升级的功能,还提供了故障时的规避机制,在IO加速技术的灰度过程当中,咱们就发现有个偶现的bug会致使宿主机重启,咱们第一时间将全部cache盘设置为只读,以免故障的再次发生,并争取到了debug的时间。
4. 兼容512e机械磁盘
新一代的机械磁盘以512e为主,该类型的磁盘须要写入IO按照4K对齐的方式才能发挥最大性能,因此原先的4K+512B的索引格式已经没法使用,咱们也考虑过把512B的索引扩大到4K,但这样会致使索引占用空间过多,且写入时也会额外占用磁盘的带宽效率过低,因此最终经过将索引放到系统盘并结合上文提到的合并写入技术来解决该问题。
5. 性能扩展和提高
在第一代的IO加速技术中只能使用1块cache盘,当这块cache盘负载较高时就会影响系统的性能,在第二代IO加速中,咱们设计了支持多块cache盘,并按照系统负载按需插入的方式,使加速随机IO的能力随着盘数量的提高而提高。在本地cache盘以及网络cache盘都采用SATA机械磁盘的条件下,测试发现,随着使用的cache盘数量的增多,随机写的性能也获得了大幅度的提高。
在只使用一块本地cache盘时,随机写性能可达4.7W IOPS:
在使用一块本地cache盘加一块网络cache盘时,随机写性能可达9W IOPS:
在使用一块本地cache盘加两块网络cache盘时,随机写性能可达13.6W IOPS:
目前,咱们已经大规模部署应用了第二代IO加速技术的云主机。得益于上述设计,以前备受困扰的cache盘IO堆积过多、性能瓶颈等问题获得了极大的缓解,特别是IO堆积的问题,在第一代方案下,负载较高时常常触发并致使性能损失和运维开销,采用第二代IO加速技术后,该监控告警只有偶现的几例触发。
五.写在最后
云主机IO加速技术极大提高了机械盘随机写的处理能力,使得用户能够利用较低的价格知足业务需求。且该技术的本质并不仅仅在于对机械盘加速,更是使系统层面具有了一种能够把性能和所处的存储介质进行分离的能力,使得IO的性能并不受限于其所存储的介质。此外,一项底层技术在实际生产环境中的大规模应用,其设计很是关键,特别是版本热升级、容错以及性能考虑等都须要仔细斟酌。但愿本文能够帮助你们更好的理解底层技术的特色及应用,并在之后的设计中作出更好的改进。
— END —
即将于12/21举办的“UCloud用户大会暨TIC上海站”上,UCloud将和参会者一块儿探讨诸如云主机IO加速这样的产品设计理念、技术细节及将来发展等话题。欢迎点击下方二维码或者点击阅读原文进行报名,期待您的光临!