consistency group,直译是一致性组,是Juno版本cinder新引进的一个概念。顾名思义,里面包含了两个意思,consistency(一致性)和group(组),如何体现的呢?处于数据保护或者是容灾的考虑,把一批存在公共操作的卷,在逻辑上划成一个组,用户可以非常方便的通过操作该组,不需要一个一个得去操作卷。所以针对的操作应该是做快照和做备份。
当前只有E公司的后端支持该特性,该blueprint估计也是E公司提出的。但个人认为在实际应用中还是十分有用的,属于通用的、公共的接口,能提升存储资源使用的效率
根据当前J版本代码的实现,修改点有:
- 增加了两张表:cgsnapshots,consistencygroups
- 增加了consistencygroup_id属性,主要在volume表和snapshot表;
- 增加了consistencygroups的配额;
- 提供了consistencygroup的创建、删除、查看的API;
- 提供了consistencygroup_snapshot的创建、删除、查看的API;
作者尚未实现对组备份的功能。在该blueprint的讨论中,作者也提到了后续要做的工作:
- 在heat层面上也应该理解卷的一致性组概念,应实现相应的接口;
- 在对一致性组做快照前,利用QEMU guest agent暂停GuestOS对文件系统的访问,等结束后再恢复;
- 支持一致性组的备份,包括在后端存储driver执行下实现对已经挂载卷的备份;
备份功能可以结合当前快照的实现来做,而heat上的尚处于八字没一撇的情况,而暂停GuestOS文件系统,则在进行中,见bp: https://wiki.openstack.org/wiki/Cinder/QuiescedSnapshotWithQemuGuestAgent
个人在J版本环境下对这个特性做了些尝试,想法是在allinone节点中创建一个组,加入两个卷,然后做统一快照,最后删除组快照。按照一致性预期结果看到有两个卷快照被创建最后被删除。但是环境没有对接E公司的后端,只有LVM,那就对LVM的代码做简单修改,使之支持基本的组操作。
首先得创建一个一致性组,在LVM的驱动代码中,需要在data[‘pool‘]字典中加入一个属性,否则过滤器这关(主要是capibility)是过不去的。 在上报能力的接口中,实现“consistencygroup_support=‘True‘”,可以简单返回空处理:
def create_consistencygroup(self, context, group): """Creates a consistencygroup.""" #raise NotImplementedError() return None def delete_consistencygroup(self, context, group): """Deletes a consistency group.""" #raise NotImplementedError() return None,[]
这样,一个组就建成了,show的结果(cinder的client尚未实现,只能用CURL测试):
有了组后,开始创建卷,指定consistencygroup_id创建同组的两个卷。
然后准备对组做快照,再次修改LVM的代码,添加create_cgsnapshot方法,功能是在创建组快照时,对组内所有卷做快照(代码实验用,仅做参考):
def create_cgsnapshot(self, context, cgsnapshot_ref): snapshots = self.db.snapshot_get_all_for_cgsnapshot(context, cgsnapshot_ref['id']) model_update = {"status":"available"} for sn in snapshots: try: self.create_snapshot(sn) except Exception as e: LOG.error("create snapshot %s fail."%sn) sn['status'] = 'error' model_update["status"] = "error" return model_update, snapshots
执行快照后,可以看到,生成了属于这个组的两个快照,并生成了一个consistencygroup_snapshot数据。show的结果:
两个快照:
这时如果再创建一个该组的卷,会报400的错,因为当前组已经有快照无法再修改该组。
“Consistency group b37f1d21-390e-4128-8fd6-2ca4789d9fc2 still has dependent cgsnapshots.”
然后再对LVM代码添加个删除接口(代码实验用,仅做参考):
def delete_cgsnapshot(self, context, cgsnapshot_ref): snapshots = self.db.snapshot_get_all_for_cgsnapshot(context, cgsnapshot_ref['id']) model_update = {'status':'available'} for sn in snapshots: try: self.delete_snapshot(sn) except Exception as e: LOG.error("delete snapshot %s fail"%sn) model_update['status'] = 'error' sn['status'] = 'error' return model_update, snapshots
执行后,consistencygroup_snapshot对象消失,伴随着两个快照也被成功删除。
快照自动消失:
至此,实现预期结果。当然这是最简单的场景,且LVM只能实现单节点存储池的场景,多节点根本搞不定。而且很多场景没有考虑,比如重复创建快照,一个组对应多个volume_type等,待后续再关注。
整个实验过程不算复杂,但第一次比预期要困难多了,还是有些细节需要去摸索的:
- 创建组的接口必须传入至少一个volume_type,也就以为着一致性组和卷类型的强相关;(这里在ethpad上的讨论有些出入,从接口看可以支持多个volume_type和组的对应关系)
- 后端存储在上报自己的硬件能力时,如果要支持创建一致性组,必须指定一个参数,“consistencygroup_support=‘True‘”,且True必须为字符串;
- 后端存储的驱动代码必须实现对应的方法,创建相关也就是“create_consistencygroup”和"delete_consistencygroup";快照相关就是“create_cgsnapshot”和“delete_cgsnapshot”;
所以,如果后续有存储厂商想实现自己的一致性组,在开发过程中注意上述问题。
参考:
https://etherpad.openstack.org/p/juno-cinder-cinder-consistency-groups
https://blueprints.launchpad.net/cinder/+spec/consistency-groups
######
最后, 一些过程中使用的API列举如下,供参考:
Type | URL | body | RSP |
ADD consistencygroup | v2/$tenant_id/consistencygroups | { "consistencygroup": {
"name":"my_cg", "description": "***", "volume_types": "Type1" }} |
N/A |
GET consistencygroups | v2/$tenant_id/consistencygroups/detail?all_tenants=1 | N/A |
{ "consistencygroups": [{ "status": "available", "description": "***", "availability_zone": "nova", "created_at": "---", "id": "*", "name": "my_cg"}]} |
DEL consistencygroup | v2/$tenant_id/consistencygroups/$cg_id |
{"consistencygroup": {"force":"True"}} |
N/A |
ADD cg_snapshot | v2/$tenant_id/cgsnapshots | {"cgsnapshot":{
"consistencygroup_id":"***", "name": "my_cg_snapshot", "description": "***"}} |
N/A |
GET cg_snapshot | v1/$tenant_id/cgsnapshots/detail?all_tenants=1 | N/A | {"cgsnapshots": [{
"status":"available", "description": "***", "created_at": "***", "consistencygroup_id": "***", "id": "***", "name":"***"}]} |
DEL cg_snapshot | v2/$tenant_id/cgsnapshots/$cgsnapshot_id | N/A | N/A |