openstack-cinder-volume服务启动分析

服务进程启动如图

image

调用cinder/cmd/volume.py 的main方法启动服务

def main():
    objects.register_all()  //导入cinder 的相关orm object
    gmr_opts.set_defaults(CONF) 
    CONF(sys.argv[1:], project='cinder',
         version=version.version_string())
    logging.setup(CONF, "cinder")
    python_logging.captureWarnings(True)
    priv_context.init(root_helper=shlex.split(utils.get_root_helper()))
    utils.monkey_patch() //打猴子补丁
    gmr.TextGuruMeditation.setup_autorun(version, conf=CONF) //捕获异常日志相关
    global LOG
    LOG = logging.getLogger(__name__) //定义日志

    if not CONF.enabled_backends:
        LOG.error('Configuration for cinder-volume does not specify '
                  '"enabled_backends". Using DEFAULT section to configure '
                  'drivers is not supported since Ocata.')
        sys.exit(1)

    if os.name == 'nt':
        # We cannot use oslo.service to spawn multiple services on Windows.
        # It relies on forking, which is not available on Windows.
        # Furthermore, service objects are unmarshallable objects that are
        # passed to subprocesses.
        _launch_services_win32()
    else:
        _launch_services_posix() //启动Linux服务

实例化launcher,Linux下实例化 ProcessLauncher

def _launch_services_posix():
    launcher = service.get_launcher() //调用oslo_service

    for backend in filter(None, CONF.enabled_backends):
        _launch_service(launcher, backend)

    _ensure_service_started()

    launcher.wait()
class ProcessLauncher(object):
    """Launch a service with a given number of workers."""
    ................

调用_launch_service, 实例化server,创建cinder-volume的backend的service记录,并初始化sqlalchemy 数据库连接池,启动服务

def _launch_service(launcher, backend):
    CONF.register_opt(host_opt, group=backend)
    backend_host = getattr(CONF, backend).backend_host
    host = "%s@%s" % (backend_host or CONF.host, backend)
    # We also want to set cluster to None on empty strings, and we
    # ignore leading and trailing spaces.
    cluster = CONF.cluster and CONF.cluster.strip()
    cluster = (cluster or None) and '%s@%s' % (cluster, backend)
    try:
        server = service.Service.create(host=host,
                                        service_name=backend,
                                        binary=constants.VOLUME_BINARY,
                                        coordination=True,
                                        cluster=cluster)
    except Exception:
        LOG.exception('Volume service %s failed to start.', host)
    else:
        # Dispose of the whole DB connection pool here before
        # starting another process.  Otherwise we run into cases where
        # child processes share DB connections which results in errors.
        session.dispose_engine()
        launcher.launch_service(server)
        _notify_service_started()

接着调用 ProcessLauncher实例的 launch_service 函数,传入cinder-volume的service,fork出子进程,默认workers=1,即每个backend service默认只启动一个worker干活

 def launch_service(self, service, workers=1):
        """Launch a service with a given number of workers.

       :param service: a service to launch, must be an instance of
              :class:`oslo_service.service.ServiceBase`
       :param workers: a number of processes in which a service
              will be running
        """
        _check_service_base(service)
        wrap = ServiceWrapper(service, workers)

        # Hide existing objects from the garbage collector, so that most
        # existing pages will remain in shared memory rather than being
        # duplicated between subprocesses in the GC mark-and-sweep. (Requires
        # Python 3.7 or later.)
        if hasattr(gc, 'freeze'):
            gc.freeze()

        LOG.info('Starting %d workers', wrap.workers)
        while self.running and len(wrap.children) < wrap.workers:
            self._start_child(wrap)

通过os.fork 出子进程,让子进程初始化eventlet协程池,子进程调用add方法,执行run_service, 最终执行cinder-volume的service.start(),此时如果数据库中没有cinder-volume service,则会自动创建service记录。

 def _start_child(self, wrap):
        if len(wrap.forktimes) > wrap.workers:
            # Limit ourselves to one process a second (over the period of
            # number of workers * 1 second). This will allow workers to
            # start up quickly but ensure we don't fork off children that
            # die instantly too quickly.
            if time.time() - wrap.forktimes[0] < wrap.workers:
                LOG.info('Forking too fast, sleeping')
                time.sleep(1)

            wrap.forktimes.pop(0)

        wrap.forktimes.append(time.time())

        pid = os.fork()
        if pid == 0:
            self.launcher = self._child_process(wrap.service)
            while True:
                self._child_process_handle_signal()
                status, signo = self._child_wait_for_exit_or_signal(
                    self.launcher)
                if not _is_sighup_and_daemon(signo):
                    self.launcher.wait()
                    break
                self.launcher.restart()

            os._exit(status)

        LOG.debug('Started child %d', pid)

        wrap.children.add(pid)
        self.children[pid] = wrap

        return pid

至此 cinder-volume 服务启动完成!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

robin5911

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值