nova状态同步

阿凡达2018-07-09 13:35


服务初始化阶段

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完成了虚拟机状态的同步,同步规则如下:

  1. 如果数据库中虚拟机已经shutdown,或者处于error状态,并且任务状态不是resize_migrating,则不做任何处理。如果任务状态是resize_migrating的话,后续还要做一些处理。
  2. 如果虚拟机已经处于deleted状态,但是数据库中还没有标记为删除,则需要更新配额相关的数据,并且删除数据库中的记录。此虚拟机状态即恢复完毕,开始恢复下一台。
  3. 如果虚拟机不是上面的状态,则需要恢复云主机的网络设备(当前配置的vif_driver是LibvirtGenericVIFDriver,tap设备由libvirt生成管理,这里就直接跳过了)
  4. 如果虚拟机的task状态为resize_migrating,说明在迁移过程中服务关闭了,保险起见需要恢复虚拟机状态finish_revert_migration
  5. 以上操作完成之后,如果数据库中记录的状态是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 日志告警
本文来自网易实践者社区,经作者岳文远 授权发布。