OpenStack之Nova分析——Nova Scheduler服务启动

来源:互联网 发布:手机象棋辅助软件 编辑:程序博客网 时间:2024/04/27 23:14

在继续介绍Nova虚拟机创建过程之前,我们来穿插一个很重要的内容,这就是Nova组件的“大脑”——Nova Scheduler(调度器)。它是我们后续分析虚拟机创建的基础。这个子服务的作用前面已经介绍过,从其名称也可以看出该子服务就是负责调度各子服务工作的。

Nova Scheduler属于RPC服务(至于什么是RPC服务可以关注我之前的文章),这篇文章我们先来分析一下Nova Scheduler的启动流程。

Nova Scheduler服务的启动脚本位于nova/bin/nova-scheduler文件

#加载配置项CONF = cfg.CONFCONF.import_opt('scheduler_topic','nova.scheduler.rpcapi')if __name__ == '__main__':    config.prase_args(sys.argv)  #加载控制台传入的参数    logging.setup("nova")        #配置服务的日志文件    #定义Nova Scheduler服务对象    server = service.Service.create(binary='nova-scheduler',topic=CONF.scheduler_topic)    service.serve(server)  #创建线程运行Nova Scheduler服务    service.wait()  #启动Nova Scheduler服务线程

import_opt方法首先会加载nova.scheduler.rpcapi模块,然后再检查模块中是否定义了scheduler_topic配置项。查看该模块的代码。

rpcapi_opts = [cfg.StrOpt('scheduler_topic',                          default='scheduler',                          help='the topic scheduler nodes listen on'),]

可以看到nova.scheduler.rpcapi模块中定义了scheduler_topic的默认值为scheduler。

注:在Nova文件的许多地方都定义了一些配置项的默认值,可以在nova.conf文件中做相应的配置来覆盖默认值

Nova Scheduler服务的启动代码加载了控制台传入的参数,例如我们通过命令:python /opt/stack/novabin/nova-scheduler --config-file=/etc/nova/nova.conf来启动Nova Scheduler服务,这里的控制台传入的参数就是配置文件的路径。

接下来调用service包中Service类的create方法创建Service对象,其中binary是服务名,topic是Nova Scheduler服务监听的RPC主题。然后分别调用了service包的serve和wait方法,创建和启动Nova Scheduler服务线程。

下面来详细分析一下service这个包。上述服务的启动过程主要用到了service包的Service类的create方法以及service包的serve和wait方法,分别来看一下。

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 = 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_obj = cls(host, binary, topic, manager,                          report_interval=report_interval,                          periodic_interval=periodic_interval,                          periodic_fuzzy_delay=periodic_fuzzy_delay)        return service_obj
这个方法很简单,首先检查一些参数设置,如果没有设置则采用默认值,最后返回一个Service对象。Service类的初始化方法做了两件事——保存create方法传入的参数并创建所需的API对象,等待Conductor服务运行。

2. serve方法

def serve(server, workers=None):    #设置_laucher全局变量,以保证每个进程只能启动一个服务    global _launcher    if _launcher:        raise RuntimeError(_('serve() can only be called once'))    #如果传入了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个线程,每个线程运行一个RPC服务。如果没有定义workers,会创建一个ServiceLauncher对象,该对象的launch_server方法只创建1个RPC服务。

在Nova Scheduler服务的启动脚本中,没有定义workers参数,所以会调用ServiceLauncher对象的launch_server方法。

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

可以看到先调用了Service对象的start方法,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)        #激活消费者        self.conn.consume_in_thread()        ...        #创建定时任务        pulse = self.servicegroup_api.join(self.host, self.topic, self)        if pulse:            self.timers.append(pulse)        ...

这个方法主要完成了两个工作,其一是:创建“消费者”,监听其它模块发来的RPC请求;其二是:创建线程运行的定时任务(这方面我目前还不太了解,后面研究一下吧)。

注:具体的关于RPC消息通信请参看我前面的文章,这里不再赘述。

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

3. wait方法

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

到这里,Nova Scheduler服务启动过程就分析完了。需要说明的是,Nova中全部子服务的启动流程都极其相似,大家可以继续去分析其它子服务的启动流程~~


0 0
原创粉丝点击