OpenStack 存储热迁移

migration

OpenStack has the ability to migrate volumes between back ends which support its volume-type. Migrating a volume transparently moves its data from the current back end for the volume to a new one. This is an administrator function, and can be used for functions including storage evacuation (for maintenance or decommissioning), or manual optimizations (for example, performance, reliability, or cost).

——摘自 OpenStack 官方手册

随着存储技术的不断发展,云计算中的存储后端种类越来越多。而在不同存储后端之间进行存储热迁移则是和普遍的需求。在 OpenStack 中,云硬盘(volume)支持在不同后端之间进行数据移。具体的可分为两类,一种是云硬盘未挂载的,另一种是已经挂载的。前一种比较简单,后面一种就是存储热迁移了。下面对这两种方式在 OpenStack 中具体实现简单介绍,此外还介绍如何实现把虚拟机从本地启动的方式热迁移到云硬盘中。

UMCloud OpenStack实现了更灵活的存储实时调度功能,使得可以根据应用和业务负载情况热迁移云硬盘和系统盘到不同的存储后端上,提高存储使用效率。

 

 

未挂载云硬盘的迁移

detached volume 指未挂载到虚拟机上的 volume,状态为available。对 detached volume 进行迁移的流程比较简单,直接将数据从原来的 volume 拷贝到新的 volume 就可以了。在迁移的过程中需要注意 volume 状态的变化、对异常的处理,保证 volume 状态的一致性。整个流程如图1所示。

3-5

图1  detach volume迁移流程图

下面简单介绍 Cinder(即 OpenStack 中 volume 的管理组件)的实现细节。

  1. cinder-api 接收 migrate 请求
    cinder-api 收到 client 发来的 migrate 请求后,经过 paste.deploy 和 route 的映射,交给 cinder.api.contrib.admin_actions.API 类中的 migrate_volume 方法。该方法首先会检查迁移的目的 host 上的 cinder volume 服务是否正常,然后将目标 volume 的 migration_status 设为migrating。当这些预处理全部完成后,cinder api 通过 rpc 将请求转到 cinder-scheduler。
  2. cinder-scheduler 对目的 host 进行检查
    cinder-scheduler 收到 cinder-api 发过来的请求后,会对迁移的目的 host 进行检查,根据配置文件对 host 进行容量等检查,以判断该 host 能否创建新的 volume。
  3. cinder-volume 处理 migrate
    当 source host 的 cinder-volume 服务收到处理请求后,会执行以下三个操作:
    通过 rpc 调用目的 host 上的 cinder-volume 服务新建一个 volume;
    当新的 volume 创建完毕后,使用 dd 命令进行复制;
    复制完成后,对 volume 的状态进行修改并删除旧的 volume。

已挂载的云硬盘的热迁移

attached volume 指已经挂载到虚拟机,状态是 in-use 的 volume,对 attached volume 进行热迁移需要在不中断虚拟机业务的同时进行 volume 的复制和切换。OpenStack 中使用 libvirt 的 rebase方法来实现 volume 的热迁移。OpenStack API 流程处理如图2所示。

3-1

图2 attach volume热迁移整体流程

如图2所示,attached volume 需要 cinder 和 nova 两个组件共同协作才能完成迁移。下面简单介绍 API 处理流程。

  1. cinder 向 nova 发起 swap volume 请求
    cinder-volume 服务收到 volume migration 请求后,如果发现 volume 状态为 attached,则通过 novaclient 向 nova 发起 swap volume 请求。
  2. nova api 对请求进行预处理
    nova-api 收到该请求后,通过 paste.deploy 和 route 的引导和映射,请求进入 VolumeAttachmentController 的 update方法。该方法先会进行例行检查,如对新旧 volume 的状态进行判断,确保能够执行 detach 和 attach 操作;对虚拟机的 Block Device Mapping 进行检查;中间还会调用 cinderclient 来更新新旧 volume 的状态。这部分的代码逻辑主要是对资源在数据库中的状态进行判断。然后,nova-api 通过 rpc 将请求提交到虚拟机所在主机的nova-compute 服务中,这时候就开始执行 volume 的热迁移了。
  3. nova-compute 调用 libvirt 执行具体的热迁移操作
    nova.compute.manager. ComputeManager 类中的 swap_volume 方法是真正执行的入口,主要流程如图3所示。
    3-2

    图3  swap volume操作流程图

  4. cinder-volume 处理 volume 热迁移后的一些状态更新
    经过 nova 的 swap volume 步骤后,新旧 volume 之间的数据已经复制并同步,并且虚拟机已经使用新的 volume 了。接下来 cinder 需要处理一些数据库相关的信息更新。cinder 会交换新旧 volume 在数据库中的元信息,具体交换的内容为 provider-location 和volume-type 这两个字段,该交换过程如图4所示
    3-33-4

    图4 volume信息交换示意图

    现在需要将旧的 volume 的状态改回 attached 并添加新的 attachment 记录,然后把新的 volume 的记录删除。

Ceph RBD 支持

OpenStack 社区目前对 volume 的迁移主要考虑了 LVM 等 iSCSI 协议的后端。对 Ceph RBD 后端的支持比较有限,目前还不支持从 LVM 迁移到 RBD,这时需要进行进一步开发。目前我们进行了相关的测试,使得可以热迁移到 Ceph RBD。

虚拟机系统盘热迁移

虚拟机如果一开始就是从云硬盘启动的,那么我们可以方便地将虚拟机在各个存储后端直接迁移。然而虚拟机如果是从本地镜像启动的,我们想要迁移就比较麻烦了。一种简单的方式是迁移整个虚拟机到其他存储后端的 nova 计算节点上。这里我们介绍另一种方法,直接将虚拟机的本地启动镜像迁移到云硬盘中,同时这个云硬盘还能使用上述的热迁移的方法,进一步迁移到其他存储上。

Libvirt 的 rebase 功能

在讲如何实现迁移到云硬盘功能之前,我们来回顾下 volume 热迁移时提到的 libvirt rebase 方法。Libvirt rebase 主要是用到了 QEMU live block copy 的功能,这个具体在 libvirt 中如何实现我们暂且不讨论。我们来看下 nova 在 swap volume 时如何调用 libvirt rebase 的。

def _swap_volume(self, guest, disk_path, new_path, resize_to):
    """Swap existing disk with a new block device."""
    dev = guest.get_block_device(disk_path)

    # Save a copy of the domain's persistent XML file
    xml = guest.get_xml_desc(dump_inactive=True, dump_sensitive=True)

    # Abort is an idempotent operation, so make sure any block
    # jobs which may have failed are ended.
    try:
        dev.abort_job()
    except Exception:
        pass

    reraise = False
    try:
    # NOTE (rmk): blockRebase cannot be executed on persistent
    # domains, so we need to temporarily undefine it.
    # If any part of this block fails, the domain is
    # re-defined regardless.
    if guest.has_persistent_configuration():
    guest.delete_configuration()

    # Start copy with VIR_DOMAIN_REBASE_REUSE_EXT flag to
    # allow writing to existing external volume file
    dev.rebase(new_path, copy=True, reuse_ext=True)

    while not dev.is_job_complete():
        time.sleep(0.5)

    dev.abort_job(pivot=True)
    # NOTE(alex_xu): domain.blockJobAbort isn't sync call. This
    # is bug in libvirt. So we need waiting for the pivot is
    # finished. libvirt bug #1119173
    while not dev.is_job_complete():
        time.sleep(0.5)

    if resize_to:
        dev.resize(resize_to * units.Gi / units.Ki)
    except Exception:
        dev.abort_job()
        reraise = True
    finally:
    # NOTE(mdbooth): We don't know if we're in exception context or
    # not. reraise=False will not fail if we're not in exception
    # context.
        with excutils.save_and_reraise_exception(reraise=reraise):
            self._host.write_instance_config(xml)

注意到 _swap_volume 函数并没有指定旧的磁盘是否必须是 cinder 提供的 volume,如果被迁移的磁盘是本地的系统盘呢?其实也是可以的。

实现迁移系统盘到云硬盘中

考虑到 _swap_volume 函数也能支持将本地的系统盘迁移到 volume 上,我们可以实现新的 nova API 来调用此函数。

基本步骤如下:

  1. 调用 cinder 创建新的 volume
  2. 调用 libvirt driver 来进行热迁移
  3. 对 nova 中虚拟机的信息进行更新,将虚拟机的状态改为从云硬盘启动

 

优势

使用UMCloud OpenStack存储热迁移功能,可以方便用户切换云硬盘的类型,即使云硬盘正在被使用过程中,这样根据业务负载情况更灵活的使用不同的云硬盘类型,降低成本,提高效率和灵活性。

通过在线切换云硬盘类型,可以把现有业务从SAN切换到Ceph上,使用Ceph的更多高级存储功能,比如异地容灾备份等。

通过使用存储热迁移功能,UMCloud OpenStack实现了更灵活的存储调度,根据业务负载情况使用不同的后端存储,提高存储资源使用率。

另外虚拟机本地系统盘的热迁移功能,可以让本地虚拟机在线变成boot from volume方式,然后就可以使用多种共享存储后端,进而实现在不同级别的云平台环境上进行热迁移。

1 Comment

  1. Pingback: 梅馨嫣栀 » 从云硬盘(卷)中创建虚拟机

发表评论

电子邮件地址不会被公开。 必填项已用*标注