Openstack Cinder的调度服务用于选择一个合适的cinder-volume节点来处理用户有关云盘生命周期的请求。本文介绍调度器affinity/anti-affinity的原理和使用方法。
一 简介
过滤器affinity/anti-affinity描述了云盘之间的关系,affinity表示新创建的云盘跟指定的云盘在同一个后端(back-end/pool), anti-affinity表示新创建的云盘跟指定的云盘在不同一个后端(back-ends/pools).为了实现该功能,Cinder新增了2个过滤器SameBackendFilter/DifferentBackendFilter.
二 功能验证
Mitaka版本默认不配置调度器SameBackendFilte/DifferentBackendFilter,需要另外配置。
1. 验证cinder后端为zte,fujitsu 2种磁阵后端,openstack版本为Mitaka。
2. 配置调度器SameBackendFilte/DifferentBackendFilter
为了使能该调度器,需要在cinder.conf中增加scheduler_default_weighers为SameBackendFilte/DifferentBackendFilter,并重启openstack-cinder-scheduler服务。
[DEFAULT]
scheduler_default_filters = AvailabilityZoneFilter,CapacityFilter,CapabilitiesFilter,SameBackendFilter,DifferentBackendFilter
3. 命令
# Volume A 后端是 'backend 1', 创建跟volume A后端相同的Volume B,命令如下
cinder create --hint same_host=VolA-UUID SIZE
# Volume A 后端是 'backend 1', 创建跟volume A后端不同的Volume C,命令如下
cinder create --hint different_host=VolA-UUID SIZE
# Volume A 后端是 'backend 1', 创建跟volume A和volumeC都不同的Volume D,命令如下
cinder create --hint different_host=VolA-UUID --hint different_host=VolC-UUID SIZE
cinder create --hint different_host="[VolA-UUID, VolC-UUID]" SIZE
4. SameBackendFilte过滤器测试
(1)先创建云盘test1,host为cinder@FUJITSU_ETERNUS-1#FUJITSU
。
$ cinder create 1 --name test1
+--------------------------------+--------------------------------------+
| Property | Value |
+--------------------------------+--------------------------------------+
| attachments | [] |
| availability_zone | nova |
| bootable | false |
| consistencygroup_id | None |
| created_at | 2019-05-08T07:05:52.000000 |
| description | None |
| encrypted | False |
| id | b9f37226-ef9e-417a-8e6a-2661b6a35a0f |
| metadata | {} |
| migration_status | None |
| multiattach | False |
| name | test1 |
| os-vol-host-attr:host | cinder@FUJITSU_ETERNUS-1#FUJITSU |
| os-vol-mig-status-attr:migstat | None |
| os-vol-mig-status-attr:name_id | None |
| os-vol-tenant-attr:tenant_id | b56b9ffcd531451f967b914658ce4058 |
| replication_status | disabled |
| size | 1 |
| snapshot_id | None |
| source_volid | None |
| status | creating |
| updated_at | 2019-05-08T07:05:52.000000 |
| user_id | 133a5ec1786243a2a92b85cd726d8f29 |
| volume_type | None |
+--------------------------------+--------------------------------------+
(2)创建跟test1同一host的云盘test2。
$ cinder create 2 --name test2 --hint same_host=b9f37226-ef9e-417a-8e6a-2661b6a35a0f
+--------------------------------+--------------------------------------+
| Property | Value |
+--------------------------------+--------------------------------------+
| attachments | [] |
| availability_zone | nova |
| bootable | false |
| consistencygroup_id | None |
| created_at | 2019-05-08T07:58:49.000000 |
| description | None |
| encrypted | False |
| id | 8f2ba309-bba7-41f6-afbc-63e8393246d8 |
| metadata | {} |
| migration_status | None |
| multiattach | False |
| name | test2 |
| os-vol-host-attr:host | cinder@FUJITSU_ETERNUS-1#FUJITSU |
| os-vol-mig-status-attr:migstat | None |
| os-vol-mig-status-attr:name_id | None |
| os-vol-tenant-attr:tenant_id | b56b9ffcd531451f967b914658ce4058 |
| replication_status | disabled |
| size | 2 |
| snapshot_id | None |
| source_volid | None |
| status | creating |
| updated_at | 2019-05-08T07:58:50.000000 |
| user_id | 133a5ec1786243a2a92b85cd726d8f29 |
| volume_type | None |
+--------------------------------+--------------------------------------+
云盘创建成功,host为cinder@FUJITSU_ETERNUS-1#FUJITSU
,跟test1一样。
5. DifferentBackendFilter过滤器测试
创建跟test1不同host的云盘test3
$ cinder create 2 --name test3 --hint different_host=b9f37226-ef9e-417a-8e6a-2661b6a35a0f
+--------------------------------+--------------------------------------+
| Property | Value |
+--------------------------------+--------------------------------------+
| attachments | [] |
| availability_zone | nova |
| bootable | false |
| consistencygroup_id | None |
| created_at | 2019-05-08T08:04:05.000000 |
| description | None |
| encrypted | False |
| id | f123f91d-a18b-42b4-8438-6012dfe58858 |
| metadata | {} |
| migration_status | None |
| multiattach | False |
| name | test3 |
| os-vol-host-attr:host | cinder@ZTE_IPSAN-1#SrvRAID_247_1 |
| os-vol-mig-status-attr:migstat | None |
| os-vol-mig-status-attr:name_id | None |
| os-vol-tenant-attr:tenant_id | b56b9ffcd531451f967b914658ce4058 |
| replication_status | disabled |
| size | 2 |
| snapshot_id | None |
| source_volid | None |
| status | creating |
| updated_at | 2019-05-08T08:04:06.000000 |
| user_id | 133a5ec1786243a2a92b85cd726d8f29 |
| volume_type | None |
+--------------------------------+--------------------------------------+
云盘创建成功,host为cinder@ZTE_IPSAN-1#SrvRAID_247_1
,跟test1不同。
6. 注意事项
如果同时指定了same_host和volume_type,需要用户保证参数可以调度到合适的后端,否则会因为调度不到后端而失败。
$ cinder create 2 --name test4 --hint same_host=b9f37226-ef9e-417a-8e6a-2661b6a35a0f --volume-type ztr_zte
+--------------------------------+--------------------------------------+
| Property | Value |
+--------------------------------+--------------------------------------+
| attachments | [] |
| availability_zone | nova |
| bootable | false |
| consistencygroup_id | None |
| created_at | 2019-05-08T07:59:45.000000 |
| description | None |
| encrypted | False |
| id | ab31e3b6-22e6-40bc-b299-ad4c359828a2 |
| metadata | {} |
| migration_status | None |
| multiattach | False |
| name | test4 |
| os-vol-host-attr:host | None |
| os-vol-mig-status-attr:migstat | None |
| os-vol-mig-status-attr:name_id | None |
| os-vol-tenant-attr:tenant_id | b56b9ffcd531451f967b914658ce4058 |
| replication_status | disabled |
| size | 2 |
| snapshot_id | None |
| source_volid | None |
| status | error |
| updated_at | 2019-05-08T07:59:46.000000 |
| user_id | 133a5ec1786243a2a92b85cd726d8f29 |
| volume_type | ztr_zte |
+--------------------------------+--------------------------------------+
cinder-scheduler日志如下:
2019-05-08 15:59:46.058 43813 INFO cinder.scheduler.base_filter [None req-0b9073dd-3ded-472c-b0b2-ec1e46c90b62 - - - - -] Filter SameBackendFilter returned 0 host(s)
2019-05-08 15:59:46.059 43813 WARNING cinder.scheduler.filter_scheduler [None req-0b9073dd-3ded-472c-b0b2-ec1e46c90b62 - - - - -] No weighed hosts found for volume with properties: {u'name': u'ztr_zte', u'qos_specs_id': None, u'deleted': False, u'created_at': u'2019-04-24T03:25:37.000000', u'updated_at': None, u'extra_specs': {u'volume_backend_name': u'ZTE', u'backend:availability_zone': u'nova'}, u'is_public': True, u'deleted_at': None, u'id': u'4c5ac178-d52b-4cd6-a7f4-4e151fe42677', u'description': None}
2019-05-08 15:59:46.066 43813 ERROR cinder.scheduler.flows.create_volume [None req-0b9073dd-3ded-472c-b0b2-ec1e46c90b62 - - - - -] Failed to run task cinder.scheduler.flows.create_volume.ScheduleCreateVolumeTask;volume:create: No valid host was found. No weighed hosts available
三 源码实现
过滤器代码实现比较简单,通过2个条件cinder后端存储host和云盘id查询volume表。
class DifferentBackendFilter(AffinityFilter):
"""Schedule volume on a different back-end from a set of volumes."""
def host_passes(self, host_state, filter_properties):
context = filter_properties['context']
scheduler_hints = filter_properties.get('scheduler_hints') or {}
affinity_uuids = scheduler_hints.get('different_host', [])
# scheduler hint verification: affinity_uuids can be a list of uuids
# or single uuid. The checks here is to make sure every single string
# in the list looks like a uuid, otherwise, this filter will fail to
# pass. Note that the filter does *NOT* ignore string doesn't look
# like a uuid, it is better to fail the request than serving it wrong.
if isinstance(affinity_uuids, list):
for uuid in affinity_uuids:
if uuidutils.is_uuid_like(uuid):
continue
else:
return False
elif uuidutils.is_uuid_like(affinity_uuids):
affinity_uuids = [affinity_uuids]
else:
# Not a list, not a string looks like uuid, don't pass it
# to DB for query to avoid potential risk.
return False
if affinity_uuids:
return not self.volume_api.get_all(
context, filters={'host': host_state.host,
'id': affinity_uuids,
'deleted': False})
# With no different_host key
return True
class SameBackendFilter(AffinityFilter):
"""Schedule volume on the same back-end as another volume."""
def host_passes(self, host_state, filter_properties):
context = filter_properties['context']
scheduler_hints = filter_properties.get('scheduler_hints') or {}
affinity_uuids = scheduler_hints.get('same_host', [])
# scheduler hint verification: affinity_uuids can be a list of uuids
# or single uuid. The checks here is to make sure every single string
# in the list looks like a uuid, otherwise, this filter will fail to
# pass. Note that the filter does *NOT* ignore string doesn't look
# like a uuid, it is better to fail the request than serving it wrong.
if isinstance(affinity_uuids, list):
for uuid in affinity_uuids:
if uuidutils.is_uuid_like(uuid):
continue
else:
return False
elif uuidutils.is_uuid_like(affinity_uuids):
affinity_uuids = [affinity_uuids]
else:
# Not a list, not a string looks like uuid, don't pass it
# to DB for query to avoid potential risk.
return False
if affinity_uuids:
return self.volume_api.get_all(
context, filters={'host': host_state.host,
'id': affinity_uuids,
'deleted': False})
# With no same_host key
return True
参考:http://specs.openstack.org/openstack/cinder-specs/specs/juno/affinity-antiaffinity-filter.html
网友评论