nova-compute服务启动时调用manager中的host初始化函数数据库
self.manager.init_host()
在host初始化函数中完成以下操做:api
#初始化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
完成了虚拟机状态的同步,同步规则以下:网络
finish_revert_migration
resume_state_on_host_boot
启动虚拟机(其实是hard_reboot操做,可是不更新数据库状态)。
init_host中对事件处理的初始化:app
#注册异常处理函数,这里的libvirt_error_handler是空的,也就是异常不作处理 libvirt.registerErrorHandler(libvirt_error_handler, None) #向libvirt注册一个事件 libvirt.virEventRegisterDefaultImpl() # self._init_events()
_init_events
中:dom
#建立一个队列,用于存储事件消息 #建立一对管道,用于事件消息的通知 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)
ui
#调用注册的事件处理函数 self._compute_event_callback(event)
注册事件处理函数init_virt_events
spa
#此处注册了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.服务启动时
数据库状态 | 节点状态 | 任务状态 | 处理 |
---|---|---|---|
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状态同步
更多网易研发、产品、运营经验分享请访问网易云社区。