标签:config style view result 搜索 ble sel mes comm
目前,nova compute读写数据库都是通过nova-conductor进行转发。数据库的读写操作都是根据objects下面模块中对应的方法来实现的,而这些方法都是使用了装饰器。
目前nova读写数据库所用的装饰器包括:
1 base.remotable_classmethod 2 base.remotable 3 staticmethod 4 db_api.api_context_manager.reader 5 db_api.api_context_manager.writer 6 property 7 db_api.pick_context_manager_reader 8 db_api.pick_context_manager_writer 9 base.NovaObjectRegistry.register 10 require_context
参考:https://blog.csdn.net/tiantao2012/article/details/78530213
测试:
1.使用remotable_classmethod
我们看一下remotable_classmethod这个装饰器的定义:
1 from oslo_versionedobjects import base as ovoo_base 2 remotable_classmethod = ovoo_base.remotable_classmethod 3 4 def remotable_classmethod(fn): 5 """Decorator for remotable classmethods.""" 6 @six.wraps(fn) 7 def wrapper(cls, context, *args, **kwargs): 8 if cls.indirection_api: 9 version_manifest = obj_tree_get_versions(cls.obj_name()) 10 try: 11 result = cls.indirection_api.object_class_action_versions( 12 context, cls.obj_name(), fn.__name__, version_manifest, 13 args, kwargs) 14 except NotImplementedError: 15 # FIXME(danms): Maybe start to warn here about deprecation? 16 result = cls.indirection_api.object_class_action( 17 context, cls.obj_name(), fn.__name__, cls.VERSION, 18 args, kwargs) 19 else: 20 result = fn(cls, context, *args, **kwargs) 21 if isinstance(result, VersionedObject): 22 result._context = context 23 return result 24 25 # NOTE(danms): Make this discoverable 26 wrapper.remotable = True 27 wrapper.original_fn = fn 28 return classmethod(wrapper)
这里,如果cls.indirection_api为空,则直接调用fn方法,fn这里一般指数据库的操作方法。
如果cls.indirection_api不为空,则调用cls.indirection_api中的object_class_action_versions方法。
我们搜索一下nova中关于indirection_api的初始化相关的代码:
[root@controller nova]# grep -rn indirection_api cmd/api_metadata.py:45: objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI() cmd/dhcpbridge.py:120: objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI() cmd/compute.py:54: objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI() cmd/network.py:54: objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI()
而这里的conductor_rpcapi指的就是nova.conductor中的rpcapi。
我们知道nova-conductor的rpcapi用的是rabbitmq做连接的,分析如下:
1 @profiler.trace_cls("rpc") 2 class ConductorAPI(object): 3 def __init__(self): 4 super(ConductorAPI, self).__init__() 5 ...... 6 self.client = rpc.get_client(target, 7 version_cap=version_cap, 8 serializer=serializer)
在get_client 中,初始化了一个RPCClient对象:
1 def get_client(target, version_cap=None, serializer=None): 2 assert TRANSPORT is not None 3 4 if profiler: 5 serializer = ProfilerRequestContextSerializer(serializer) 6 else: 7 serializer = RequestContextSerializer(serializer) 8 9 return messaging.RPCClient(TRANSPORT, 10 target, 11 version_cap=version_cap, 12 serializer=serializer)
这里用assert声明了TRANSPORT这个变量不为空,那么这个变量是在哪里初始化的呢?
在nova.conductor.rpc.py中的init方法里面,对其进行了初始化:
1 def init(conf): 2 global TRANSPORT, NOTIFICATION_TRANSPORT, LEGACY_NOTIFIER, NOTIFIER 3 exmods = get_allowed_exmods() 4 TRANSPORT = create_transport(get_transport_url())
而这个方法是在nova.config.py中初始化的:
1 def parse_args(argv, default_config_files=None, configure_db=True, 2 init_rpc=True): 3 ...... 4 if init_rpc: 5 rpc.init(CONF)
parse_args这个方法又在nova的每个服务初始化的时候就定义了:
从上面我们可以得知,一般是nova-compute和nova-network服务,其对应的cls.indirection_api不为空,所以读写数据库都是通过nova-conductor,也就是rabbitmq来完成的。
从remotable_classmethod的定义来看,对数据库的操作都是调用 cls.indirection_api中的object_class_action_versions方法来实现的。这个方法在nova-conductor的rpcapi里面实现的。
1 def object_class_action_versions(self, context, objname, objmethod, 2 object_versions, args, kwargs): 3 cctxt = self.client.prepare() 4 return cctxt.call(context, ‘object_class_action_versions‘, 5 objname=objname, objmethod=objmethod, 6 object_versions=object_versions, 7 args=args, kwargs=kwargs)
根据RPC的调用原理,这里调用的是nova.conductor.manager 中的 object_class_action_versions 方法。
这个方法定义如:
1 def object_class_action_versions(self, context, objname, objmethod, 2 object_versions, args, kwargs): 3 objclass = nova_object.NovaObject.obj_class_from_name( 4 objname, object_versions[objname]) 5 args = tuple([context] + list(args)) 6 result = self._object_dispatch(objclass, objmethod, args, kwargs)
因此,可以得知,最终的结果是通过self._object_dispatch来实现的。
self._object_dispatch的定义如:
1 def _object_dispatch(self, target, method, args, kwargs): 2 try: 3 return getattr(target, method)(*args, **kwargs) 4 except Exception: 5 raise messaging.ExpectedException()
这里的target就是对应的object对象,method就是对应的object方法。
又由于nova-conductor对应的self.indirection_api为空,因此,这里直接调用了数据库的操作方法来返回结果。
测试在nova boot实例的过程中,nova-compute在操作数据库过程所消耗的时间:
测试 instance.save()
使用remotable:
1 cmd/compute.py: 2 cmd_common.block_db_access(‘nova-compute‘) 3 objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI()
数据库访问次数->消耗时间(s):
1-> 0.119282 10->0.704272 100-> 8.679072 1000-> 59.863044 10000-> 312.080721 100000->3140.704155
不使用remotable:
1 cmd/compute.py: 2 #cmd_common.block_db_access(‘nova-compute‘) 3 #objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI()
数据库访问次数->消耗时间(s):
1->0.076283 10->0.153130 100->1.267794 1000->10.103049 10000->105.528138 100000->1027.132933
因此,通过conductor操作数据库的时间比直接操作数据库的时间要更长,在数据库调用次数越大的情况下越明显。
标签:config style view result 搜索 ble sel mes comm
原文地址:https://www.cnblogs.com/wangwei1/p/13037623.html