服務初始化階段
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,通過
啟動虛拟機(實際上是hard_reboot操作,但是不更新資料庫狀态)。resume_state_on_host_boot
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 | |||
DELETED | 清理資源 | ||
RESIZE_MIGRATING | 復原遷移操作 | ||
RUNNING | 非RUNNING | 啟動 |
2.事件通知及定時任務的狀态同步
上報狀态 | ||
---|---|---|
ACTIVE | SHUTDOWN | stop |
CRASHED | ||
SUSPENDED | ||
PAUSED | ignore | |
NOSTATE | ||
STOPPED | 非NOSTATE/SHUTDOWN/CRASHED | destroy |
SHUTDOWN/CRASHED | ||
非NOSTATE/SHUTDOWN | 日志告警 | |
本文來自網易雲社群,經作者嶽文遠授權釋出。
原文位址:nova狀态同步
更多網易研發、産品、營運經驗分享請通路網易雲社群。