Cinder
OpenStack集群中的存储通常分为块存储、对象存储和文件系统存储。
简单而言,块存储就是通过 SAN或iSCSI 等存储协议将存储设备端的卷(Volume)挂载到虚拟机上并进行分区和格式化,然后挂载到本地文件系统使用的存储实现方式;而文件系统存储就则是通过NFS 或CIFS (Samba)等网络文件系统协议将远程文件系统挂载到本地系统使用的存储实现方式;相对而言,对象存储在实现和使用方式上与块存储和文件系统存储都不同,对象存储是一种以REST API方式提供数据访问的存储实现方式。
在OpenStack 中,块存储是使用最多的数据存储实现方式,并且由 Cinder 项目提供,Cinder 是 OpenStack 集群中提供块存储服务的独立项目,其前身为Nova 项目中的Nova-Volume子项目,并在 OpenStack的F版本后独立成为 OpenStack的核心项目。
Cinder支持不同形式的多种后端存储驱动,用户只需选择 Cinder块存储驱动所支持的存储后端即可。通常情况下,为了提高整体的读写IO,实例应用程序通过块存储设备驱动直接访问底层硬件存储块设备,不过 Cinder也支持使用文件系统来模拟创建 Volumes并挂载到实例供应用程序访问,如NFS和 GlusterFS存储后端便是基于文件系统的块存储实现的。
由于 Cinder项目以存储Driver插件的形式来管理不同的存储后端实现(Cinder 与 Neutron类似,都被设计为可插拔架构),很多存储厂商都实现了统一的Cinder存储Driver接口,如IBM、EMC、Netapp、HPE、Hitachi 和华为等很多存储厂商都不同程度地实现了对Cinder后端存储的支持。
在 OpenStack 中,块存储服务Cinder 为 Nova 项目所实现的虚拟机实例提供了数据持久性的存储服务。此外,块存储还提供了 Volumes管理的基础架构,同时还负责Volumes的快照和类型管理。从功能层面来看,Cinder 以插件架构的形式为各种存储后端提供了统一 API访问接口的抽象层实现,使得存储客户端可以通过统一的API访问不同的存储资源,而不用担心底层各式各样的存储驱动。Cinder提供的块存储通常以存储卷的形式挂载到虚拟机后才能使用,目前一个Volume同时只能挂载到一个虚拟机,但是不同的时刻可以挂载到不同的虚拟机,因此 Cinder 块存储与AWS 的 EBS不同,不能像EBS 一样提供共享存储解决方案。除了挂载到虚拟机作为块存储使用外,用户还可以将系统镜像写人块存储并从加载有镜像的 Volume启动系统(SAN BOOT)。
Cinder块存储服务主要由以下几部分组成。
Cinder-api: Cinder-api 是一种WSIG类型的应用服务,其主要负责接收来自 Horizon或命令行客户端的块存储API请求,同时负责请求客户端的身份信息验证(通过Keystone项目实现)。Cinder-api 接收到客户端请求后,根据 Cinder-scheduler 的存储后端调度结果,将请求API路由到运行Cinder-volume服务的对应后端存储上
Cinder-scheduler:与Nova一scheduler 的功能类似,Cinder-scheduler 是 Cinder项目的后端Volumes服务调度器,当Cinder-api 接收到客户端请求后,将由 Cinder-scheduler 服务来负责API的路由。根据用户配置的 Scheduler 策略,Cinder-api请求可以采用形如 Round一robin的轮询方式路由到运行Volume服务的各个存储节点,也可以采用FilterScheduler 来实现更为复杂和智能的后端存储节点过滤策略。在Cinder的配置中,FilterScheduler 是默认设置,通过FilterScheduler的配置可以实现基于 Capacity、Availability Zone、Volume Types、Capabilities 或者用户自定义过滤策略的后端存储节点调度。
Cinder-volume: Cinder-volume 是 Cinder项目中真正提供块存储和不同存储驱动插件管理的服务,不论节点处于什么角色,只要其运行Cinder-volume服务,该节点均可称为存储节点。Cinder-volume服务通过AMQP与 Cinder-scheduler进行交互,将其所管理的各个存储驱动后端的运行、性能和容量等参数实时传递到Cinder-scheduler,以便 Cinder-scheduler 根据这些参数进行存储节点的调度。此外,Cinder-volume通过 Driver架构实现与不同存储驱动后端的交互。
Cinder-backup: Cinder-backup 为块存储卷(Volumes)提供了备份服务,要实现Volumes的备份,需要提供备份存储驱动的实现,目前比较常见的备份存储后端由Swift提供。与Cinder-volume类似,Cinder-backup也通过Driver 插件架构的形式与不同的存储备份后端交互。
消息队列:Cinder 项目的不同内部服务组件之间通过 Queue进行消息交互,如Cinder-volume与 Cinder-scheduler之间的信息交互。Cinder 项目内部各个服务之间的消息交互如图10一1所示。


Cinder项目的整体架构如图10一2所示,图形界面客户端或命令行客户端通过 Horizon与 Cinder-api服务交互,Cinder-api通过 Keystone实现客户端身份验证,Cinder-volume通过Driver插件形式管理各种 Volume Providers存储后端,并将 Volumes 相关的消息写人DB进行保存。
Cinder提供了不同存储后端的抽象统一接口,通过Cinder 项目,用户可以将不同的存储后端整合在一起并通过统一的OpenStack API接口对外提供存储资源服务。
而Cinder块存储最常见的使用方式便是在不同的存储后端上创建Volumes,并将 Volumes挂载到虚拟机上以块存储的形式提供存储服务。此外,为了实现虚拟机的高可用,通常也将系统镜像写人Cinder块存储,使其成为 Bootable Volume,从而可以在虚拟机宿主服务器故障的情况下在其他物理主机上迅速重启位于故障物理机上的虚拟机。(当用户将系统镜像写人Volume之后,此Volume成为 Bootable Volume,用户可利用 Bootable Volume创建虚拟机。)
功能:
在 Cinder提供的功能中,创建、扩展、删除、Attach 和 Detach 是最核心的功能,也是块存储工作过程中最常使用的功能。其他如快照创建和基于镜像的 Volume创建也是比较重要的功能。快照功能使得虚机系统的复制变得非常简单,基于镜像的Volume创建可以实现 SAN BOOT功能,而这使得虚机在线迁移变得更为简单(无须配置类似NFS共享文件系统即可实现live-migration)。


volume的生命周期
通常而言,Cinder 块存储提供的Volume总是与Nova虚拟机的生命周期密切关联在一起,如在虚拟机的创建时,对应着也要创建Volume并将 Volume 挂载到虚拟机。在虚拟机的运行过程中,随着业务数据的增加,可能需要对 Volume 进行扩容或者对主要数据进行快照保存,而在虚拟机被终止或销毁时,对应的Volume将会被卸载。卸载并不意味着 Volume上的数据会丢失,而只有在删除 Volume 后其上的数据才会丢失。用户可以将卸载后的Volume 挂载到其他虚拟机并继续访问其上的数据。

Cinder 项目中的 Cinder-Volume服务通过插件式(Plugins)的 Driver与各种后端 VolumeProviders 进行交互,从而屏蔽了后端各种开源或商业的存储实现方式,并对外提供统一的Cinder API 接口。Cinder项目在架构上与Neutron类似,均是采用可插拔的插件来兼容各个厂商的存储设备和驱动,从而使得各个存储厂商均可参与Cinder 项目并提供自己的存储插件供用户使用,而用户也可以自主选择适合自己的存储产品,并只需在 Cinder的配置文件中进行适当的存储Driver设置即可。
在 Cinder中, Cinder volume为不同的 Volume后端( Volume Providers,通常为不同厂商的存储设备)提供了统一的 Driver接口,而 Volume Provider只需实现这些接口即可。当存储设备厂商基于自己的设备实现了这些 Driver接口后,购买了相应厂商存储设备的用户便可通过这些插件在Cinder中使用厂商存储。

在LVM插件架构中,Volumes 以VG的LV形式被创建,即用户在配置Cinder块存储和创建Volumes之前,需要在存储节点上创建卷组VG,并在配置文件中指定使用此VG进行 Volumes创建源。此外,计算节点与存储节点之间的存储网络通过iSCSI协议实现,运行虚拟机的计算节点作为iSCSI的发起端(iSCSI Initiator),而运行 Cinder-Volume的存储节点作为 iSCSI的目标端(iSCSI Target),用户通过Cinder一API创建的每个Volume 对应的都是存储节点中VG上的一个逻辑卷LV,当用户发起 Attach (或Detach)操作时,存储节点上的Volumes 通过iSCSI协议自动挂载到计算节点虚拟机上(或从计算节点虚拟机上卸载)。在基于LVM 的 Cinder创建架构中,Volume 操作完全由 LVM 来实现,此外,全部计算节点虚拟机上的I/O通过软件iSCSI协议集中传输到存储节点,因此采用 LVM 插件实现的 Cinder块存储比较适合轻负载I/O应用场景,而且由于全部虚拟机的读写I/O通过软件iSCSI协议汇聚至存储节点,这很容易造成存储节点的I/O性能瓶颈。不过使用 LVM插件的优势在于无须特定存储设备和对应插件的支持,任何存储设备都可以映射到存储节点Linux系统中,并通过LVM插件架构实现 Cinder块存储服务。

缺点:
由于LVM插件部署和使用简单,而且适用于不同的物理或虚拟存储设备,因此 LVM插件是 OpenStack官方 Cinder 部署文档指定的默认插件,但是基于LVM插件的Cinder块存储服务功能完全基于软件仿真来实现,因此仅适用于开发和测试等轻量级系统环境中。而在高并发 I/O的生产环境中,基于LVM的 Cinder 服务并不具备高可用性和稳定性,尤其是Cinder-Volume服务在高可用实现方面一直是个难点。此外,由于虚拟机的I/O数据全部通过以太网络写人存储节点,因此存储节点的性能和带宽限制很容易造成存储I/O瓶颈。
Volume到计算节点虚拟机的挂载通过软件iSCSI实现。而其不足之处在于虚拟机I/O不能像FC插件一样直接写人存储设备,因此一旦Cinder-Volume 或 iSCSITarget 端服务故障,则虚拟机到存储节点的I/O将会停止,虚拟机也有可能崩溃,并且整个集群存储网络的带宽会受到运行Cinder-Volume服务存储节点的带宽限制。
下图展示了 cinder、nova 是如何与 NFS volume provider 协调工作的。

NFS Volume Provider
就是我们通常说的 NFS Server,提供远程 NFS 目录,NFS Clinet 可以 mount 这些远程目录到本地,然后像使用本地目录一样创建、读写文件以及子目录。
cinder-volume
存储节点通过 NFS driver 管理 NFS volume provider 中的 volume,这些 volume 在 NFS 中实际上是一个个文件。
nova-compute
计算节点将 NFS volume provider 存放 volume 的目录 mount 到本地,然后将 volume 文件作为虚拟硬盘映射给 instance。
这里有几点需要强调:
- 在 Cinder 的 driver 架构中,运行 cinder-volume 的存储节点和 Volume Provider 可以是完全独立的两个实体。 cinder-volume 通过 driver 与 Volume Provider 通信,控制和管理 volume。
- Instance 读写 volume 时,数据流不需要经过存储节点,而是直接对 Volume Provider 中的 volume 进行读写。 正如上图所示,存储节点与 NFS Volume Provider 的连接只用作 volume 的管理和控制(绿色连线);真正的数据读写,是通过计算节点和 NFS Volume Proiver 之间的连接完成的(紫色连线)。这种设计减少了中间环节,存储节点不直接参与数据传输,保证了读写效率。
- 其他 Volume Provider(例如 ceph,swift,商业存储等)均遵循这种控制流与数据流分离的设计。