nova状态同步
服务初始化阶段
nova-compute服务启动时调用manager中的host初始化函数
self.manager.init_host()
在host初始化函数中完成如下操作:
#初始化libvirt的事件处理
self.driver.init_host(host=self.host)
#注册生命周期事件的处理函数
self.init_virt_events()
#处理evacuated的虚拟机
通过libvirt接口获取本节点上所有的虚拟机,再查询这些虚拟机在数据库中的host信息。如果host与当前节点不一致,说明是已经撤离的虚拟机,直接destroy。
self._destroy_evacuated_instances(context)
#虚拟机状态同步
for instance in instances:
wait_ticks = self._init_instance(context, instance,
wait_ticks=wait_ticks)
_init_instance完成了虚拟机状态的同步,同步规则如下:
- 如果数据库中虚拟机已经shutdown,或者处于error状态,并且任务状态不是resize_migrating,则不做任何处理。如果任务状态是resize_migrating的话,后续还要做一些处理。
- 如果虚拟机已经处于deleted状态,但是数据库中还没有标记为删除,则需要更新配额相关的数据,并且删除数据库中的记录。此虚拟机状态即恢复完毕,开始恢复下一台。
- 如果虚拟机不是上面的状态,则需要恢复云主机的网络设备(当前配置的vif_driver是LibvirtGenericVIFDriver,tap设备由libvirt生成管理,这里就直接跳过了)
- 如果虚拟机的task状态为resize_migrating,说明在迁移过程中服务关闭了,保险起见需要恢复虚拟机状态
finish_revert_migration - 以上操作完成之后,如果数据库中记录的状态是running但是节点上虚拟机状态不为running,通过
resume_state_on_host_boot启动虚拟机(实际上是hard_reboot操作,但是不更新数据库状态)。
init_host中对事件处理的初始化:
#注册异常处理函数,这里的libvirt_error_handler是空的,也就是异常不做处理
libvirt.registerErrorHandler(libvirt_error_handler, None)
#向libvirt注册一个事件
libvirt.virEventRegisterDefaultImpl()
#
self._init_events()
_init_events中:
#创建一个队列,用于存储事件消息
#创建一对管道,用于事件消息的通知
self._init_events_pipe()
#启动一个系统原生线程,线程内用循环监听上面注册的libvirt事件。
_native_thread
libvirt.virEventRunDefaultImpl()
#启动一个绿色线程,线程内用一个循环分发监听到的libvirt事件。
eventlet.spawn(self._dispatch_thread)
事件分发流程_dispatch_thread
#读取上面建立的管道内容,如果读出数据,说明队列中有消息待处理。没有消息则退出此次循环。
_c = self._event_notify_recv.read(1)
#尝试读取事件队列
event = self._event_queue.get(block=False)
#如果是生命周期事件,则进入生命周期事件处理函数
self.emit_event(event)
#处理连接断开事件(告警日志打印,重置nova与libvirt的连接conn)
conn = last_close_event['conn']
生命周期事件处理函数emit_event(self, event)
#调用注册的事件处理函数
self._compute_event_callback(event)
注册事件处理函数init_virt_events
#此处注册了handle_events作为生命周期事件的处理函数
self.driver.register_event_listener(self.handle_events)
handle_events-->>handle_lifecycle_event
#按照如下的关系同步虚拟机在openstack层的电源状态
#EVENT_LIFECYCLE_STOPPED -> SHUTDOWN
#EVENT_LIFECYCLE_STARTED -> RUNNING
#EVENT_LIFECYCLE_PAUSED -> PAUSED
#EVENT_LIFECYCLE_RESUMED -> RUNNING
self._sync_instance_power_state(context,
instance,
vm_power_state)
_sync_instance_power_state
#如果虚拟机的宿主机不是当前节点,说明虚拟机做了迁移,这种虚拟机直接跳过,不做同步。
if self.host != db_instance.host
#虚拟机的任务状态不为空,说明当前事件只是一个任务的中间状态,也直接跳过不做处理
elif db_instance.task_state is not None
#事件上报的虚拟机电源状态与数据库电源状态不一致的情况下,更新数据库中的虚拟机电源状态。
if vm_power_state != db_power_state:
db_instance.power_state = vm_power_state
db_instance.save()
#数据库中的虚拟机状态为ACTIVE
#接收到SHUTDOWN/CRASHED -> call stop api
#接收到SUSPENDED -> call stop api
#接收到PAUSED -> 虚拟机异常pause,ignore
#接收到NOSTATE -> 虚拟机丢失,忽略
#数据库中的虚拟机状态为STOPPED,而上报的生命周期事件不是NOSTATE/SHUTDOWN/CRASHED其中之一,则强制关闭虚拟机。
self.compute_api.force_stop(context, db_instance)
#数据库中的虚拟机状态为PAUSED,上报的生命周期事件为SHUTDOWN/CRASHED,则认为一个暂停状态的虚拟机被关机了,强制关闭虚拟机。
self.compute_api.force_stop(context, db_instance)
#数据库中虚拟机状态为SOFT_DELETED或者DELETED,而上报的事件不是NOSTATE或者SHUTDOWN,则发出日志告警。
nova-compute服务启动时,libvirt driver会同步加载,并与libvirt建立一个长连接。通过这个连接注册了libvirt的生命周期事件的回调函数
#注册生命周期事件,只有这些事件发生时,后面virEventRunDefaultImpl才会被触发。
wrapped_conn.domainEventRegisterAny(
None,
libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
self._event_lifecycle_callback,
self)
当libvirt监听到事件发生时,会调用注册的回调函数
#将事件添加到队列中
self._queue_event(virtevent.LifecycleEvent(uuid, transition))
_queue_event
#加入队列
self._event_queue.put(event)
#通过管道通知给dispatch绿色线程
c = ' '.encode()
self._event_notify_send.write(c)
self._event_notify_send.flush()
定时任务同步
nova-compute在服务启动的最后阶段启动了一个定时任务_sync_power_states。这个定时任务的主要功能是同步节点上的虚拟机电源状态与数据库记录保持一致。最终也是通过与事件同步一样的_sync_instance_power_state同步电源状态。
总结
nova中的状态同步有以下几种情况:
1.服务启动时
- 节点上执行了evacuate操作的虚拟机直接destroy删除。
| 数据库状态 | 节点状态 | 任务状态 | 处理 |
|---|---|---|---|
| SOFT_DELETED | - | 非RESIZE_MIGRATING | - |
| ERROR | - | 非RESIZE_MIGRATING | - |
| DELETED | - | - | 清理资源 |
| - | - | RESIZE_MIGRATING | 回滚迁移操作 |
| RUNNING | 非RUNNING | - | 启动 |
2.事件通知及定时任务的状态同步
| 数据库状态 | 上报状态 | 处理 |
|---|---|---|
| ACTIVE | SHUTDOWN | stop |
| ACTIVE | CRASHED | stop |
| ACTIVE | SUSPENDED | stop |
| ACTIVE | PAUSED | ignore |
| ACTIVE | NOSTATE | ignore |
| STOPPED | 非NOSTATE/SHUTDOWN/CRASHED | destroy |
| PAUSED | SHUTDOWN/CRASHED | destroy |
| SOFT_DELETED | 非NOSTATE/SHUTDOWN | 日志告警 |
| DELETED | 非NOSTATE/SHUTDOWN | 日志告警 |
本文来自网易云社区,经作者岳文远授权发布。
原文地址:nova状态同步
更多网易研发、产品、运营经验分享请访问网易云社区。
nova状态同步的更多相关文章
- Postman+Postman interceptor的安装和使用-解决把chrome浏览器登录状态同步到postman进行有依赖的接口测试 Postman 使用方法详解
Postman+Postman interceptor的安装和使用-解决把chrome浏览器登录状态同步到postman进行有依赖的接口测试 问题引入:做接口测试时,有依赖关系的接口往往不好测试( ...
- 图解kubernetes容器状态同步机制核心实现
在K8s中将Pod调度到某一台Node节点之后,后续的状态维护信息则是由对应机器上的kubelet进行维护,如何实时反馈本地运行状态,并通知apiserver则是设计的难点, 本节主要是通过感知Pod ...
- vue父子组件状态同步的最佳方式
哈喽!大家好!我是木瓜太香,一位老牌儿前端工程师,平时我们在使用 vue 开发的时候,可能会遇到需要父组件与子组件某个状态需要同步的情况,通常这个是因为我们封装组件的时候有一个相同的状态外面要用,里面 ...
- vue父子组件状态同步的最佳方式续章(v-model篇)
大家好!我是木瓜太香!一名前端工程师,之前写过一篇<vue父子组件状态同步的最佳方式>,这篇文章描述了大多数情况下的父子组件同步的最佳方式,也是被开源中国官方推荐了,在这里表示感谢! 这次 ...
- zookeeper有几种部署模式? zookeeper 怎么保证主从节点的状态同步?
一.zookeeper的三种部署模式 Zookeeper 有三种部署模式分别是单机模式.伪集群模式.集群模式.这三种模式在不同的场景下使用: 单机部署:一般用来检验 Zookeeper 基础功能,熟悉 ...
- Android系统移植与调试之------->增加一个双击物理按键打开和关闭闪光灯并将闪光灯状态同步到下拉菜单中
最近有一个客户有这样的需求: 1.在[设置]--->[无障碍]中添加一个开关按钮. 如果打开开关的话,双击某个物理按键的时候,打开闪光灯,再双击该物理按键的时候,关闭闪光灯. 如果关闭开关的话, ...
- java线程控制、状态同步、volatile、Thread.interupt以及ConcurrentLinkedQueue
在有些严格的系统中,我们需要做到干净的停止线程并清理相关状态.涉及到这个主题会带出很多的相关点,简单的总结如下: 我们知道,在java中,有一个volatile关键字,其官方说明(https://do ...
- java多线程之hashmap concurrenthashmap的状态同步
最近在高并发的系统中发现,concurrenthashmap除了大家熟知的避免循环期间发生ConcurrentModificationException异常外,还有重要的一点是Retrievals r ...
- 浅谈js拖拽
本文来自网易云社区 作者:刘凌阳 前言 本文依据半年前本人的分享<浅谈js拖拽>撰写,算是一篇迟到的文章. 基本思路 虽然现在关于拖拽的组件库到处都是,HTML5也把拖放纳入了标准.但考虑 ...
随机推荐
- LeetCode题解之N-ary Tree Postorder Traversal
1.题目描述 2.问题分析 递归. 3.代码 vector<int> postorder(Node* root) { vector<int> v; postNorder(roo ...
- 调研getfit
Gitfit实际是一个提供私人教练的服务,其主要业务有三种,“局部减脂”每天0.5-1小时,对局部高强度的刺激,快速达到塑形目地,不需要复杂器械,0基础也能跟上训练进度,并提供咨询师.营养师团队.专属 ...
- M5加密字符串
private string GetMD5str(string oldStr) { //将输入转换为ASCII 字符编码 ASCIIEncoding enc = new ASCIIEncoding() ...
- python-ldap修改AD域用户密码(CA+SSL)
代码连接:https://github.com/raykuan/ldap-notes 使用python的ldap模块连接AD服务器,有两种方式: 非加密:con = ldap.initialize(' ...
- /etc/resolv.conf服务器客户端DNS重要配置文件
DNS客户端配置文件:etc/resolv.conf /etc/resolv.conf文件相当于windows如下图: 当然/etc/resolv.conf文件为辅助配置DNS文件,其实在网卡里也可以 ...
- 【转载】sql注入之入门
原文在:https://smelond.com MySql基础语法 mysql无非就是增删改查 mysql数据库结构: 数据库 test,test1 表名 admin,manage 数据 id,use ...
- python的学习之路day6
大纲: 1.反射 其中的方法:getattr,delattr,setattr,hasattr __import__() __import__() 注意事项 2.模块中的特殊变量 __doc__ __c ...
- 记录一次nginx配置vhost的小bug
话说这篇博客是在是为了保持自己记录生活的习惯而写的,没有什么阅读的价值,各位读者可以直接忽略了.今天在配置一个域名的时候,写了new_example.com(举例而已) 因为是内测,所以并未想象到深层 ...
- How to display values with in piechart using Jfreechart(values in sector )
I am using Jfreechart to create pie charts. Values are displayed outside pie chart as labels. I want ...
- Angular简介与程序架构
什么是angularJs 基于javascript开发的客户端应用框架,使我们可以更加快捷,简单的开发web应用. 诞生于2009年,后来被google收购,用在了很多项目中. 适用于CRUD应用或者 ...