以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-program\cinder-codejuno\service.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-program\cinder-codejuno\scheduler\manager.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-program\cinder-codejuno\volume\rpcapi.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-program\cinder-codejuno\volume\manager.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-program\cinder-codejuno\manager.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通信代码分析的更多相关文章

  1. Cinder Volume 服务启动流程分析和周期性任务分析

    1.cinder-volume服务的程序入口 #!/usr/bin/python2 # PBR Generated from u'console_scripts' import sys from ci ...

  2. CentOS7安装OpenStack(Rocky版)-09.安装Cinder存储服务组件(控制节点)

    本文分享openstack的Cinder存储服务组件,cinder服务可以提供云磁盘(卷),类似阿里云云盘 ----------------------- 完美的分隔线  -------------- ...

  3. devstack环境中不能创建cinder volume

    刚安装好的devstack环境中无法成功创建cinder volume,创建的volume的status为error:在cinder scheduler中看到失败log:2015-10-15 14:1 ...

  4. cinder存储服务

    一.cinder 介绍: 理解 Block Storage 操作系统获得存储空间的方式一般有两种: 1.通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

  5. OpenStack核心组件-cinder存储服务

    1. cinder 介绍 Block Storage 操作系统获得存储空间的方式一般有两种: 1)     通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文 ...

  6. openstack核心组件--cinder存储服务(6)

    一.cinder 介绍:   理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

  7. OpenStack组件——cinder存储服务

    1.cinder 介绍 1)理解 Block Storage 操作系统获得存储空间的方式一般有两种: (1)通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文 ...

  8. openstack核心组件——cinder存储服务(11)

    一.cinder 介绍:   理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

  9. 云计算openstack核心组件——cinder存储服务(11)

    一.cinder 介绍:   理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

随机推荐

  1. Pattern、Matcher的用法

    Pattern和Matcher Pattern 一个Pattern是一个正则表达式经编译后的表现模式. Matcher 一个Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符 ...

  2. html中input提示文字样式修改

    在很多网站上我们都看到input输入框显示提示文字,让我们一起来看看如果在input输入框中显示提示文字.我们只需要在<input>标签里添加:placeholder="提示文字 ...

  3. PHP imagecolorat - 取得某像素的颜色索引值

    imagecolorat — 取得某像素的颜色索引值.高佣联盟 www.cgewang.com 语法 int imagecolorat ( resource $image , int $x , int ...

  4. 7.29 NOI模拟赛 题答 npc问题 三染色 随机 贪心

    LINK:03colors 这道题虽然绝大多数的人都获得了满分 可是我却没有. 老师讲题的时候讲到了做题答的几个技巧 这里总结一下. 数据强度大概为n=5000,m=60000的随机数据. 老师说:一 ...

  5. QDC day4

    图论. 强连通图 与 弱连通图 . 最短路 .dij 不支持负权.显然 值得一提的是利用斐波那契堆m+nlogn . 一张 边权都是2的整数次幂 考虑 一下直接 结构体维护这个2的整次幂数组但比大小 ...

  6. RabbitMQ学习总结(1)-基础概念

    1. 概念 1.1 AMQP协议 AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消 ...

  7. IDEA插件配置推荐

    一.配置 [自动编译]如下图配置:推荐指数[***] [忽略大小写]说明:IDEA默认是匹配大小写,此开关如果未关,你输入字符一定要符合大小写.比如敲string是不会出现代码提示或只能补充.但是如果 ...

  8. 查看 Linux 系统服务的 5 大方法

    Linux 系统服务有时也称为守护程序,是在Linux启动时自动加载并在Linux退出时自动停止的系统任务. 在本文中,良许将为大家介绍如何列出 Linux 系统里所有运行的服务,以及如何检查某个服务 ...

  9. 自定制格式化方式format

    自定制格式化方式format # x='{0}{0}{0}'.format('dog') # # print(x) # class Date: # def __init__(self,year,mon ...

  10. Ubuntu安装海思SDK(转)

    问题 海思SDK安装时,无法运行sdk.unpack 原因 BASH 和 DASH 的问题. Debian和Ubuntu中,/bin/sh默认已经指向dash,这是一个不同于bash的shell,它主 ...