目录
方法注册
实例序列化与反序列化
conductor与数据库交互
Instance类对象与ComputeManager类对象
compute服务的worker数量
这里以instance.save函数为例进行说明。
方法注册
nova组件中compute服务访问DB的方式是通过Conductor服务来实现的,即通过indirection_api重定向到Conductor服务。
compute服务启动方法:
nova.cmd.compute.main
在该函数中初始化重定向api方法:
cmd_common.block_db_access('nova-compute')
objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI()
同时在nova.service.Service函数中,会等待conductor服务正常运行:
if objects_base.NovaObject.indirection_api:
conductor_api = conductor.API()
conductor_api.wait_until_ready(context.get_admin_context())
因为构造Instance实例的时候,类的继承关系是:
oslo_versionedobjects.base.VersionedObject
--> nova.objects.base.NovaObject
--> nova.objects.instance.Instance
而indirection_api作为oslo_versionedobjects.base.VersionedObject成员变量,在nova.objects.instance.Instance中也是起到作用的,即调用instance的save()方法时,有一个@base.remotable装饰器,位于/nova/objects/instance.py
@base.remotable
def save(self, expected_vm_state=None,
expected_task_state=None, admin_state_reset=False):
通过这个装饰器,会判断self.indirection_api是否存在,上面已经赋值,因此可以在compute服务中通过indirection_api重定向到nova-conductor中。
@base.remotable装饰器源码位于:
oslo_versionedobjects.base.remotable
if self.indirection_api:
updates, result = self.indirection_api.object_action(
ctxt, self, fn.__name__, args, kwargs)
前面indirection_api函数已经赋值,为conductor_rpcapi.ConductorAPI()
因此调用的方法是:nova.conductor.rpcapi.ConductorAPI.object_action
继而调用的方法是:
nova.conductor.rpcapi.ConductorAPI.object_action
PRC call的调用方法object_action:
构造的target是:
target = messaging.Target(topic=RPC_TOPIC, version='3.0')
cctxt = self.client.prepare()
在prepare()中并未指定server,因此这里是想conductor队列发送消息。
假设由多个节点上同时运行conductor服务,则这几个节点上的conductor服务都会监听这个队列,但最终该消息会被其中一个conductor服务消费掉。
实例序列化与反序列化
消息在传输的时候,用的是字典类型的消息体作为消息传输的格式。但是在OpenStack组件中使用的都是对象实例,这些对象实例是怎么传输和接收的?这里以Instance对象实例为例进行介绍。
消息序列化
消息将要发送的时候,在oslo_messaging组件中都会调用如下的函数,将对象进行序列化:
self.serializer.serialize_entity=
nova.rpc.RequestContextSerializer.serialize_entity
(是nova.rpc.ProfilerRequestContextSerializer成员变量)
---> nova.objects.base.NovaObjectSerializer.serialize_entity
在该函数中,如果是对象实例的话,则会调用oslo_versionedobjects.base.VersionedObject.obj_to_primitive函数将对象实例转换为字典类型的数据,VersionedObject对象作为基类的继承关系如下所示:
oslo_versionedobjects.base.VersionedObject
--> nova.objects.base.NovaObject
--> nova.objects.instance.Instance
因此Instance对象中也有obj_to_primitive和_obj_from_primitive方法。
经过序列化之后的Instance对象实例如下所示:
{'nova_object.name': 'Instance', 'nova_object.namespace': 'nova',
'nova_object.version': '2.7', 'nova_object.data':{Instance实例中的数据},
'nova_object.changes': ['flavor', 'task_state', 'power_state', 'info_cache'……]}
消息反序列化
作为服务端,当接收到client端发送来的消息之后,就会将字典类型的消息转化成能够在服务中相对应的实例对象,调用的方法如下:
oslo_messaging.rpc.client._BaseCallContext.call
--> nova.objects.base.NovaObjectSerializer.deserialize_entity
同时消息通过RPC call请求返回之后,也会经过deserialize_entity函数的处理。在这个函数中会将所有的字典都变为对象的形式。
[{'info_cache': InstanceInfoCache(created_at=2022-09-16T08:19:45Z,deleted=False,deleted_at=None,instance_uuid=10032782-3c3a-4e75-88c0-6b11b36f8072,
network_info=NetworkModel(2774d9d6-9e6c-470d-bdb5-a05a375e368f),updated_at=2022-09-21T08:25:44Z),
'security_groups': SecurityGroupList(objects=[]),
'flavor': Flavor(created_at=2022-08-26T09:16:12Z,deleted=False,deleted_at=None,description=None,disabled=False,ephemeral_gb=0,extra_specs={:architecture='x86_architecture',:category='general_purpose'},flavorid='e3c20f1b-2dba-49d5-9ea6-e9e58f913d09',id=3,is_public=True,memory_mb=1024,name='mini',projects=<?>,root_gb=0,rxtx_factor=1.0,swap=0,updated_at=None,vcpu_weight=0,vcpus=1),
'updated_at': '2022-09-27T08:44:11Z',
'obj_what_changed': ['flavor']}, None]
上述就是在Conductor服务中调用Instance.save之后的消息经过反序列化得到的对象。这些对象最后在oslo_versionedobjects.base.remotable函数中被重新更新到Instance对象中,就此完成数据库的更改。
conductor与数据库交互
在conductor服务中调用的方法是:
nova.conductor.manager.ConductorManager.object_action
直接调用nova.conductor.manager.ConductorManager._object_dispatch完成instance.save方法。然后将内容返回。访问数据库的接口位于nova/db/api.py文件中,该模块只是一个代理,剩下的实现是IMPL,其赋值如下:
_BACKEND_MAPPING = {'sqlalchemy': 'nova.db.sqlalchemy.api'}
IMPL = concurrency.TpoolDbapiWrapper(CONF, backend_mapping=_BACKEND_MAPPING)
Instance类对象与ComputeManager类对象
Instance对象和nova.compute.manager.ComputeManager类对象之间是什么样的关系?也就是说,compute作为服务端,client端将instance的序列化消息传入,然后server端反序列化得到Instance对象,接着compute进程就可以对该Instance对象实例进行相应的操作了。
原因是nova.compute.manager.ComputeManager对象和nova.objects.instance.Instance对象在接收到消息时,作为oslo_messaging.rpc.dispatcher.RPCDispatcher对象的成员变量,直接调用ComputeManager中的方法,并将Instance作为参数传入,这样在ComputeManager对象中就可以直接调用Instance对象了。
compute服务的worker数量
即:同一个节点上有多少个服务在监听compute.control01这个队列,消息在排队,rabbitmq是如何将消息分发到不同的worker线程上的?
注:nova-compute只有一个worker,因为还涉及到与libvirt后端连接,因此只有一个进程监听rabbitmq队列。
而conductor中有多个worker,每个worker都会监听对应的队列:
对于compute服务而言,首先在nova.cmd.compute.main函数中创建nova.service.Service对象实例,然后通过oslo_service.service.ServiceLauncher对象继续调用oslo_service.service.Services.run_service,在进程中调用nova.service.Service.start函数。
调用nova.rpc.get_server创建RPC Consumer所需的队列等信息。
等接收到消息之后,会将消息转换成实例对象,并调用ComputeManager对象中的类方法对参数进行处理。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)