cinder-volume服务上报自己的状态给cinder-scheduler的rpc通信代码分析

Posted potato-chip

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cinder-volume服务上报自己的状态给cinder-scheduler的rpc通信代码分析相关的知识,希望对你有一定的参考价值。

以juno版本为基础,主要从消息的生产者-消费者模型及rpc client/server模型来分析cinder-volume是如何跟cinder-scheduler服务进行rpc通信的

1、cinder-scheduler服务的启动入口

cat /usr/bin/cinder-scheduler
from cinder.common import config  # noqa
from cinder.openstack.common import log as logging
from cinder import service
from cinder import utils
from cinder import version

CONF = cfg.CONF
if __name__ == ‘__main__‘:
    CONF(sys.argv[1:], project=‘cinder‘,
         version=version.version_string())
    logging.setup("cinder")
    utils.monkey_patch()
    server = service.Service.create(binary=‘cinder-scheduler‘)
    service.serve(server)
    service.wait()

2、cinder-volume服务的启动入口 

cat /usr/bin/cinder-volume
from cinder.common import config  # noqa
from cinder.openstack.common import log as logging
from cinder import service
from cinder import utils
from cinder import version
host_opt = cfg.StrOpt(‘host‘,
                      help=‘Backend override of host value.‘)
CONF = cfg.CONF

if __name__ == ‘__main__‘:
    CONF(sys.argv[1:], project=‘cinder‘,
         version=version.version_string())
    logging.setup("cinder")
    utils.monkey_patch()
    launcher = service.get_launcher()
    if CONF.enabled_backends:
        for backend in CONF.enabled_backends:
            CONF.register_opts([host_opt], group=backend)
            backend_host = getattr(CONF, backend).host
            host = "%s@%s" % (backend_host or CONF.host, backend)
            server = service.Service.create(host=host,
                                            service_name=backend)
            launcher.launch_service(server)
    else:
        server = service.Service.create(binary=‘cinder-volume‘)
        launcher.launch_service(server)
    launcher.wait()

 3、cinder-volume/cinder-scheduler两者服务的启动

/etc/cinder/cinder.conf文件配置的 scheduler_manager 管理类
# Full class name for the Manager for scheduler (string value)
scheduler_manager=cinder.scheduler.manager.SchedulerManager
# Full class name for the Manager for volume (string value)
volume_manager=cinder.volume.manager.VolumeManager
	
D:code-programcinder-codejunoservice.py
class Service(service.Service):
  def __init__(self, host, binary, topic, manager, report_interval=None,
                 periodic_interval=None, periodic_fuzzy_delay=None,
                 service_name=None, *args, **kwargs):
        super(Service, self).__init__()

        if not rpc.initialized():
            rpc.init(CONF)

        self.host = host
        self.binary = binary
        self.topic = topic
        self.manager_class_name = manager
        manager_class = importutils.import_class(self.manager_class_name)----加载各自的管理类
        manager_class = profiler.trace_cls("rpc")(manager_class)

        self.manager = manager_class(host=self.host,
                                     service_name=service_name,
                                     *args, **kwargs)
        self.report_interval = report_interval
        self.periodic_interval = periodic_interval
        self.periodic_fuzzy_delay = periodic_fuzzy_delay
        self.basic_config_check()
        self.saved_args, self.saved_kwargs = args, kwargs
        self.timers = []
        setup_profiler(binary, host)


    def start(self):-------启动服务
        version_string = version.version_string()
        LOG.info(_(‘Starting %(topic)s node (version %(version_string)s)‘),
                 {‘topic‘: self.topic, ‘version_string‘: version_string})
        self.model_disconnected = False
        self.manager.init_host()--------步骤一,调用cinder-scheduler/cinder-volume管理类的init_host方法
        ctxt = context.get_admin_context()
        try:
            service_ref = db.service_get_by_args(ctxt,
                                                 self.host,
                                                 self.binary)
            self.service_id = service_ref[‘id‘]
        except exception.NotFound:
            self._create_service_ref(ctxt)

        LOG.debug("Creating RPC server for service %s" % self.topic)

        target = messaging.Target(topic=self.topic, server=self.host)
        endpoints = [self.manager]
        endpoints.extend(self.manager.additional_endpoints)
        self.rpcserver = rpc.get_server(target, endpoints)--------创建rpc server对象,用于接受rpc client发送的请求
        self.rpcserver.start()-----启动rpc server对象,创建相应的rabbitmq队列,用于监听消息

        if self.report_interval:
            pulse = loopingcall.FixedIntervalLoopingCall(
                self.report_state)
            pulse.start(interval=self.report_interval,
                        initial_delay=self.report_interval)
            self.timers.append(pulse)

        if self.periodic_interval:
            if self.periodic_fuzzy_delay:
                initial_delay = random.randint(0, self.periodic_fuzzy_delay)
            else:
                initial_delay = None

            periodic = loopingcall.FixedIntervalLoopingCall(
                self.periodic_tasks)
            periodic.start(interval=self.periodic_interval,
                           initial_delay=initial_delay)
            self.timers.append(periodic)

4、对于cinder-scheduler服务

步骤一,调用cinder-scheduler管理类的init_host方法,
该方法的一个重要角色是给cinder-volume服务发消息,告知对方需要上报自己的存储状态

D:code-programcinder-codejunoschedulermanager.py
from cinder.volume import rpcapi as volume_rpcapi
class SchedulerManager(manager.Manager):
    """Chooses a host to create volumes."""
    RPC_API_VERSION = ‘1.7‘
    target = messaging.Target(version=RPC_API_VERSION)		

    def init_host(self):
        ctxt = context.get_admin_context()
        self.request_service_capabilities(ctxt)
		
    def request_service_capabilities(self, context):
        volume_rpcapi.VolumeAPI().publish_service_capabilities(context)	
		
D:code-programcinder-codejunovolume
pcapi.py
class VolumeAPI(object):
    def publish_service_capabilities(self, ctxt):
        cctxt = self.client.prepare(fanout=True, version=‘1.2‘)
        cctxt.cast(ctxt, ‘publish_service_capabilities‘)

在cinder-scheduler服务启动的时候,
主动给cinder-volume服务发送 publish_service_capabilities 一次rpc 请求,来通知cinder-volume上报各自的存储特性
在这个过程中,cinder-scheduler充当的是消息的生产者,rpc client的角色,cinder-volume充当的是消息的消费者,rpc server的角色

5、对应cinder-volume服务

步骤一,调用cinder-volume管理类的init_host方法

from cinder import manager
D:code-programcinder-codejunovolumemanager.py

class VolumeManager(manager.SchedulerDependentManager):
    """Manages attachable block storage devices."""
    RPC_API_VERSION = ‘1.19‘
    target = messaging.Target(version=RPC_API_VERSION)
    def init_host(self):
        """Do any initialization that needs to be run if this is a
           standalone service.
        """
		......
        self.publish_service_capabilities(ctxt)

    def publish_service_capabilities(self, context):
        """Collect driver status and then publish."""
        self._report_driver_status(context)------步骤一 上报驱动的状态
        self._publish_service_capabilities(context)-----步骤二 发布服务的特性
对5 步骤一详解 
这是一个定位任务
    @periodic_task.periodic_task
    def _report_driver_status(self, context):
        LOG.info(_("Updating volume status"))
        if not self.driver.initialized:
            if self.driver.configuration.config_group is None:
                config_group = ‘‘
            else:
                config_group = (‘(config name %s)‘ %
                                self.driver.configuration.config_group)

            LOG.warning(_(‘Unable to update stats, %(driver_name)s ‘
                          ‘-%(driver_version)s ‘
                          ‘%(config_group)s driver is uninitialized.‘) %
                        {‘driver_name‘: self.driver.__class__.__name__,
                         ‘driver_version‘: self.driver.get_version(),
                         ‘config_group‘: config_group})
        else:
            volume_stats = self.driver.get_volume_stats(refresh=True)---调用相关的驱动,获取cinder-volume的状态
            if self.extra_capabilities:
                volume_stats.update(self.extra_capabilities)
            if volume_stats:
                # Append volume stats with ‘allocated_capacity_gb‘
                self._append_volume_stats(volume_stats)

                # queue it to be sent to the Schedulers.
                self.update_service_capabilities(volume_stats)---把cinder-volume的状态信息,赋值给cinder-scheduler的相关变量
		
D:code-programcinder-codejunomanager.py

class SchedulerDependentManager(Manager):

    def __init__(self, host=None, db_driver=None, service_name=‘undefined‘):
        self.last_capabilities = None
        self.service_name = service_name
        self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
        super(SchedulerDependentManager, self).__init__(host, db_driver)

    def update_service_capabilities(self, capabilities):
        """Remember these capabilities to send on next periodic update."""
        self.last_capabilities = capabilities

    @periodic_task.periodic_task
	一个定时任务,默认情况下,间隔一分钟的频率给nova-scheduler服务发送rpc 请求,把自己的存储资源信息更新给nova-scheduler服务
    def _publish_service_capabilities(self, context):
        """Pass data back to the scheduler at a periodic interval."""
        if self.last_capabilities:
            LOG.debug(‘Notifying Schedulers of capabilities ...‘)
            self.scheduler_rpcapi.update_service_capabilities(
                context,
                self.service_name,
                self.host,
                self.last_capabilities)

在这个过程中,cinder-volume服务,充当的是消息的生产者,rpc client的角色,cinder-scheduler服务充当的是消息的消费者,rpc server的角色 .除cinder-scheduler服务初始化或者重启的时候,会主动的给cinder-volume服务,发送一个上报自身存储状态的rpc请求,cinder-volume服务接受该请求,上报自己的存储状态外,剩下的都是cinder-volume服务,默认间隔60秒主动的上报自己的存储状态给cinder-scheduler服务,在状态上报时,rpc请求使用的是类型为fanout,名字为cinder-scheduler_fanout的exchange..

cinder-scheduler 的 HostManager 类维护一个数组service_states,每个cinder-volume 节点占该数组的一项,其值为该节点上 cinder-volume 服务的 capabilities,该值通过消息机制定期更新。在发生特定操作比如删除卷时,会进行立刻更新。

 

  

以上是关于cinder-volume服务上报自己的状态给cinder-scheduler的rpc通信代码分析的主要内容,如果未能解决你的问题,请参考以下文章

伪基站,卒于5G——本质上是基于网络和UE辅助的伪基站检测,就是将相邻基站的CI信号强度等信息通过测量报告上报给网络,网络结合网络拓扑配置信息等相关数据,对所有数据进行综合分析,确认在某个区域中是

微信硬件平台 设备直连微信云

献给Nacos小白的一篇好文:服务的健康检查

献给Nacos小白的一篇好文:服务的健康检查

献给Nacos小白的一篇好文:服务的健康检查

怎么扩大cinder-volumes