note:网上有很多关于软件定义存储的负面消息。有人说,在存储发展的历史中,存储早就不仅仅是硬件了,软件在存储中有一个核心的地位;还有人觉得应该做软件隐藏的存储,因为软件这个事让存储的管理变得很难,这些软件包括:重复数据删除,自动精简配置等;也有些人说,我们并不需要更多的软件,我们需要看到的是更少的软件;也有人说,存储本来就是软件定义的,所有的存储都需要软件;尤其是当存储成为分享资源时(大数据和数据中心的存储),往往会被复杂而神秘的软件包围。很多人说,每次更新系统时,就会增加越来越多的存储软件,从快照到复制再到自动精简配置等。
而当我怀着不太乐观的情绪,看了IOFlow论文[1]的摘要的时候,特别惊喜。对于上面所有的对于软件定义存储的疑惑都通通打消了。
在现在的数据中心中,应用程序到存储设备的I/O路径都特别长,其中包括很多的层次或者说是stages,具体是怎样的可以点击这里,而且这些层次之间的接口还是不透明的(就像隧道),这使得要enforce一个end-to-end的policy (比如对于不同的tenant,需要不同的存储带宽,比如热数据和冷数据,比如存储服务的不同等级的客户)很难(相对于软件定义网络的控制逻辑而言,因为网络包的头部很好处理)。相对于SDN的OpenFlow,这里设计了IOFlow,在hypervisor阶段和storage server阶段进行实施。
break:对疑问的解释是,IOFlow不是单纯的增加软件,而是用软件去管理不透明的软件和硬件,从而实现管理和监控,看到的软件当然也就更少了(只有控制器的程序,还可以方便的监控)。而且更新系统的时候,这些存储软件根本就不需要更新啦,逻辑都在控制器上。
但是既然是软件定义存储,肯定有数据平面,控制器,然后有控制器的应用程序。那么问题来了,他们各自的作用是什么?然后是怎么交互的?下面将给出详细的阐述。
在软件定义存储里,这数据平面跟软件定义网络的数据平面又不一样,在存储领域,这数据平面是一层层的,很深;而在软件定义网络里面,数据平面是plate的,很广(转发路由的算法多)。
IOFlow把数据平面称为stage,根据queues和排队规则来implement traffic流量的区别。(和SDN的 flow table不一样,flow table需要根据流规则来转发)。排队规则将不同头部(原地址(比如VM ID)和目的地址(比如shared storage的ID))的I/O请求映射到不同的队列上面,然后根据要求配置队列的属性。这样,这些队列便可以通过service 特性来控制队列处理过程的速度,然后使用route特性来引导I/O请求到下一个stage。
首先,控制器的discovery组件使用getqueueinfo来获得这个stage是哪种io头部stage(比如说是网络头部呢,还是smb头部呢),然后控制器可以使用createqueuerule来创建排队规则,把到来的IO packets分配给这个stage的queues。然后就可以配置队列的路由和速度属性了。
note:在这些层次化的模块之间进行转发和管理有点太不可思议,层次化的模块本来就环环相扣,谁也少不了谁,怎么转发本来就都已经是确定了的。所以这里Control功能只是更精确的控制转发速度以及为了安全特性而设置的route功能。
note:IOFlow是微软做的,不开源。IOFlow的虚拟存储是基于virtual disk的,但是我想用的fcoe的虚拟化的层次不是基于virtual disk 的,而是vm-based的,所以基于这种情况的存储stage是不一样的。
虽然stage的原理大概能够说清楚了,但是如果要是问怎么控制流速?服务特性除了流速还有什么,分别采用什么机制来进行控制?怎么控制路由?你能不能举个例子?在stage部分还有没有什么特殊处理?下面一一解答。
要怎么控制流速呢?在stage阶段是采用一种叫做token bucket的机制。令牌环的工作原理是,信息帧在传输时,如果有足够的令牌就能够传输,否则不能(在这里,token多代表更高的带宽,少则代表更低的速率)。队列的速度也是按照令牌的速率。然而存储的请求和网络packets不同,所以令牌环的设计也不同。对于网络packets,一个byte就代表一个令牌环,对于存储而言,因为不同的请求,read,write和create等的处理方式都不一样,所以令牌环的设计要基于tenant的requests,令牌环要根据请求的不同来设计。然而他们之间也不是线性关系,因为在存储的backend,每种请求的处理时间又和请求大小,数据局部性以及设备类型相关,所以为了测量io请求的开销,控制器还是做了很多其他的事情的。当把这个测量出来之后,控制器再调用API配置stage的queue的令牌数。这种配置每隔一段时间更新一次。
除了用令牌环控制流速,还需要使用priority特性来配置每个队列,对于特殊的队列给特殊的优先级。然后还通过queue size 这个参数来配置队列的长度,这样可以使得请求拥塞,给后端造成压力。
那么stage又是怎么控制路由的呢?就像note中顾虑的那样,由于stage是那种层层依赖的关系,queue当然会有一个默认的下一跳。但是也可以控制去让它走不同的路线。比如说让从不被信任的vm出来的io流进入malware scanning stage。
举个例子,比如对于一个tenant租户,他所有的虚拟机跨越10个hypervisor,这几个虚拟机共同访问某个存储服务器,这个时候控制器可以通过在每个hypervisor处节流来达到更大的并行性,而不是在存储服务器端节流(这样可能会引起竞争)。
需要特殊考虑的情况?比如说在SMBc stage将大io请求(可能不好确定io性能,影响token的准确性)分解为小io请求。
软件定义存储的控制器要控制的内容是和存储相关的,存储在乎的是带宽保证,而是否能够到达目的地这个并不难,因为存储网络看起来比较简单,不像是网络的路由是那么复杂的拓扑结构,往往将导致非常复杂的路由算法。
在软件定义的存储领域,Controller有两个主要的作用,一是和上面的Control 应用程序交互,另外一方面是和数据平面交互,控制数据平面。在这里控制器的作用主要是表现在发现数据中心的stages,然后和他们进行交互,并且维护一张全局的stage graph拓扑结构。然后他将这个拓扑和每个stage的信息告知上层的控制应用程序。这些Control应用程序,是和sdn领域里面的控制逻辑比如hub或者l2 switching在一个层面上。
在这篇论文里面,主要提到了两种类型的应用程序。一个是性能控制的应用程序,另外一个是Malware Scanning middlebox。Malware Scanning middlebox是基于这样的一个前提,认为有些Flow是trusted,而另外有些是untrusted。所以对于untrusted的flow,就让他们进入这个malware scanning middlebox进行检测,如果检测发现他们是可以被信任的,再让他们路由到其他的stages(否则可能被丢弃)。Controller使用API configureQueueRouting(使得进入malware scanning middlebox)来处理untrusted虚拟机发出的流。对于一般的情形,关心的更多的是性能,也就要用到性能控制的应用程序了。
性能控制主要是包括minBandwidth或者exactBandwidth。性能控制的应用程序应该可以看到他需要的一张子图。控制器要做的就是给子图中的任何一个个队列配置某个合适的带宽。
比如说对于上面的左边的图,这种复杂的情形,首先要保证这个带宽是可以保证的,然后可能要用到右边的算法来保证带宽(文章中有具体的说明),配置队列的属性。
比起在软件定义网络里面的那些个情形,比如hub,那个逻辑基本是算比较简单的了,第二层的学习也还算是比较复杂,若是FCOE的转发逻辑(曾经分析过)那是相当的复杂,这么比较一番,SDS的控制程序逻辑算是很容易。Control application似乎没有那么宽广的使用空间(比如hub, l2 switching,或者fcoe路由),它只是数据中心的一个tenant的控制程序。
note: 通过上面的Control application,估计对控制器的理解也更加深入了,但是软件定义网络的控制器有很多种实现版本,比如NOX,POX,以及FLOODLIGHT。但是这里微软的IOFlow不开源,估计也就只有微软版的控制器啦。然后这个控制器提供一套API和控制应用程序交互。
p.s.犯懒了,关于功能评价和可扩展性和性能的评价不写了,总的一句话就是功能很好,效果很显著,但是可扩展性问题值得担忧。感兴趣的还是自己分析原论文吧~~
[1]Eno Thereska, Hitesh Ballani, Greg O'Shea, Thomas Karagiannis, Ant Rowstron, Tom Talpey, Richard Black, and Timothy Zhu,IOFlow: A SoftwareDefined Storage Architecture,SOSP'13,November 2013