英雄所见略同:阿里云和XSKY如何实现应用无感的SDS升级?

简介: 如果说对运维人员最痛苦的事情是什么,莫过于生产系统的软件版本升级了。笔者就曾经历过某金融行业系统,因为跨大版本升级,不支持在线升级,而不得不协调多个部门,在数十个晚上通宵达旦,才完成几十套的软件升级,耗费的精力人力真是一言难尽 。而存储系统作为IT基础设施基座,长期稳定性和可靠性是关键。但是软件定义存储的好处是能够通过软件的更新迭代不断提升存储本身,因此 XSKY 在2016年便研发了基于"共享内存环"的热升级技术,分离了客户端存储访问接口和核心客户端功能实现,使得任何大版本升级都无需影响客户端运行,充分保证了生产系统既能享受可靠稳定的运行时,又能随时接受新版本的功能加强。

从一篇来自国人的优秀论文说起

USENIX ATC(USENIX Annual Technical Conference)是USENIX组织的技术年会,偏重系统设计与实现,是计算机系统领域具有最高学术地位的国际性会议之一, USENIX ATC每年录用70篇左右的论文,录用率在20%左右。在今年的USENIX ATC'20会议中,有一篇来自阿里云团队和上海交通大学新兴并行计算研究中心合作提交的论文 “Spool: Reliable Virtualized NVMe Storage Pool in Public Cloud Infrastructure”引起了笔者的兴趣。关于这篇论文,英文版地址在附录1,中文版地址在附录2, 读者可先行查阅。

仔细研读此文,笔者感同身受,对阿里云团队为解决这些复杂场景的问题而采取的种种努力也表示敬意。无独有偶,几年前,笔者所在团队也遇到过类似的问题,不同的是阿里云的应用场景是在公有云环境上,笔者遇到的是私有云环境上的问题,虽然大的场景有差距,解决方案也有区别,但总体解决思路还是比较类似的,并且都付出了艰苦的努力,才逐渐换来了现在产品的高性能,高可靠性和高可用性。

对于企业级生产系统,24(小时)×365(天)不间断运行是一个基本要求。而对于阿里公有云来说,尤其如此,现在阿里云上面已经运行了无数的关键企业应用,如文中所说 “我们目前在210个集群中部署Spool,大约20000台物理机,配备超过200000个NVMe SSD,提供低延迟、高IOPS和高吞吐量I/O支持的平台即服务云(IaaS)。生产中的云托管包括Cassandra、MongoDB、Cloudera和Redis等应用,是大数据、SQL、NoSQL数据库、数据仓库和大型事务数据库的理想选择”,对于这么多的应用系统,如果说升级软件,要不断中断客户业务的话,简直是不可想象的。

开源组件的局限性

我们先从技术的视角来探讨下论文中阿里云的Spool的架构,如下图所示

image.png

这是一个典型的linux下QEMU虚拟化框架。对于物理机上的若干NVMe盘,经过虚拟化后,再提供给QEMU下的Guest OS。在这个架构中,会用到比较多的开源组件,如SPDK用来管理NVMe盘,虚拟机和宿主机通过virtio和host来进行数据通信。如论文中所述,阿里云是4年前开始落地这个功能的,相信那时SPDK还并不是很稳定,那么经常性的更新,修正SPDK的bug就是一个常规需求了。

对于使用virtio框架的程序,必然要遵守virtio的一些规范,如该框架规定了前后端,virtqueue, 通信机制等。详细规范请参考附录3 。如下图,是guest和host数据交互的一般流程图。

image.png

GuestOS内的driver通过这个virtqueue与外边的Spool进行交互。这是一个很好的框架,但麻烦的是很多组件都用到它,不好在上面做定制化,比如更改它的一些核心数据结构。

正如论文中所述,guest和host之间是生产者-消费者模型,guest在有数据发送给host时,通过将描述符写入到descriptor table和available ring中,然后通知到host,host侧再从这个共享内存中取出信息,完成数据读写。

在没有论文中所述的Spool journal时,从guest发往host的IO请求在程序异常时,比如host侧的程序崩溃,或者SPDK,NVMe盘出现故障时,都有可能丢失那些“处理中的(Inflight)IO”。

image.png

比如上图中2处,IO1,IO2都被发送到NVMe设备,但NVMe设备尚未返回,这时SPDK软件出现故障了,则IO1,IO2的信息将可能完全丢失,guest可能不知道这些IO是否成功处理而造成潜在的数据不一致。

阿里云的解决方案

Spool journal的目的就在于能够保存这些Inflight IO的一些必要信息,以便于在后端故障恢复后,能够重新接着处理这些Inflight IO,保证IO运行的连续性,使Guest无感知。

原理上看很简单,但在实现的时候,却是布满陷阱。首先,程序运行时可能在代码的任意一行崩溃掉。因此,在设计上,这个journal应该是能够抗进程崩溃的,即虽然进程因为异常崩溃掉,但是journal不能丢失。其次,在新的进程启动后,要能认识这个journal,能恢复到崩溃前的一个一致性状态。最后,还要重试那些未完成的IO。

为了保存对应的journal信息,还会涉及到原子性保存,即记录journal时,不能在记录到一半的时候进程崩溃掉,而麻烦的地方在于journal信息可能会比较多,无法在一个指令中完成,所以论文中采用了一种特殊的方法,类似于RCU(Read,Copy and Update参见附录4)实现中的,先对一个副本变量进行修改,等到最后一步,才使用一个64位对齐的一次性原子操作,将journal信息记录下来。

可以看出,Spool journal是在线升级能够成功的关键因素,有了在线升级,则对于软件故障,基本上对于前端Guest业务是无感知的,软件会被快速重新拉起,继续处理IO。另外,文中介绍的Spool另外一个重要的作用是用于亚健康检测,比如检测到“坏盘”,则一般可以通过重新复位IO控制器解决,因为据统计,大部分IO读写错误其实不是真的磁盘损坏,而是IO通路上比如硬盘driver,IO控制器这样的一些中间组件出现故障,这时快速复位IO控制器会比“踢盘”来的更为聪明一些。

XSKY SDS遇到的问题

XSKY SDS是XSKY公司提供的私有云存储解决方案,在最初开发块存储的时候,也面临着同样的开源软件局限性问题,比如openstack在对接社区ceph版本时,至少在以下几方面存在着严重的问题:

虚拟机在打开ceph的卷时,每打开1个卷就会产生20多个线程,如果每个虚拟机打开10个卷,系统上有50个虚拟机,那么整个机器上就会有10000个线程,这对系统资源是一个极大的挑战。

虚拟机在打开ceph的卷时,实质上是要打开一个到ceph集群的网络通道,如果只打开1个网络通道,在某些情况下,如该卷是一个高性能卷时,单个网络通道又显得不够用,会成为瓶颈,需要打开多个网络通道才能完全把这个高性能卷驱动起来。

虚拟机在打开ceph的卷时,建立的和ceph集群的网络通道,并不具备应用层面的容错处理,即如果ceph集群进行升级,则那些Inflight IO可能会失去响应或者丢失,这样业务层就会出错,如果虚拟机的系统卷使用的也是ceph的卷时,则可能会引起虚拟机的挂死,无法恢复。即,开源ceph并不能很好的支持ceph软件的在线升级。

关于更多的细节内容,请参考附录5由XSKY在2017年发表的这篇文章的相关描述。

XSKY SDS的解决之道

笔者团队在2016年即开始解决上述问题,为了规约资源和在单卷下打开更多的网络通道,引入了XDC(XSKY DATA CLIENT)模块,其接管从开源librbd模块过来的所有命令,在XDC经过逻辑处理后,再发往XSKY SDS集群。并且在单卷的情况下,XDC还会按需打开多个通道,以提高单卷的读写性能。

而对于在线升级功能,巧合的是,和前面阿里云论文中所述的Spool Journal功能在原理上竟非常相似,都是采用进程间共享内存来管理,包括Inflight IO的状态保存,后端软件升级重启后的重发机制等。只不过实现机制不同,后文在描述实现原理时再详述。

image.png

如上图所示,对比开源Ceph实现,我们发现在性能上,XSKY SDS实现了:

单客户端4K随机写IOPS提升20%;

客户端IO延迟降低15%;

每节点CPU利用率降低40%;

每节点存储部分内存使用减少2/3;

完全满足最初的开发需求。

XSKY SDS 代理转发实现原理

与阿里云环境不同的是,我们的场景是使用QEMU下的RBD协议,将XDC提供的卷映射给Guest OS,这个卷实质上是一个逻辑上的网络卷,由XSKY SDS集群通过网络提供。

image.png

rbd driver通过librbd.so访问XSKY SDS提供的rbd设备,在开源社区版本中,librbd.so是直接访问ceph集群的,而我们则在librbd里面提供了代理转发逻辑,将多个卷打开通道的命令全部转发到XDC模块,由XDC按需打开一定的通道,从而减少CPU和内存资源,提高性能。

image.png

由于我们提供的是增强版的librbd.so,而这个库是链接到qemu进程的,我们并不需要更改qemu的核心代码,所有的逻辑都可以在librbd.so内部实现。为此,我们实现了qemu进程和XDC进程间的共享内存,在qemu进程启动的时候,我们会在librbd.so内部申请一定的内存,比如申请32M的空间,然后将这32M内存分配成mailbox头部,命令区,数据区。命令区按照规格预先分配好,比如命令队列是1024个,那么就最多能同时处理1024个命令,数据区则设计为可以动态增长。这段共享内存由librbd.so侧负责申请,然后映射到XDC侧。

image.png

使用这样的方法,所有的Inflight IO都是天然存在于共享内存中的,只要Guest不死机,所有的命令都存在,而如果Guest死机了,那命令自然也就没有存在的必要了。所以我们这个共享环已经兼具了前面Spool journal的属性了。

Guest在需要写入数据时,会首先使用librbd.so 将待写入的命令描述符填入CMD entry区,数据部分会写入到DATA区,最后再更新mailbox的 head和tail索引,再通过事件通知机制激活XDC侧的处理。

XDC侧则会根据mailbox的信息,获取对应的CMD entry,然后进行处理,处理完后再更新CMD entry的状态信息,再通知到librbd侧,librbd再进行后续IO完成处理流程。

下面给出一个简单的交互流程图,当然具体的产品化代码比这个要复杂的多。

image.png

对于最重要的在线升级功能,比如XDC升级,后端XSKY SDS升级等,我们是让XDC重启后,能够认识到之前的共享内存的,这里的技巧在于我们使用了PIPE FD,而这些FD是存在于虚拟内存文件系统之上的,当XDC重启后,通过这些FD来重建事件通知通道,进而在后续的事件通知中再交换之前的如共享内存地址等相关信息。等所有通道,共享内存都准备就绪后,librbd侧会重试之前未完成的IO。

有了这样的分离设计后,我们把librbd.so 称作head部分,而把XDC及其后边的整个XSKY SDS称作body部分,除了head不能在线升级外,整个body部分都是可以在线升级的。当然在线升级作为一个系统化工程,head除了设计稳定的接口不需要经常性的升级外,还是可以在需要的时候通过虚拟机迁移完成不中断业务的在线升级的。目前使用librbd proxy功能的XSKY SDS软件在生产系统上已经部署上万节点,运行4年多来,经历过多次如安全补丁修复,高级功能增强等,都是不需要停止业务系统直接动态升级,用户无感知的。

结语

在现代企业级存储系统中,关键业务系统对于在线升级要求是极高的,必须提供24*365的服务时间。软件系统在设计开发中,必须优先考虑能够无中断的提供高可靠,高可用性服务。同为企业级软件,XSKY SDS和阿里云系统都能提供这样的特性,其主要异同点在于:

阿里云将本地的NVMe设备通过Spool虚拟化后提供给虚拟机,而XSKY SDS则是通过RBD协议将集群内的逻辑虚拟卷使用XDC/librbd proxy技术提供给虚拟机。

Spool的开发在QEMU的virtio/virtio-blk/virtqueue框架下进行,受制于框架的约束,不得不在Spool侧实现较为复杂的journal,并且需要实现原子事务更新等机制。而librbd proxy则是基于librbd库进行,其共享内存机制可以完全独立实现,包括共享内存的分配,格式组织,通信协议等,可以实现的更为轻量级和高效。相较而言,Spool更为通用一些,而librbd proxy则更为轻量一些,两者殊途同归,有异曲同工之妙,却并无优劣之分。

两者都能提供毫秒级别的在线升级功能,Spool需要处理的是SPDK的耗时升级逻辑,而librbd proxy更多的是考虑网络层面的升级逻辑,如后端XSKY SDS整体软件的升级。两者都能处理如后端软件崩溃即时拉起功能,并能自动恢复,重发IO请求,做到业务无感知.

两者都经过长时间大规模的核心业务生产考验,阿里云在公有云系统上部署超过200多套集群20000多台的物理节点,而XSKY SDS也在私有云存储上经过长达4年部署上万物理节点的考验,证明这种方法确实是稳定可靠的。当然笔者也希望看到更多的优秀解决方案产生,如果读者有类似的应用场景和更好的解决方案,也欢迎留言讨论,以期望提高行业整体技术水平,更好的为客户服务。

附录

附录1:https://www.usenix.org/conference/atc20/presentation/xue

附录2:https://kernel.taobao.org/2020/07/solves-large-scale-high-performance-storage-reliability-problems

附录3:https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html

附录4:https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html

附录5:https://www.xsky.com/news/5112/

作者:XSKY融合存储
原文链接:https://mp.weixin.qq.com/s/lCj0zgi6RILu_wufz68Oeg

相关文章
|
2月前
|
缓存 物联网 数据库
如何帮助我们改造升级原有架构——基于TDengine 平台
一、简介 TDengine 核心是一款高性能、集群开源、云原生的时序数据库(Time Series Database,TSDB),专为物联网IoT平台、工业互联网、电力、IT 运维等场景设计并优化,具有极强的弹性伸缩能力。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一个高性能、分布式的物联网IoT、工业大数据平台。 二、TDengine 功能与组件 TDengine 社区版是一开源版本,采用的是 AGPL 许可证,它具备高效处理时序数据所需要的所有功能,包括: SQL 写入、无模式写入和通过第三方工具写入 S标准 SQL 查
79 13
|
3月前
|
物联网 区块链
应用多活技术问题之企业利用应用多活技术进行稳定性能力扩展如何解决
应用多活技术问题之企业利用应用多活技术进行稳定性能力扩展如何解决
|
4月前
|
缓存 人工智能
通用研发提效问题之女娲的缓存方案,体现易用性的四重境界,如何解决
通用研发提效问题之女娲的缓存方案,体现易用性的四重境界,如何解决
|
6月前
|
存储 Cloud Native 对象存储
AutoMQ:基于阿里云计算与存储产品实现云原生架构升级
AutoMQ[1] 是新一代基于共享存储架构实现的云原生 Kafka。得益于其存算分离的共享存储架构,通过和阿里云合作,深度使用阿里云可靠、先进的云服务如对象存储OSS、块存储 ESSD、弹性伸缩ESS以及抢占式实例实现了相比 Apache Kafka 10倍的成本优势并且提供了自动弹性的能力。
84319 26
AutoMQ:基于阿里云计算与存储产品实现云原生架构升级
|
6月前
|
存储 弹性计算 Cloud Native
AutoMQ:如何基于阿里云计算与存储产品实现云原生架构升级
AutoMQ:如何基于阿里云计算与存储产品实现云原生架构升级
|
人工智能 Kubernetes Cloud Native
【热点追踪】从价值到架构,走近全新升级的阿里云 Serverless 容器服务 ASK
【热点追踪】从价值到架构,走近全新升级的阿里云 Serverless 容器服务 ASK
|
存储 运维 监控
带你读《云存储应用白皮书》之34:7、可观测运维解决方案
带你读《云存储应用白皮书》之34:7、可观测运维解决方案
196 0
|
消息中间件 缓存 运维
“解密数据隔离方案,让SaaS应用开发更轻松”技术分享
相信有不少朋友都已经了解到SaaS多租户模式,帮助企业选择合适的SaaS系统匹配企业的客户和业务特点。如:独享资源模式、全共享模式、数据层共享模式等。此时,我们往往会遇到不同租户间的数据隔离问题,如何正确的进行数据路由,才能保证租户的数据隔离。在SaaS应用开发时应用层和数据层的租户路由设计以及实现方面,我们会遇到几种情况:当租户独享应用层和数据层时,这个时候租户的数据是天然隔离的,不会被其他租户影响,此时是不需要路由的;当多个租户涉及到应用层和数据层的资源共享的时候,就需要对租户的数据进行隔离,不管是应用层共享或者数据层共享,还是数据层和应用层都存在共享,正确的数据路由才能保证租户隔离。
977 0
“解密数据隔离方案,让SaaS应用开发更轻松”技术分享
|
运维 容灾 Cloud Native
我们如何实现“业务 100% 云原生化,让阿里中间件全面升级到公共云架构”?
在今年的天猫双 11 中,中间件支撑了 5403 亿的交易量,并全面升级到了公共云架构。 此次的架构升级,是以开源为内核、以公共云为基础、以 OpenAPI 进行解偶扩展,在架构上,对开源、自研、商业化进行统一。通过采用和反哺开源、推动社区建设,通过阿里巴巴丰富的业务场景、打磨技术的性能和可用性,通过云上商业化服务更多企业、打造更好的用户体验,全方位锤炼云上产品的竞争力。
939 4
我们如何实现“业务 100% 云原生化,让阿里中间件全面升级到公共云架构”?
|
SQL 存储 监控
直击阿里新一代数据库技术:如何实现极致弹性能力?
张瑞,阿里巴巴研究员,阿里集团数据库技术团队负责人,经历阿里数据库技术变革历程,连续六年作为数据库总负责人参与双11备战工作。今天,我们邀请他来分享新一代数据库技术在双11中的应用。
8728 0
下一篇
无影云桌面