對虛擬機器進行實時熱遷移
眾所周知,對於虛擬化的工作負載(尤其是公有云場景),我們希望其具有足夠的高可用性。當一個服務在物理層面上暴斃了,或者因為網路原因斷開了和主叢集的連線,我們希望有備份機對於原有的服務進行實時的熱遷移(real-time & hot),而不丟失(或者很少丟失)原有的執行狀態。尤其是對於那些負載較高或者可用性要求較高的服務來說,這個技術在業務側進行混合雲部署時也比較有用。
本文描述了一種解決方案,對於這個過程中的技術細節和可能出現的問題進行了一些討論。
本專案的絕大部分思路來源於這篇非常經典的Remus論文:https://www.usenix.org/legacy/event/nsdi08/tech/full_papers/cully/cully_html/
這裡有一個示例專案的程式碼,客觀來說寫的略顯雜亂,僅供參考:https://github.com/mahiru23/intravisor/tree/syscall
快照機制
顯然,如果我們想要遷移一個服務,我們一定要有技術將一個服務的快照完整儲存下來並且在另一臺物理機上進行恢復。
如果你的服務是以一個程序/執行緒的方式存在,我們只需要遷移其上下文(thread context),當然也包括儲存系統的維護。如果是容器或者虛擬機器,我們可能需要一些額外的metadata和與底層基座/硬體解耦合的機制,這裡不做過多討論,僅為拋磚引玉。
如果你的叢集使用OSS等技術來進行外部儲存,則可以忽略對於同步持久化儲存的需求。
這裡我們討論一個最簡單的情況:一個單執行緒的程序,其可能的快照組成如下:
複製流水線(streaming replication pipeline)
一個典型的單執行緒複製流水線分為:停機(suspend) -> 快照採集(snapshot) -> 傳輸(network) -> 恢復(resume) 四個步驟。
模組化的主機操作流水線:
備份機操作流水線:
主備切換
我們需要一個靈敏的錯誤檢測器,可能由多種機制組成:
- heartbeat心跳包
- 已存在的socket網路連線監測
- 外部服務狀態檢測器(基於雲)
- 客戶端狀態反饋(基於端)
效能提升:非同步事件佇列(event queue)
根據需求,我們可能需要將快照採集和傳輸兩個過程解耦合,使得我們主服務的停機時間儘可能短。這就需要幾個額外的執行緒去採集並傳輸不同的資源,包括TCP狀態,disk,context等。
我們的事件可能是heartbeat/snapshot/disk ops/net ops/其他......
這樣我們就可以對頻寬和計算資源完全分開,並且動態調整了,甚至我們可以設定一個threshold來監控佇列的大小,是否阻塞。
效能提升:髒頁追蹤(dirty page tracking)
顯然我們不能在每一個複製週期都進行全量複製,相反,我們只傳輸自上一個複製週期以來被修改的那部分,也就是做增量的備份。
對於記憶體頁面來說,髒頁追蹤(dirty page tracking)機制是我們需要的。
我們透過mmap監控實體記憶體段,手動disable掉自動page的write back機制,將使用者虛擬頁面的管理許可權從kernel層面上移到user space層面,這也是本方案的一個核心要點。
在使用者空間,我們可以使用hash table對於使用者的頁面進行編碼,進行統一管理。
由於一個4KB的頁面可能只有很小一部分被修改,一個合理的最佳化是將本週期的頁面更新與上一個週期做差,用gzip或者run length encode做壓縮,這個最佳化在高頻複製時可以顯著降低傳輸中的頻寬需求。
代價
高可用永遠都是有代價的,額外的頻寬消耗/算力損耗/備份空間需求等都是潛在的問題,是否採用請自行抉擇。
複製的頻率從每秒10次到每10min一次或者更長,這一切也取決與你的個人需求(以及程式碼編寫水平)。
總結
以上,就這樣吧,如果有其他想要討論的內容評論區見。