基于ocata版本的,源码梳理

1)用户输入cinder service-list命令行,查看cinder服务的状态时,cinder的入口函数为cinder/api/contrib/services.py:Service:index方法

class ServiceController(wsgi.Controller):
def __init__(self, ext_mgr=None):
self.ext_mgr = ext_mgr
super(ServiceController, self).__init__()
self.volume_api = volume.API() def index(self, req):
"""Return a list of all running services. Filter by host & service name.
"""
context = req.environ['cinder.context']
authorize(context, action='index')
detailed = self.ext_mgr.is_loaded('os-extended-services')
now = timeutils.utcnow(with_timezone=True)------------------//获取controller 当前的时间 filters = {} if 'host' in req.GET:
filters['host'] = req.GET['host']
if 'binary' in req.GET:
filters['binary'] = req.GET['binary']
elif 'service' in req.GET:
filters['binary'] = req.GET['service']
versionutils.report_deprecated_feature(LOG, _(
"Query by service parameter is deprecated. "
"Please use binary parameter instead.")) services = objects.ServiceList.get_all(context, filters)----------//从 db 获取所有的 cinder service 列表 svcs = []
for svc in services:----------------------------//循环每个 service
updated_at = svc.updated_at
delta = now - (svc.updated_at or svc.created_at)-------------//获取 updated_at。不存在的话,获取 created_at,并和当前时间计算时间差
delta_sec = delta.total_seconds()
if svc.modified_at:
delta_mod = now - svc.modified_at
if abs(delta_sec) >= abs(delta_mod.total_seconds()):
updated_at = svc.modified_at
alive = abs(delta_sec) <= CONF.service_down_time------/获取时间差值的绝对值,并检查是否小于配置的 server_down_time,该配置项默认是60秒
art = (alive and "up") or "down"----------------------//如果差值小于60,则service 状态为 up,否则为 down
active = 'enabled'
if svc.disabled:
active = 'disabled'
if updated_at:
updated_at = timeutils.normalize_time(updated_at)
ret_fields = {'binary': svc.binary, 'host': svc.host,
'zone': svc.availability_zone,
'status': active, 'state': art,
'updated_at': updated_at} # On V3.7 we added cluster support
if req.api_version_request.matches('3.7'):
ret_fields['cluster'] = svc.cluster_name if detailed:
ret_fields['disabled_reason'] = svc.disabled_reason
if svc.binary == "cinder-volume":
ret_fields['replication_status'] = svc.replication_status
ret_fields['active_backend_id'] = svc.active_backend_id
ret_fields['frozen'] = svc.frozen
svcs.append(ret_fields)
return {'services': svcs}

 

因此 service 的 up/down 状态取决于数据库中 service 表对应某 service 的行的 updated_at 列的值和当前 controller 节点的时间的差值是否在配置的范围之内,如果差值在设置的范围之内,那么就认为服务是up的,如果差值不在设置的范围之内,那么就认为服务时down的,那么每个服务的updated_at的值从如何更新的?

2、cinder各个服务对应数据库中update_at值的更新,这个字段的时间值,获取的是该服务运行在哪个物理节点上,就获取当前物理节点的时间值,更新到数据库值,计数器加1

cinder 的各种service,比如cinder-api,cinder-backup 等,都是cinder/service.py 文件中 class Service(service.Service) 的一个实例
(这个实例,采用一个manager,使能rpc,通过监听基于topic的队列,同时他还定期在manager上运行一个任务,上报他的状态给数据库服务表)
该类的start方法如下:

   def start(self):
version_string = version.version_string()
LOG.info(_LI('Starting %(topic)s node (version %(version_string)s)'),
{'topic': self.topic, 'version_string': version_string})
self.model_disconnected = False if self.coordination:
coordination.COORDINATOR.start() self.manager.init_host(added_to_cluster=self.added_to_cluster,--------调用的是manager模块中init_host方法,
service_id=Service.service_id)------------------这个方法的实现中依次调用driver.do_setup,driver.check_for_setup_error,driver.init_capabilities 三个函数,而函数init_capabilities中有会调动驱动的get_volume_stats函数来获取存储后端的存储状态信息 LOG.debug("Creating RPC server for service %s", self.topic) ctxt = context.get_admin_context()
endpoints = [self.manager]
endpoints.extend(self.manager.additional_endpoints)
obj_version_cap = objects.Service.get_minimum_obj_version(ctxt)
LOG.debug("Pinning object versions for RPC server serializer to %s",
obj_version_cap)
serializer = objects_base.CinderObjectSerializer(obj_version_cap) target = messaging.Target(topic=self.topic, server=self.host)
self.rpcserver = rpc.get_server(target, endpoints, serializer)
self.rpcserver.start() # NOTE(dulek): Kids, don't do that at home. We're relying here on
# oslo.messaging implementation details to keep backward compatibility
# with pre-Ocata services. This will not matter once we drop
# compatibility with them.
if self.topic == constants.VOLUME_TOPIC:
target = messaging.Target(
topic='%(topic)s.%(host)s' % {'topic': self.topic,
'host': self.host},
server=vol_utils.extract_host(self.host, 'host'))
self.backend_rpcserver = rpc.get_server(target, endpoints,
serializer)
self.backend_rpcserver.start() # TODO(geguileo): In O - Remove the is_svc_upgrading_to_n part
if self.cluster and not self.is_svc_upgrading_to_n(self.binary):
LOG.info(_LI('Starting %(topic)s cluster %(cluster)s (version '
'%(version)s)'),
{'topic': self.topic, 'version': version_string,
'cluster': self.cluster})
target = messaging.Target(
topic='%s.%s' % (self.topic, self.cluster),
server=vol_utils.extract_host(self.cluster, 'host'))
serializer = objects_base.CinderObjectSerializer(obj_version_cap)
self.cluster_rpcserver = rpc.get_server(target, endpoints,
serializer)
self.cluster_rpcserver.start() self.manager.init_host_with_rpc() if self.report_interval:-------------------------//如果设置了 report_interval 配置项,那么该 service 将启动一个无限循环来执行 report_state 方法,
运行间隔就是 report_interval,其默认值是 10 秒,即默认10上报一次状态
pulse = loopingcall.FixedIntervalLoopingCall(----------这是一个循环,self.report_state这个方法就是要循环执行的任务
self.report_state)
pulse.start(interval=self.report_interval,-----------开始这个运行这个循环,s1
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)

 

s1方法的实现
def report_state(self):----更新服务的状态到数据库中
"""Update the state of this service in the datastore."""
if not self.manager.is_working():
# NOTE(dulek): If manager reports a problem we're not sending
# heartbeats - to indicate that service is actually down.
LOG.error(_LE('Manager for service %(binary)s %(host)s is '
'reporting problems, not sending heartbeat. '
'Service will appear "down".'),
{'binary': self.binary,
'host': self.host})
return ctxt = context.get_admin_context()
zone = CONF.storage_availability_zone
try:
try:
service_ref = objects.Service.get_by_id(ctxt,Service.service_id)-----根据service_id从数据库中获取service信息
except exception.NotFound:
LOG.debug('The service database object disappeared, '
'recreating it.')
self._create_service_ref(ctxt)
service_ref = objects.Service.get_by_id(ctxt,Service.service_id) service_ref.report_count += 1--------------更新报告计数器,加1
if zone != service_ref.availability_zone:
service_ref.availability_zone = zone service_ref.save() # TODO(termie): make this pattern be more elegant.
if getattr(self, 'model_disconnected', False):
self.model_disconnected = False
LOG.error(_LE('Recovered model server connection!'))

3、services表字段的内容

mysql> desc services;
+------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+----------------+
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
| deleted_at | datetime | YES | | NULL | |
| deleted | tinyint(1) | YES | | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| host | varchar(255) | YES | | NULL | |
| binary | varchar(255) | YES | | NULL | |
| topic | varchar(255) | YES | | NULL | |
| report_count | int(11) | NO | | NULL | |
| disabled | tinyint(1) | YES | | NULL | |
| availability_zone | varchar(255) | YES | | NULL | |
| disabled_reason | varchar(255) | YES | | NULL | |
| modified_at | datetime | YES | | NULL | |
| rpc_current_version | varchar(36) | YES | | NULL | |
| object_current_version | varchar(36) | YES | | NULL | |
| replication_status | varchar(36) | YES | | NULL | |
| frozen | tinyint(1) | YES | | NULL | |
| active_backend_id | varchar(255) | YES | | NULL | |
| cluster_name | varchar(255) | YES | | NULL | |
+------------------------+--------------+------+-----+---------+----------------+
19 rows in set (0.01 sec)

 

样例
mysql> select * from services limit 2\G;
*************************** 1. row ***************************
created_at: 2018-08-16 07:29:20
updated_at: 2019-06-14 09:22:23
deleted_at: NULL
deleted: 0
id: 1
host: 10.24.1.9
binary: cinder-scheduler
topic: cinder-scheduler
report_count: 838433
disabled: 0
availability_zone: nova
disabled_reason: NULL
modified_at: NULL
rpc_current_version: 3.5
object_current_version: 1.21
replication_status: not-capable
frozen: 0
active_backend_id: NULL
cluster_name: NULL
*************************** 2. row ***************************

  

 

 

 

cinder服务状态up/down的源码梳理的更多相关文章

  1. SpringCloud微服务如何优雅停机及源码分析

    目录 方式一:kill -9 java进程id[不建议] 方式二:kill -15 java进程id 或 直接使用/shutdown 端点[不建议] kill 与/shutdown 的含义 Sprin ...

  2. cesium结合geoserver利用WFS服务实现图层编辑(附源码下载)

    前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...

  3. cesium结合geoserver利用WFS服务实现图层删除(附源码下载)

    前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...

  4. [阿里DIN] 从模型源码梳理TensorFlow的乘法相关概念

    [阿里DIN] 从模型源码梳理TensorFlow的乘法相关概念 目录 [阿里DIN] 从模型源码梳理TensorFlow的乘法相关概念 0x00 摘要 0x01 矩阵乘积 1.1 matmul pr ...

  5. [阿里DIN]从模型源码梳理TensorFlow的形状相关操作

    [阿里DIN]从模型源码梳理TensorFlow的形状相关操作 目录 [阿里DIN]从模型源码梳理TensorFlow的形状相关操作 0x00 摘要 0x01 reduce_sum 1.1 reduc ...

  6. [Linux]服务管理:rpm包, 源码包

    --------------------------------------------------------------------------------------------------- ...

  7. 客户端与服务端的事件watcher源码阅读

    watcher存在的必要性 举个特容易懂的例子: 假如我的项目是基于dubbo+zookeeper搭建的分布式项目, 我有三个功能相同的服务提供者,用zookeeper当成注册中心,我的三个项目得注册 ...

  8. 短链接服务Octopus的实现与源码开放

    前提 半年前(2020-06)左右,疫情触底反弹,公司的业务量不断提升,运营部门为了方便短信.模板消息推送等渠道的投放,提出了一个把长链接压缩为短链接的功能需求.当时为了快速推广,使用了一些比较知名的 ...

  9. 微服务架构 | *3.5 Nacos 服务注册与发现的源码分析

    目录 前言 1. 客户端注册进 Nacos 注册中心(客户端视角) 1.1 Spring Cloud 提供的规范标准 1.2 Nacos 的自动配置类 1.3 监听服务初始化事件 AbstractAu ...

随机推荐

  1. spring与mybati整合方法

    (1)spring配置文件: <!-- 引入jdbc配置文件 --> <context:property-placeholder location="jdbc.proper ...

  2. Oracle学习笔记_04_多表查询

    一.概念: 1.多表连接有以下几种分法: (1)内连接           vs          外连接 (左.右.满) (2)等值连接        vs         不等值连接 (3)非自连 ...

  3. Abp模块分析

    1.什么是模块? 模块化是一种处理复杂系统分解为更好的可管理模块的方式.模块化用来分割,组织和打包软件.每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功 ...

  4. java - BigDecimal的format()方法和setScale()方法格式字符串

    1.BigDecimal.setScale()方法用于格式化小数点 setScale(1)表示保留一位小数,默认用四舍五入方式 setScale(1,BigDecimal.ROUND_DOWN)直接删 ...

  5. PostgreSQL物化视图(materialized view)

    1.创建视图 CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] table_name [ (column_name [, ...] ) ] [ WITH ( sto ...

  6. C++内存使用机制基本概念详解

    .程序使用内存区 一个程序占用的内存区一般分为5种: ()全局.静态数据区:存储全局变量及静态变量(包括全局静态变量和局部静态变量) ()常量数据区:存储程序中的常量字符串等. ()代码区:存储程序的 ...

  7. CodeForces Gym 100228 Graph of Inversions

    题目大意 对于一个长为$N$的序列$A$,定义它所对应的逆序图: 有$N$个点组成,标号为$1...N$的无向图,对于每一组$i,j(i<j)$若存在$A_i>A_j$则在新图中就存在一条 ...

  8. bzoj 1941 [Sdoi2010]Hide and Seek——KDtree

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1941 第二道KDtree! 枚举每个点,求出距离它的最远和最近距离.O( n * logn ...

  9. Poj 1860 Currency Exchange(Bellman-Ford,SPFA解单源最短路径问题)

    一.题意 有多个货币交易点,每个只能互换两种货币,兑换的汇率不同,并收取相应的手续费.有N种货币,假定你拥有第S中,数量为V,有M个兑换点.问你能不能通过兑换操作使你最后拥有的S币比起始的时候多. 二 ...

  10. POJ3468(树状数组区间维护)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 89818   ...