非破坏性备份¶
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>
工作项¶
步骤 1:提供默认实现。补丁在此处审核:https://review.openstack.org/#/c/193937/
步骤 2:通过添加新的驱动程序 API 以支持连接快照来提供更优化的实现。WIP 补丁在此处提出:https://review.openstack.org/#/c/201249/
步骤 3(未来):这将在备份服务与卷驱动程序解耦后发生。
依赖项¶
无
测试¶
将提供单元测试。
文档影响¶
将修改文档以描述此功能。