近年來(lái),Linux 操作系統(tǒng)在技術(shù)、社區(qū)和商業(yè)化方案均取得了快速發(fā)展,移動(dòng)云先后發(fā)布了新一代天元操作系統(tǒng)和易行遷移工具,保障了移動(dòng)云全場(chǎng)景業(yè)務(wù)高效遷移。在移動(dòng)云 CentOS 遷移實(shí)踐過(guò)程中,跨操作系統(tǒng)虛機(jī)遷移是改造中的一個(gè)重要環(huán)節(jié),現(xiàn)網(wǎng)環(huán)境錯(cuò)綜復(fù)雜,如何保證客戶業(yè)務(wù)在虛機(jī)遷移過(guò)程不中斷,確保遷移后的虛機(jī)在 Linux 操作系統(tǒng)上平穩(wěn)運(yùn)行,在底層虛擬化側(cè)面臨諸多技術(shù)挑戰(zhàn)。
關(guān)鍵挑戰(zhàn)
虛擬化組件同源異構(gòu)
新的虛擬化組件需要在多款 Linux 操作系統(tǒng)上穩(wěn)定運(yùn)行,在不同操作系統(tǒng)和 CPU 架構(gòu)上共用同一份源碼,因此首先需要解決同源異構(gòu)難題。
OS 兼容適配
計(jì)算、存儲(chǔ)、SDN 等核心業(yè)務(wù)需要在 OS 之上相互兼容,在新的平臺(tái)上需要在中間層即虛擬化層解決一些業(yè)務(wù)兼容適配問(wèn)題。
跨 OS 不停服熱遷移
跨操作系統(tǒng)、跨虛擬化組件大版本的遷移,可能因虛機(jī) cpu 能力、內(nèi)存布局、設(shè)備結(jié)構(gòu)體等差異,導(dǎo)致遷移失敗影響業(yè)務(wù)連續(xù)性,這是虛機(jī)跨操作系統(tǒng)遷移過(guò)程中的一大難題。
虛擬化組件同源異構(gòu)
同源異構(gòu)可以屏蔽不同系統(tǒng)、不同架構(gòu)的差異,收縮現(xiàn)網(wǎng)版本,減小代碼維護(hù)的壓力。實(shí)現(xiàn)“一份代碼,一次編譯,處處運(yùn)行”。
在同源異構(gòu)改造過(guò)程中我們解決了諸多問(wèn)題,如:不同系統(tǒng)、不同架構(gòu)其編譯安裝依賴包會(huì)有差異,需要在 spec 文件中根據(jù)不同系統(tǒng)、架構(gòu)指定相應(yīng)的依賴。新舊虛擬化組件軟件包安裝時(shí)存在沖突,需利用 rpm 的 Obsoletes 機(jī)制刪除對(duì)應(yīng)安裝包,實(shí)現(xiàn)組件的平滑升級(jí)。另外由于新舊虛擬化組件差異大,導(dǎo)致舊版補(bǔ)丁回合后函數(shù)調(diào)用失敗,需要根據(jù)代碼差異重新設(shè)計(jì)實(shí)現(xiàn)部分功能。
OS 兼容適配
為了保證虛機(jī)能在 OS 上平穩(wěn)運(yùn)行,需要解決一些計(jì)算、存儲(chǔ)、SDN 同虛擬化組件在平臺(tái)上適配存在的問(wèn)題,并做一些優(yōu)化。
Python2 版本的兼容
隨著 Python2 的生命周期結(jié)束,libvirt-python 自 6.0.0 就停止了對(duì) Python2 的支持,但由于部分產(chǎn)品改造周期長(zhǎng),需要暫時(shí)維持使用 Python2 環(huán)境作為過(guò)渡,虛擬化作為底層組件,需要構(gòu)建一個(gè)基于 Python2 的 libvirt-python 組件包。 我們從 Python3 和 Python2 間語(yǔ)法差異、接口改變、模塊變化等方面入手,對(duì)適配 OS 上的 libvirt-python 代碼做了修改,包括:
針對(duì)數(shù)據(jù)類型、類的定義等語(yǔ)法差異上做了對(duì)應(yīng)修改。
針對(duì)異常捕獲、輸入輸出、迭代器等 API 使用差異部分做了對(duì)應(yīng)修改。
針對(duì) Python3 和 Python2 間名稱變化或廢棄的模塊做了對(duì)應(yīng)修改。
在修改了 50 多個(gè)文件,上千行代碼后,最終得到了一個(gè)基于 Python2 的穩(wěn)定可靠的 libvirt-python。
OVS-dpdk 與 QEMU 的適配
SDN 的穩(wěn)定性和可靠性直接影響到用戶虛機(jī)的網(wǎng)絡(luò)服務(wù)質(zhì)量,為了保證 SDN 能在新平臺(tái)上平穩(wěn)運(yùn)行,我們積極推動(dòng)各 SDN 廠商在 OS 上的適配工作,解決了多個(gè)適配問(wèn)題。
SDN 適配時(shí)發(fā)現(xiàn)當(dāng) QEMU 作為 server 時(shí),重啟 ovs,虛機(jī)可能會(huì) crash。查看 QEMU 的 coredump 文件,定位到如下代碼觸發(fā)了 crash。
當(dāng) QEMU 作為 server 端時(shí),一旦 ovs 重啟,按照上面代碼邏輯 QEMU 會(huì)主動(dòng)嘗試進(jìn)行 reconnect,過(guò)程中會(huì)改變網(wǎng)卡設(shè)備 tcp 狀態(tài)字為 TCP_CHARDEV_STATE_DISCONNECTED,此時(shí)會(huì)造成處理邏輯 bug,使得 QEMU 發(fā)生 crash(實(shí)際上 QEMU 作為 server 端時(shí),不應(yīng)進(jìn)行 reconnect 操作,而是由作為 client 端的 ovs 進(jìn)行 reconnect)。具體觸發(fā) crash 的流程如下:
解決方案是只有當(dāng) QEMU 作為 client,重啟 ovs,QEMU 才做 reconnect,問(wèn)題得到修復(fù)。 除上述問(wèn)題外,我們還解決了一些其他問(wèn)題,包括 ovs 熱升級(jí)后 windows 虛機(jī)網(wǎng)絡(luò)不通、海光平臺(tái)執(zhí)行 testpmd 測(cè)試程序虛機(jī)卡住等多個(gè)問(wèn)題。
卷遷移操作的效率優(yōu)化
分布式存儲(chǔ)為云平臺(tái)提供基礎(chǔ)存儲(chǔ)服務(wù),在使用中往往伴隨著一些卷遷移和容量查詢的操作,但這些操作實(shí)際執(zhí)行效率并不高,需要做一些優(yōu)化。
在 QEMU 原生版本實(shí)現(xiàn) Ceph 卷遷移功能時(shí),遷移前將 bitmap 每位都置臟,首輪遷移時(shí)會(huì)將源盤所有數(shù)據(jù)遷往目的盤(未寫入數(shù)據(jù)的部分以 0 寫入),導(dǎo)致遷移數(shù)據(jù)量增多,時(shí)間變長(zhǎng)。 我們對(duì) ceph 卷遷移做了優(yōu)化,減少了首輪遷移的數(shù)據(jù)量,效率得到大幅提升(尤其是源盤空間較大數(shù)據(jù)量較少時(shí)),具體步驟:
修改 QEMU 組件的 rbd 驅(qū)動(dòng),增加獲取后端集群 Ceph 卷已使用空間分布的接口。
遷移開(kāi)始時(shí),利用接口初始化卷遷移的 dirty bitmap。
遷移過(guò)程中,如果虛機(jī)新增 IO,將對(duì)應(yīng) dirty bitmap 置臟。不斷迭代清理 dirty bitmap,只對(duì)有數(shù)據(jù)的存儲(chǔ)塊進(jìn)行遷移拷貝,無(wú)數(shù)據(jù)的塊直接跳過(guò)。
當(dāng) dirty bitmap 全部清理時(shí)卷熱遷移完成。
此外還有一些其他優(yōu)化:
優(yōu)化 ceph 卷容量查詢,調(diào)用新的接口,其查詢效率提升 30%+。
QEMU 支持 ceph 卷 snapshot 遷移功能,遷移后依然保有源卷的快照信息。
跨 OS 不停服熱遷移
解決了同其他核心產(chǎn)品適配的各種問(wèn)題后,我們工作重點(diǎn)轉(zhuǎn)向了跨 OS 的遷移適配上來(lái)。我們與 openEuler 社區(qū)的 Virt SIG 成員進(jìn)行了深度協(xié)同聯(lián)創(chuàng),解決了跨 OS 遷移需要考慮 Guest 的 CPU 能力、設(shè)備狀態(tài)等多個(gè)方面的問(wèn)題。
目的端主板類型不兼容遷移失敗
從 BC-Linux7 系列系統(tǒng)往 BC-Linux For Euler 系列系統(tǒng)遷移時(shí)會(huì)有“unsupported machine type”的報(bào)錯(cuò),對(duì)比兩個(gè)操作系統(tǒng) QEMU 組件支持的 machine type,發(fā)現(xiàn) BC-Linux7 的虛擬化組件裁剪了 QEMU 社區(qū)原生的 Machine Type,完全自定義了私有的主板類型,無(wú)法正常熱遷移到 openEuler 上。
由于 machine type 在遷移時(shí)不能被改變,要想遷移成功,就必須在 BC-Linux For Euler 系統(tǒng)上的高版本 QEMU 兼容低版本的 machine type。為此,我們梳理低版本 QEMU 中每種 machine type 支持的設(shè)備,并在高版本 QEMU 上移植相應(yīng)的 machine type,這樣遷移時(shí)便不會(huì)出現(xiàn)主板類型不支持的問(wèn)題。
設(shè)備結(jié)構(gòu)體差異引起遷移失敗
QEMU 使用 VMStateDescription(VMSD)數(shù)據(jù)結(jié)構(gòu)來(lái)對(duì)設(shè)備狀態(tài)進(jìn)行描述和管理,遷移時(shí) VMSD 的 fields 和 subsections 會(huì)被發(fā)送到目的端。 要想虛機(jī)遷移成功,如果源端設(shè)備結(jié)構(gòu)體字段多于目的端,則目的端 vmstate_load_state 加載設(shè)備狀態(tài)時(shí),需要將多出來(lái)的字段 disable 掉,反之則需將缺少的字段跳過(guò)加載。
測(cè)試時(shí)我們發(fā)下虛機(jī)從 BC-Linux For Euler 系列系統(tǒng)往 BC-Linux7 系列系統(tǒng)回遷時(shí),對(duì)端無(wú)法成功接收鍵盤的設(shè)備狀態(tài)。對(duì)比鍵盤的 VMSD,高版 QEMU 增加了 kbd_extended_state 字段的發(fā)送,目的端因缺失該字段導(dǎo)致遷移失敗。
kbd_extended_state_needed 是判斷是否將 kbd_extended_state 字段發(fā)送的函數(shù)(默認(rèn) True)。為了保證虛機(jī)不會(huì)因?yàn)?kbd_extended_state 而導(dǎo)致回遷失敗,回遷時(shí)須將多出的 kbd_extended_state 字段不發(fā)送。
此外我們還比較了其他設(shè)備,尤其是 virtio 和 vhost_user 設(shè)備的 VMSD 在高低 QEMU 版本間的差異,對(duì)有差異的地方做了修改。
cpu feature 不兼容熱遷移失敗
虛機(jī) CPU 有 3 種模式:custom(指令集最少但熱遷移兼容性最好)、host-passthrough(指令集最多但熱遷移兼容性最差)和 host-model(介于兩者之間),但虛機(jī) cpu features 不僅和虛擬化配置有關(guān),還與宿主機(jī)的 CPU 型號(hào)、操作系統(tǒng)內(nèi)核等有關(guān)。即使是在 custom 或 host-model 模式下,我們也遇到一些因目的端缺失 cpu features 而導(dǎo)致的遷移失敗的問(wèn)題。
case1:目的端缺失 arch-facilities 特性
由于高版本 libvirt 將同一 cpu feature 名稱由 arch-facilities 變?yōu)榱?arch-capabilities,目的端不識(shí)別 arch-facilities,導(dǎo)致熱遷移失敗。需要在源端的 cpu_map.xml 中將其修改為 arch-capabilities 才能通過(guò) cpu feature 兼容性檢查。
case2:目的端缺失 spec_ctrl 特性
BC-Linux7 系列系統(tǒng)上使用的 3.10 內(nèi)核需要使能 spec_ctrl 來(lái)避免“幽靈漏洞”,但 BC-Linux For Euler 系列系統(tǒng)使用的 4.19 內(nèi)核通過(guò)其他方式避免了該漏洞,關(guān)閉了 spec_ctrl,需要更新微碼才能在目的端使能 spec_ctrl 特性。
case3:目的端缺失 hle/rtm 特性
配置 host-model 的模式虛機(jī)因目的端缺失 hle/rtm 特性導(dǎo)致熱遷移失敗。需要在目的節(jié)點(diǎn)的內(nèi)核的啟動(dòng)參數(shù)增加“tsx=on”來(lái)使能相關(guān)指令集。
總結(jié)
我們做了虛擬化組件的同源異構(gòu)、對(duì) OS 兼容適配,并與 openEuler 社區(qū)進(jìn)行深度聯(lián)創(chuàng),實(shí)現(xiàn)跨 OS 不停服熱遷移優(yōu)化,從原理和實(shí)踐兩個(gè)方面,保障了 CentOS 的遷移改造任務(wù)得以高效進(jìn)行。 然而移動(dòng)云現(xiàn)網(wǎng)有海量的節(jié)點(diǎn)需要做遷移,這對(duì)遷移的效率與成功率有了更高的要求,在下期的分享中,我們將帶來(lái)對(duì)熱遷移性能提升優(yōu)化做的技術(shù)分享,敬請(qǐng)期待! ?
評(píng)論
查看更多