openstack下熱遷移機制

hNicholas發表於2020-10-19

熱遷移,也叫線上遷移(live migration),是虛擬機器從一臺主機上遷移到另一臺主機上但是“不中斷VM服務”的一種機制。這裡“不中斷”指的是在使用者觀感上,VM一直提供服務。而實際上,在熱遷移的過程中,VM會短暫地暫停一段時間。

openstack的熱遷移是nova元件呼叫libvirtd完成的。我們一般通過nova配置檔案(path:/etc/nova/nova.conf)來設定有關熱遷移的引數,從而讓VM按照我們希望的方式進行線上遷移。

nova配置檔案有關熱遷移的引數有如下幾個:

  • live_migration_bandwidth
  • live_migration_downtime
  • live_migration_downtime_steps
  • live_migration_downtime_delay
  • live_migration_completion_timeout
  • live_migration_permit_post_copy
  • live_migration_permit_auto_converge 

下面詳細地介紹這幾個引數代表的意義以及對熱遷移產生的影響。

live_migration_bandwidth

它是遷移期間要使用的最大頻寬(以MiB / s為單位),預設值是0,意味著不限制遷移頻寬。

live_migration_downtime、live_migration_downtime_steps、live_migration_downtime_delay

這三個引數都是有關熱遷移停機時間(downtime)的。我們說熱遷移過程中VM會短暫的暫停,而VM暫停的時間就是停機時間,它與這三個引數有關。

實際上,熱遷移是轉移記憶體(或儲存)的過程。源主機不斷把虛擬機器的記憶體轉移到目的主機,直到源主機僅僅省一部分可以一次轉移完成的記憶體未被轉移,此時把源主機上的虛擬機器暫停,轉移掉最後這一部分。這樣做是因為,在轉移記憶體時,源主機上的虛擬機器有可能在提供有關記憶體寫入的服務,生成新的未被遷移的記憶體,這就是所謂的“髒記憶體”,如果不暫停虛擬機器,“髒記憶體”一直產生,遷移永遠不能完成。

openstack下熱遷移的停機時間(downtime)不是單純設定一個數字那麼簡單,它停機策略要稍微複雜一點。openstack在遷移過程中的停機時間是變化的,該值不斷增加,在一段時間後停機時間達到最終的最大值,這個值就是由live_migration_downtime設定的。而live_migration_downtime_steps表示達到最大值所經歷的次數,live_migration_downtime_delay表示每一次增加downtime的間隔時間。下面舉一個實驗的例子,來具體說明停機時間是如何變化的:

進行實驗的虛擬機器的記憶體為4GiB。在/etc/nova/nova.conf設定的三個引數的值如下:

live_migration_downtime=5000 / live_migration_downtime_steps=7 / live_migration_downtime_steps=75

檢視nova的log日誌(path:/var/log/nova/nova-compute.log),找到了nova的變化情況

  1. Increasing downtime to 714 ms after 0 sec elapsed time
  2. Increasing downtime to 1326 ms after 300 sec elapsed time
  3. Increasing downtime to 1938 ms after 600 sec elapsed time
  4. Increasing downtime to 2550 ms after 900 sec elapsed time
  5. Increasing downtime to 3162 ms after 1200 sec elapsed time
  6. Increasing downtime to 3774 ms after 1500 sec elapsed time
  7. Increasing downtime to 4386 ms after 1800 sec elapsed time
  8. Increasing downtime to 4998 ms after 2100 sec elapsed time

可以看到,初始的downtime是一個較小的值,經歷七步以後,downtime增加到接近5000(ms)。初始的downtime值是由live_migration_downtime/live_migration_downtime_steps得來的,這裡就是5000/7=714(ms)。每一步增加的時間是由初始的downtime*(live_migration_downtime_steps-1)/live_migration_downtime_steps得到的,這裡就是714*(7-1)/7=612(ms)。

除此之外,我們發現,遷移每進行300s,downtime就變化一次,300s這個時間是由live_migration_downtime_delay決定的。在這裡,300s=live_migration_downtime_delay*VM記憶體大小(GiB),即75*4=300。

在實際實際工作中,在最大停機時間一定的情況下,有時我們需要儘快完成遷移,不在乎停機的時間,這時我們減少live_migration_downtime_stepslive_migration_downtime_delay,儘快達到最大停機時間;有時我們不在乎遷移總時長,希望服務中斷的時間越短越好, 就儘量增大live_migration_downtime_stepslive_migration_downtime_delay,慢慢地達到最大停機時間,這樣在有可能在最大停機時間內完成VM的遷移。

 live_migration_completion_timeout

這個參數列示整個遷移過程所允許的最大遷移時間,若超過這個時間遷移未完成,則遷移失敗,取消遷移。這個引數跟live_migration_downtime_delay一樣,也與記憶體有關係。實際的最大完成時間=live_migration_completion_timeout*VM記憶體大小(GiB)。live_migration_completion_timeout的預設值為800,假如虛擬機器的記憶體大小是4GiB,那麼意味著在3200s的時候,未遷移完成的該虛擬機器停止遷移,遷移失敗。

live_migration_permit_post_copy

live_migration_permit_post_copy是一種遷移模式,叫做後拷貝。在不設定此模式的情況下,VM都是通過前拷貝完成的,所謂前拷貝指的是VM上所有記憶體資料都是在切換到目標主機之前拷貝完的。而後拷貝會先儘可能快的切換到目標主機,因此後拷貝模式會先傳輸裝置的狀態和一部分(10%)資料到目標主機,然後就簡單的切換到目標主機上面執行虛擬機器。當發現訪問虛擬機器的某些記憶體page不存在時,就會產生一個遠端頁錯誤,觸發從源主機上面拉取該page的動作。這種後拷貝的遷移模式相對於前拷貝更加危險,當網路不同,或任意一臺主機出現故障的時候,虛擬機器會出現異常。

live_migration_permit_auto_converge

live_migration_permit_auto_converge是另一種遷移模式,叫做自動收斂。它在虛擬機器長時間處於高業務下而影響遷移的時候,調整vcpu的引數減少vcpu的負載,降低“髒記憶體”的增長速度,從而使遷移能夠順利完成。

在libvirtd中,當“髒記憶體“的增長速度大於遷移記憶體傳輸速度時,觸發自動收斂模式,libvirtd在一開始降低了20%的vcpu效能,如果“髒記憶體“的增長速度依舊大於遷移記憶體傳輸速度,則在此基礎上再降低10%的效能,直到“髒記憶體“的增長速度小於遷移記憶體傳輸速度。值得注意的是,該模式只能保證虛擬機器未遷移的記憶體持續減少,但不能保證遷移在設定的最大遷移時間內遷移完成。

  1.  

  2. NOVA在遷移流程中所做的事

  3. Conductor:

    1. 構建一個task,非同步執行。

    2. 如果沒有指定目標主機,向scheduler申請目標主機。

    3. 檢查一些條件:不能遷移到源主機、目標主機必須是up狀態、hypervisor型別必須一致、目標主機 hypervisor版本必須大於等於源主機hypervisor版本。

  4. S_compute:

    1. 檢查cpu架構相容、共享儲存等等。

    2. 向libvirtd傳送遷移指令:

      根據遷移flag引數選擇遷移模型

       
      1. 幾個重要的flag引數的含義如下

      2. VIR_MIGRATE_TUNNELLED:是否使用隧道網路傳輸數

      3. VIR_MIGRATE_PEER2PEER:是否啟用託管模式    

      4. VIR_MIGRATE_LIVE:是否啟用熱遷移

      5. VIR_MIGRATE_PERSIST_DEST:是否持久化域定義檔案到目標主機(也即使遷移過後,目標主機上面也有改虛擬機器的域定義檔案)

      6. VIR_MIGRATE_UNDEFINE_SOURCE:是否在遷移之後在源主機刪除域定義檔案

      7. VIR_MIGRATE_PAUSED:是否讓目標側的域一直處於掛起狀態

      還有其他的一些引數,可以參考libvirt.py檔案(centos7:/usr/lib64/python2.7/site-packages/libvirt.py)

    3. 更新xml域定義檔案
    4. 配置熱遷移頻寬,live_migration_bandwidth,如果設定成0,則會自動選擇一個合適的頻寬
    5. 監控libvirtd遷移進度

      1. libvirtd資料遷移邏輯:libvirtd遷移分3個階段完成

        • step1:標記所有的髒記憶體
        • step2:傳輸所有的髒記憶體,然後開始重新計算新產生的髒記憶體,如此迭代,直到某一個條件退出
        • step3:暫停虛擬機器,傳輸剩餘資料

        因此這裡最關鍵的點就在於step2階段的退出條件,早期的退出條件有:

        • 50%或者更少的記憶體需要遷移
        • 不需要進行2次迭代或迭代次數超過30次。
        • 動態配置downtime時間
        • host主機策略(比如host 5min後關機,這個時候就需要遷移所有的VMs)

        在L版openstack的時候,支援的是downtime配置時間,因此step2的每次迭代都會重新計算新的髒記憶體以及每次迭代所花掉的時間來估算頻寬,再根據頻寬和當前迭代的髒頁數,就可以計算出傳輸剩餘資料的時間。如果這個時間在配置的downtime時間內是可以接受的,就轉到step3,否則就繼續step2。

        配置downtime的step2存在一個問題,如果虛擬機器的髒記憶體產生速度很快,也就是意味每次迭代的資料量都很大,downtime時間一直無法滿足推出條件,無法進入step3。因此針對這種情況下,libvirt出了一些新的特性:

        • post-copy模式:前面所說的都屬於pre-copy模式,也就是說所有的資料都是在切換到目標主機之前拷貝完的。在post-copy模式下,會先儘可能快的切換到目標主機,因此後拷貝模式會先傳輸裝置的狀態和一部分(10%)資料到目標主機,然後就簡單的切換到目標主機上面執行虛擬機器。當發現訪問虛擬機器的某些記憶體page不存在時,就會產生一個遠端頁錯誤,觸發從源主機上面拉取該page的動作。當然這種模式也引發了另一個重要的問題:如果其中一臺主機當機,或出現故障,或網路不通等等,會導致整個虛擬機器異常。
        • 自動收斂模式:如果虛擬機器長時間處於高業務下而影響遷移的話,libvirtd會自動調整vcpu的引數減少vcpu的負載,達到降低髒記憶體的增長速度,從而保證遷step2的推出條件。

        這兩個新的特性在N版的openstack中都已經應用進來,可以通過live_migration_permit_auto_converge和live_migration_permit_post_copy來配置自動收斂和後拷貝模式。

      2. nova監控

        nova在遷移的過程中是作為客戶端的角色而存在,nova只有不斷的輪詢libvirtd才能獲得遷移的資訊,因此nova監控最核心的就是一個輪詢處理,nova會每隔0.5s向libvirtd輪詢遷移資訊,並以此來做一些處理,具體的處理也很簡單,不在這裡詳細說,這裡重點看下輪詢的幾個最核心的變數的含義:

        • downtime_steps:前面有說到libvirtd遷移由step2進入step3的條件是在downtime時間內,libvirtd能夠將剩餘的資料傳輸完畢。因此這個引數的主要設計邏輯是:分steps次給libvirtd喂downtime時間。那麼多久喂一次?一次喂多少?nova通過一個演算法來計算,這個演算法的變數有data_db,live_migration_downtime,live_migrate_downtime_steps,live_migrate_downtime_delay.其中後面3個引數都是可以通過配置檔案配置的。這個演算法最終會計算出一個元組列表,比如:[(0, 46), (150, 47), (300, 48)...]每個元組的第一個值是delay時間,第二個值downtime時間。直到最後一次就是你配置的live_migrate_downtime_delay和live_migration_downtime。
        • progress_timeout、progress_watermark:這兩個變數的設計主要是用來防止libvirtd遷移出現某種異常導致遷移資料在一定時間沒有發生變化,這時候就會啟動progress_timeout來中止輪詢。理論上,這種情況應該由libvirtd的配置來配置,而nova只需取出異常就可以,但是目前libvirtd並沒有相關配置。progress_watermark是用來標示上次查詢到的剩餘資料,在單次迭代中,如果資料有在遷移,那麼水位總是遞減的。社群在水位的處理上面是有問題的,社群並沒有考慮到當下次迭代開始之後,輪詢到的剩餘資料比上次迭代的水位要大,因此這時候應該把水位重新置位到當前迭代來重新標記,而不是讓水位停留在上次迭代的位置,從而錯誤的觸發progress_timeout。 我給社群提了一個patch,就是為了在下次迭代的時候,將水位重新置到當前迭代。在N版裡面,已經加入對後拷貝模式的支援,正如前面說的,後拷貝模式雖然能假象地提高遷移速度,但是是非安全性的。patch:https://review.openstack.org/#/c/374587/
        • completion_timeout:這個變數的設計主要就是防止libvirtd長時間處於遷移過程,可能是原因是當時的網路頻寬太低等等。這個時間是從一開始輪詢就開始計時的,一旦在completion_timeout時間內遷移沒有完成,就中止遷移。
    6. post_live_migration:在虛擬機器資料遷移成功之後,還需要做一些其他的配置資訊,比如:斷開磁碟連線、清除網路裝置、flag標誌位、例項事件,更新源主機可用資源、更新例項排程資訊、清除例項控制檯tokens

  5. D_compute

    1. pre_live_migration:配置例項目錄、映象磁碟準備、vnc埠等等一些需要修改在xml檔案裡面的資訊。

    2. post_live_migration:設定網路資訊、更新xml檔案、更新例項資訊。

 

virsh 檢視遷移進度

    1. nova 檢視遷移任務

相關文章