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狀態同步
更多網易研發、產品、運營經驗分享請訪問網易雲社區。