Nova RPC服务 之 Nova RPC服务的创建

在Nova Scheduler的启动脚本中,最终的代码是创建Service类的create方法,以及service包的serve和wait方法。

分析Nova Scheduler服务的启动流程。

1、Service类的create方法

class Service(object): 
    @classmethod
    def create(cls, host=None, binary=None, topic=None, manager=None,
               report_interval=None, periodic_interval=None,
               periodic_fuzzy_delay=None):
        if not host:  #主机名
            host = CONF.host
        if not binary: #服务名
            binary = os.path.basename(inspect.stack()[-1][1])
        if not topic:  #主题
            topic = binary.rpartition('nova-')[2]
        if not manager: #manager类名
            manager = CONF.get('%s_manager' % topic, None)
        if report_interval is None:
            report_interval = CONF.report_interval #状态报告周期
        if periodic_interval is None:
            periodic_interval = CONF.periodic_interval #是否允许周期任务
        if periodic_fuzzy_delay is None: #周期任务延迟时间
            periodic_fuzzy_delay = CONF.periodic_fuzzy_delay
		#创建Service对象
        service_obj = cls(host, binary, topic, manager,
                          report_interval=report_interval,
                          periodic_interval=periodic_interval,
                          periodic_fuzzy_delay=periodic_fuzzy_delay)

        return service_obj
create方法首先检查一些参数设置,如果在方法调用时没有设置则采用默认值,最后 返回一个Service对象

Service类的初始化方法做了两个工作:

(1) 保存create方法传入的参数

(2) 创建所需的API对象,并等待Conductor服务正常运行。注意:所有的数据库操作都是通过Nova Conductor服务完

成。因此,其他服务的正常运行,都依赖于Nova Conductor服务已经正常运行

2、serve方法

def serve(server, workers=None):
    #设置_laucher全局变量,以保证每个进程只能启动一个服务
    global _launcher
    if _launcher: #_launcher不为None,说明有服务启动了
        raise RuntimeError(_('serve() can only be called once'))
    #workers指定启动的服务个数
    #如果传入了workers参数,则启动(workers)个线程运行服务
    if workers:
        _launcher = ProcessLauncher()
        _launcher.launch_server(server, workers=workers)
    else:
        _launcher = ServiceLauncher()
        _launcher.launch_server(server)
serve方法有两个参数,其中server是 Service类的create方法创建的Service对象workers是创建的服务的个数

果定义了workers,会创建一个ProcessLauncher对象,该对象的launch_server方法会创建workers个线程,每个线

运行一个Nova RPC服务。如果没有定义workers,会创建一个ServiceLauncher对象,该对象的launch_server方法

只创建一个线程运行Nova RPC服务。

在Nova Scheduler服务的启动脚本中,没有定义workers参数。因此serve方法会创建ServiceLauncher对象的

launch_server方法。ServiceLauncher类继承于Launcher类,launcher_server方法定义在Launcher类中。

def launch_server(self, server):
    ...
    gt = eventlet.spawn(self.run_server, server)
    self._services.append(gt)
方法创建了一个绿色线程,该线程会运行 ServiceLauncher对象的run_server方法。我们仔细看一下run_server方

法,该方法中的server参数是一个Service对象。

3、wait方法

service包的serve方法创建了一个绿色线程,而wait方法的功能是运行线程。serve方法创建的绿色线程会执行

ServiceLauncher对象的run_server方法。ServiceLauncher类继承于Launcher类,launcher_server方法定义在

Launcher类中。如下:

class Launcher(object):
@staticmethod
def run_server(server):
    server.start()
    server.wait()

该server参数是一个Service对象。可以看到,run_server方法依次调用了Service对象的start和wait方法。

Service类的start方法定义如下:

class Service(object):
    def start(self):
        ...
        self.basic_config_check()  #检查服务配置
        self.manager.init_host()   #初始化主机
        self.model_disconnected = False
        ctxt = context.get_admin_context() #获取管理员上下文
        try:
            #查看数据库,获取当前服务的id
            self.service_ref = self.conductor_api.service_get_by_args(ctxt,
                                                                      self.host,
                                                                      self.binary)
            self.service_id = self.service_ref['id']
        except exception.NotFound:
            #如果不存在当前服务记录,则创建新记录
            self._create_service_ref(ctxt)
        ...
        #创建与RabbitMQ服务器的连接    出现高级消息队列的重要东东
        self.conn = rpc.create_connection(new=True)
        #创建分发RPC请求的RpcDispatcher对象
        rpc_dispatcher = self.manager.create_rpc_dispatcher()
        #创建RPC消费者
        self.conn.create_consumer(self.topic, rpc_dispatcher, fanout=False)
        node_topic = '%s.%s' % (self.topic, self.host)
        self.conn.create_consumer(node_topic, rpc_dispatcher, fanout=False)
        self.conn.create_consumer(self.topic, rpc_dispatcher, fanout=True)
        #激活RPC消费者
        self.conn.consume_in_thread()
        ...
        #创建定时任务,定时报道服务的状态
        pulse = self.servicegroup_api.join(self.host, self.topic, self)
        if pulse:
            self.timers.append(pulse)
        #如果允许运行周期任务,设置初始等待时间
		if self.periodic_enable:
			if self.periodic_fuzzy_delay:
				#初始等待时间在0~periodic_fuzzy_delay之间随机选择一个数
				initial_delay = random.randint(0, self.periodic_fuzzy_delay)
			else:
				#如果没有选择periodic_fuzzy_delay,则服务启动后立即运行定时任务
				initial_delay = None
			#创建线程,运行周期任务
			periodic = utils.DynamicLoopingCall(self.periodic_tasks)
			periodic.start(initial_delay=initial_delay,periodic_interval_max=self.periodic_interval_max)
		self.timers.append(periodic)


Service类start方法主要完成两个工作:

(1)创建RPC消费者,监听其他模块发来的RPC请求

(2)创建线程运行定时任务

1、创建RPC消费者。start方法中,共监听了3个消费者。topic类型的消费者,topic.host类型的消费者,广播类型

的消费者。功能:


2、创建一个RpcDispatcher对象,RpcDispatcher对象的功能是决定将RPC请求交给manager对象的哪个方法处理

RpcDispatcher对象和manager对象在RPC服务中的地位已在"RPC调用的实现"部分介绍(后面详细读)。

3、创建定时任务线程的工作。start方法共两个线程,一个是线程会定时向数据库更新服务状态,一个是运行自定义

的周期任务

Service对象的wait方法很简单,其功能就是启动线程运行周期任务。

4、wait方法

serve方法是创建了一个绿色线程,而wait方法的功能是运行线程。


总结:Nova Scheduler服务启动过程就分析完了。需要说明的是,Nova中全部子服务的启动流程都极其相似,可以继

续去分析其它子服务的启动流程!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值