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-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通信代码分析的更多相关文章
- Cinder Volume 服务启动流程分析和周期性任务分析
1.cinder-volume服务的程序入口 #!/usr/bin/python2 # PBR Generated from u'console_scripts' import sys from ci ...
- CentOS7安装OpenStack(Rocky版)-09.安装Cinder存储服务组件(控制节点)
本文分享openstack的Cinder存储服务组件,cinder服务可以提供云磁盘(卷),类似阿里云云盘 ----------------------- 完美的分隔线 -------------- ...
- devstack环境中不能创建cinder volume
刚安装好的devstack环境中无法成功创建cinder volume,创建的volume的status为error:在cinder scheduler中看到失败log:2015-10-15 14:1 ...
- cinder存储服务
一.cinder 介绍: 理解 Block Storage 操作系统获得存储空间的方式一般有两种: 1.通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...
- OpenStack核心组件-cinder存储服务
1. cinder 介绍 Block Storage 操作系统获得存储空间的方式一般有两种: 1) 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文 ...
- openstack核心组件--cinder存储服务(6)
一.cinder 介绍: 理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...
- OpenStack组件——cinder存储服务
1.cinder 介绍 1)理解 Block Storage 操作系统获得存储空间的方式一般有两种: (1)通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文 ...
- openstack核心组件——cinder存储服务(11)
一.cinder 介绍: 理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...
- 云计算openstack核心组件——cinder存储服务(11)
一.cinder 介绍: 理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...
随机推荐
- MySQL 8.0.20 安装教程图文详解(windows 64位)
MySQL 8.0.20 安装教程图文详解(windows 64位) 更新时间:2020年05月09日 15:09:04 转载 作者:瘦肉粥不加糖 这篇文章主要介绍了MySQL 8.0. ...
- Lua学习入门(基本数据类型)
数据类型 Lua 中有 8 个基本类型分别为:nil.boolean.number.string.userdata.function.thread 和 table. 数据类型 描述 nil 这个最简单 ...
- jupyter的服务器配置安装
该教程主要针对的是服务器安装,且在后台保持稳定运行的情况. 1.jupyter下载 有网的时候 1. pip install jupyter 离线安装 在有网络的环境下载安装包 2. pip down ...
- Numpy random函数
import numpy as np # 生成一个随机数组 np.random.randint(0,6,3) # array([1, 1, 3]) # 生成一个随机数组(二维数组) np.random ...
- PHP scandir() 函数
------------恢复内容开始------------ 实例 列出 images 目录中的文件和目录: <?php$dir = "/images/"; // Sort ...
- PHP fread() 函数
定义和用法 fread() 函数读取打开的文件. 函数会在到达指定长度或读到文件末尾(EOF)时(以先到者为准),停止运行. 该函数返回读取的字符串,如果失败则返回 FALSE. 语法 string ...
- PHP tempnam() 函数
定义和用法 tempnam() 函数在指定的目录中创建一个具有唯一文件名的临时文件. 该函数返回新的临时文件名,如果失败则返回 FALSE. 语法 tempnam(dir,prefix) 参数 描述 ...
- Typora + PicGo-Core + Custom Command 实现上传图片到图床
教程参考 Typora+PicGo-Core(command line)+Gitee实现图片上传到图床 主要借鉴 picgo 操作命令 Typora + PicGo + Gitee 实现图片自动上传到 ...
- java开发-flyway
数据库版本管理工具 什么是数据库版本管理? 做过开发的小伙伴们都知道,实现一个需求时,一般情况下都需要设计到数据库表结构的修改.那么我们怎么能保证项目多人开发时,多个数据库环境(测试,生产环境)能够保 ...
- C# Thread.Join的报错情形——论执行完的线程能够成功执行Join吗
结论: 能, 执行完的线程调用Join不会抛出错误. Thread.Join()是什么? Join()函数用于阻塞地等待线程结束, 其行为是在线程A中调用了线程B的Join()后, 线程A将一直阻塞在 ...