MultiLanes: Providing Virtualized Storage for OS-level Virtualization on Many Cores

来源:互联网 发布:安卓手机运行windows 编辑:程序博客网 时间:2024/06/11 10:23

摘要
操作系统级虚拟化是一种实现服务器整合的有效方法。但是在虚拟环境中对内核服务的共享,尤其是I/O堆栈的共享使得在多核平台上性能严重下降。本文提出了一种叫做MultiLanes的方法,在多核平台上操作系统级虚拟化实现的虚拟存储系统。在MultiLanes中,通过在每个虚拟环境中各自的虚拟存储设备之上建立隔离的I/O堆栈来消除各个虚拟环境对数据结构锁等的竞争,从而更好的扩展多核上。除了扩展性等,MultiLanes也为VEs提供了更好的灵活性和安全性。
3.3 设计组件
MultiLanes为每一个Container提供一个相互隔离的I/O堆栈,希望以此来消除Container之间的性能干扰。每个Container包括以下组件:虚拟存储设备、虚拟块设备驱动以及分区虚拟文件系统(pVFS)。
3.3.1 虚拟化存储
和传统的全虚拟化或半虚拟化为虚拟机提供虚拟存储设备相比,操作系统级虚拟化为了I/O效率直接将虚拟机的数据存放在主机文件系统中。虚拟化存储在共享存储性能隔离中具有天生的优势,这是因为每一个虚拟机具有一个隔离的I/O堆栈。
在共享I/O堆栈中,对共享数据结构以及锁的竞争,使得性能严重受到影响。在传统的存储系统中,由于缓慢机械硬盘的高延迟而被忽略,但是在新兴高速存储技术的使用中,就成为性能瓶颈。
为了消除在多核存储系统中Container之间的性能干扰,方案为每个Container提供了一个轻量级的虚拟存储。通过将一个普通的文件映射为Container中的一个虚拟块设备来实现。在系统创建文件时,主机并没有预先给文件分配文件大小的空间。其中带来的挑战是对性能隔离带了的性能和存储虚拟化导致的开销进行平衡。但是,通过对虚拟存储架构的有效设计可获得良好的扩展性和性能。
3.3.2 驱动模型
和其他的虚拟化方案一样,虚拟化的主要工作就是建立物理资源与虚拟资源之间的映射关系。在MultiLanes中,该工作是由虚拟块设备驱动实现的。
块转换:
采用了和处理CPU缓存不命中相似的方法,处理请求块不命中,即遇到不命中块时,使用转换线程,转换线程使用主机文件系统的提供的映射接口获得相应的物理块号,同时预取其后特定数目的连续的物理块号与逻辑块号之间的映射填充到cache table中。
主机文件系统中块映射需要涉及文件系统日志,因此,如果多个虚拟驱动同时发生不命中的时候,主机中映射过程可能引起严重的资源竞争,进而使得虚拟设备的扩展性比较差。通过将转换线程限制在一小组核上来减少竞争,在主机文件系统中提高数据的局部性。
请求处理:由于连续的逻辑块区域对应的物理块不是连续的,所以一个队虚拟块设备的请求可能根据相应物理块的连续性被重新映射为多个新的I/O请求。通过提供I/O completion callback来判断何时全部完成了原始I/O请求。
3.3.3 Partitioned VFS
在Linux中VFS为应用程序访问不同类型的文件系统提供了一个统一的通用文件系统接口。尽管MultiLanes允许每个Container中独立地运行各自的文件系统,但是在VFS层相互之间仍会有性能干扰。因此,文中提出了partitioned VFS, pVFS为每一个Container提供了一个私有的VFS抽象,以此来消除在VFS层各个Container对共享数据结构的争夺。
MultiLanes为每个Container分配一个索引结点哈希表和一个目录项哈希表。通过对在VFS中可能引起竞争的资源的划分,使得VFS数据结构和锁在每个Container中都是本地化的。pVFS是对隔离I/O堆栈的重要补充部分。
4 部署实现
我们选择实现MultiLanes的原型为Linux Container(LXC),不使用OpenVZ或者Linux-VServer,是因为OpenVZ和Linux-VServer需要定制适应的内核,而LXC总是支持最新的Linux内核。我们部署的MultiLanes原型使用的是Linux 3.8.2内核,该内核中有虚拟块设备驱动模块,并且适应VFS。
4.1 驱动实现
驱动主要完成以下两个功能:接收来建立虚拟资源与物理资源之间的映射关系;将客户机文件系统的I/O请求,将其转换为主机块设备请求。为实现这两个功能文章设计了两个模块:Block Translation 块转换、Request Handling 请求处理。
4.1.1 Block Translation 块转换
块中包含以下三个部件:
Cache Table(缓存表):维护逻辑块和物理块之间的映射。
Job Queue(任务队列):用于存放在缓存表中未命中的逻辑块,等待转换线程的处理 。
Translation Thread(转换线程):调用主机文件系统提供的映射程序接口完成逻辑块号到物理块号的映射,并存放到缓存表中。 这里写图片描述
当驱动程序接收到一个I/O请求,首先驱动程序根据请求中的逻辑块号查询缓存表,如果在缓存表中命中,则直接从缓存表中获得相应的物理块号。如果未命中,则启动缓存不命中事件并休眠Container线程。缓存不命中线程从任务队列中取得转换任务并启动转换线程,然后转换线程调用主机文件系统提供的映射程序接口获得逻辑块号与物理块号之间的映射关系,并将映射关系存放到缓存表中,最后转换完成唤醒Container线程。
如果启动一次转换线程只完成一个未命中块映射,将导致缓存命中率较高,线程切换频繁使得CPU资源浪费以及相当大的交互开销,从而使得块转换组件效率相当不好。因此,这里采用的预取机制,即每次启动转换线程,则获取目标块及其以后连续的一定数目块的映射关系。
由于块映射需要主机系统的的参与,所以如果多个Container同时发生不命中开始块映射线程则会引起严重的资源竞争。为改善该问题,我们将转换线程约束到一组核心上处理,以此来减少冲突,提高主机文件系统的数据局部性。
4.1.2 Request Handling 请求处理
由于I/O请求中即使逻辑块号是连续的,其对应的主机中的块编号也不一定连续,因此需要Request Handling对此进行处理。
处理过程是这样的:首先通过块转换组件获得并将I/O请求中每个逻辑块号转换成其对应的物理块,在所有块完成映射之后,将会对所有的物理块进行连续性检查。驱动程序将连续块号的请求合并成为一个新的I/O请求。同时也为不连续的块分别创建新的请求。
这里写图片描述
如图,假设页大小为4KB,块大小为4KB,一个I/O请求的数据大小为16KB,故需要4页,4个块。通过块转换获得每个块对应的物理块号,完成逻辑块到物理块的映射。有图我们可知 逻辑块19对应物理块1673,逻辑块20对应物理块1674,逻辑块21对应物理块1688,逻辑块22对应物理块1906。由于物理块1673和1674是连续的,故将这两个合并为一个I/O请求。故该请求对应于主机中的3个I/O请求。因此,通过对客户机I/O请求的转换可能获得不止一个的主机I/O请求。因此,这为如何判断一个原始的I/O请求是否处理完成带来困难。这里我们通过使用I/O Completion Callback对完成的I/O请求进行记录,当对应的所有I/O请求完成时,原始I/O请求完成,主机驱动终止改I/O请求。
6 Conclusions
本文针对操作系统级虚拟化中因共享内核服务导致资源竞争,性能下降的问题,提出了为每个虚拟环境设置一个包含pVFS和虚拟存储设备的隔离的I/O堆栈.
实验是在多个文件系统独立工作,共享几乎为零的前提下进行的,所以在共享相同线程池的文件系统中虚拟环境之间可能还会存储在性能干扰。

0 0
原创粉丝点击