非破坏性备份

https://blueprints.launchpad.net/cinder/+spec/non-disruptive-backup

目前,备份操作只能在卷被分离后执行。此蓝图建议使用临时快照或卷来实现非破坏性备份。

问题描述

如果卷已连接,则必须先将其分离才能进行备份。这效率不高,并且会中断云用户仅为了进行备份的正常操作。

用例

用例是最终用户希望在不分离卷的情况下进行备份。

提议的变更

对于已连接的卷,创建临时快照通常比创建整个临时卷更便宜。如果我们可以连接快照并直接读取它,则无需创建另一个临时卷。这样可以更快地完成备份。

如果驱动程序尚未实现连接快照并且没有读取快照的方法,我们可以从连接的源卷创建临时卷,并备份临时卷。

对于 LVM 驱动程序,由于备份服务与卷驱动程序位于同一节点上,我们可以直接读取从连接的源卷创建的临时快照的本地路径。我们将创建一个临时快照,但无需为 LVM 连接快照。

将来,如果备份服务可以位于与卷驱动程序不同的节点上,那么我们可以考虑是否为 LVM 也执行连接快照,但是,引入连接快照逻辑会使 LVM 代码复杂化。这留待将来决定。

此提案将分多个步骤实施。

步骤 1

对于 LVM 驱动程序,对连接的卷进行临时快照并备份它。

  • 创建临时快照

  • 从临时快照的本地路径进行备份

  • 清理临时快照

对于其他驱动程序,通过创建临时卷并备份它来提供默认实现。

  • 从源卷创建临时卷

  • 连接临时卷

  • 从临时卷进行备份

  • 分离临时卷

  • 清理临时卷

注意:如果卷未连接,则将以与之前相同的方式进行备份。

步骤 2

为其他驱动程序提供更优化的方法,使用临时快照备份已连接的卷。对于无法从快照的本地路径读取的驱动程序,我们需要定义一个连接快照的接口,类似于连接卷。

  • 创建临时快照

  • 连接临时快照

  • 从临时快照进行备份

  • 分离临时快照

  • 清理临时快照

步骤 3(未来)

如果备份服务将来可以使用卷驱动程序在远程节点上,我们可以提供一种通过 RPC 发生调用的方式。这类似于步骤 2,只是它将使用 RPC API 调用远程节点上的卷管理器来连接快照。

备选方案

有一些替代方案

  • 分离卷并备份它。

  • 对连接的卷进行快照,从快照创建卷,然后备份它。

数据模型影响

步骤 1

在备份表中添加以下新列,用于临时卷和快照 ID

temp_volume_id = Column(String(36)) temp_snapshot_id = Column(String(36))

在卷表中添加以下新列,以持久化卷在更改为“备份中”状态之前的状态。这将用于在备份完成后将卷状态恢复为“可用”或“使用中”。这还用于在重新启动备份服务时清理失败的备份。这是因为“可用”和“使用中”卷的清理过程不同。

previous_status = Column(String(255))

步骤 2

在快照表中添加以下新列。快照表已经像卷表一样具有 provider_id 和 provider_location。需要此 provider_auth 列来保存创建快照的目标时的身份验证数据。如果我们想要连接快照,这是必需的。

provider_auth = Column(String(255))

REST API 影响

步骤 1

更改现有的创建备份 API 以接受一个 force 标志。如果卷为“使用中”,则 force 标志必须为 True。默认情况下,它是 False。对于“可用”卷,不需要 force 标志。

  • 创建备份 * V2/<租户 ID>/backups * 方法:POST * V2 的 JSON 模式定义

    {
        "backup":
        {
            "display_name": "nightly001",  # existing
            "display_description": "Nightly backup",  # existing
            "volume_id": "xxxxxxxx",  # existing
            "container": "nightlybackups",
            "force": True,  # new
        }
    }
    

步骤 2

将添加以下驱动程序 API 以支持连接快照和分离快照。

连接快照

def _attach_snapshot(self, context, snapshot, properties,
                     remote=False)
def create_export_snapshot(self, conext, snapshot)
def initialize_connection_snapshot(self, snapshot, properties,
                                   ** kwargs)

分离快照

def _detach_snapshot(self, context, attach_info, snapshot,
                     properties, force=False, remote=False)
def terminate_connection_snapshot(self, snapshot, properties,
                                  ** kwargs)
def remove_export_snapshot(self, context, snapshot)

或者,我们可以对卷和快照使用 is_snapshot 标志来共享通用代码,而无需添加新函数,但这会使代码混乱且难以阅读。因此,在减少代码重复和提高代码可读性之间存在权衡。

安全影响

通知影响

其他最终用户影响

最终用户将能够创建备份而无需分离卷。

性能影响

没有明显的影响性能。

如果我们可以连接快照并使用提议的更改对其进行备份,那么它将比手动创建快照、从快照创建卷然后备份它并删除它更简洁、更容易。

其他部署者影响

部署者将能够备份已连接的卷。

开发人员影响

驱动程序开发人员可以实现提议的新驱动程序 API 以进行更高效的备份。虽然这不是必需的。将提供默认实现,如前所述,从源卷创建临时卷。

实现

负责人

主要负责人

<xing-yang>

其他贡献者

<None>

工作项

依赖项

测试

将提供单元测试。

文档影响

将修改文档以描述此功能。

参考资料