業(yè)務(wù)不停轉(zhuǎn),遷移已完結(jié),Linode 實(shí)時(shí)遷移到底怎么做到?
當(dāng)開(kāi)發(fā)者將工作負(fù)載部署到云計(jì)算平臺(tái)時(shí),往往并不需要考慮運(yùn)行這些服務(wù)的底層硬件。在人們對(duì)“云” 的理想化印象中,硬件維護(hù)和物理限制往往是無(wú)形的,然而硬件不可避免需要時(shí)不時(shí)進(jìn)行維護(hù),這可能會(huì)導(dǎo)致停機(jī)。為避免這樣的停機(jī)時(shí)間被轉(zhuǎn)嫁給我們的客戶,并真正實(shí)現(xiàn)云的承諾,Linode 提供了一種名為實(shí)時(shí)遷移(Live Migration)的工具。
借助實(shí)時(shí)遷移技術(shù),Linode 實(shí)例可在不中斷服務(wù)的前提下在不同物理服務(wù)器之間移動(dòng)。通過(guò)實(shí)時(shí)遷移工具移動(dòng) Linode 實(shí)例時(shí),遷移過(guò)程對(duì) Linode 實(shí)例中運(yùn)行的進(jìn)程是完全不可見(jiàn)的。如果一臺(tái)主機(jī)的硬件需要維護(hù),即可通過(guò)實(shí)時(shí)遷移,將該主機(jī)上的所有 Linode 實(shí)例無(wú)縫轉(zhuǎn)移到另一臺(tái)主機(jī)中。遷移操作完成后,即可開(kāi)始修理物理硬件,全過(guò)程中并不產(chǎn)生會(huì)影響到客戶的停機(jī)時(shí)間。
這幾乎成為一種決定性的技術(shù),也成為云技術(shù)和非云技術(shù)之間的轉(zhuǎn)折點(diǎn)。本文我們將深入了解這項(xiàng)技術(shù)背后的細(xì)節(jié)。
延伸閱讀,了解Akamai cloud-computing
實(shí)時(shí)遷移的工作原理
和大部分新項(xiàng)目類似,Linode 的實(shí)時(shí)遷移也是這樣啟動(dòng)的:進(jìn)行大量研究,創(chuàng)建一系列原型,獲得同事和管理層的大量幫助。我們的第一步是調(diào)查 QEMU 如何處理實(shí)時(shí)遷移。QEMU 是 Linode 使用的一種虛擬化技術(shù),而實(shí)時(shí)遷移也是 QEUM 的一項(xiàng)功能。因此我們團(tuán)隊(duì)的重點(diǎn)是將這項(xiàng)技術(shù)引入 Linode,而非重新發(fā)明一個(gè)類似的技術(shù)。
那么實(shí)時(shí)遷移技術(shù)到底是如何以 QEMU 的方式實(shí)現(xiàn)的?整個(gè)過(guò)程分為以下四步:
- 啟動(dòng)目標(biāo) QEUM 實(shí)例,該實(shí)例的各項(xiàng)參數(shù)與需要遷移的源 QEUM 實(shí)例完全相同。
- 對(duì)磁盤進(jìn)行實(shí)時(shí)遷移。數(shù)據(jù)傳輸過(guò)程中,對(duì)磁盤內(nèi)容進(jìn)行的任何更改也會(huì)提交至目標(biāo)磁盤。
- 對(duì)內(nèi)存數(shù)據(jù)進(jìn)行實(shí)時(shí)遷移。遷移過(guò)程中,內(nèi)存內(nèi)容的任何變化也會(huì)提交至目標(biāo)內(nèi)存。如果這一過(guò)程中磁盤內(nèi)容也出現(xiàn)了變化,相關(guān)變化同樣會(huì)被提交至目標(biāo) QEUM 實(shí)例的磁盤中。
- 執(zhí)行割接點(diǎn)。當(dāng) QEMU 確認(rèn)有足夠多的內(nèi)存頁(yè)可以放心進(jìn)行割接后,源和目標(biāo) QEMU 實(shí)例將會(huì)暫停。QEMU 會(huì)復(fù)制最后幾頁(yè)內(nèi)存數(shù)據(jù)和機(jī)器狀態(tài),機(jī)器狀態(tài)包括 CPU 緩存和下一條 CPU 指令。隨后,QEMU 會(huì)讓目標(biāo)開(kāi)始運(yùn)行,這樣目標(biāo)實(shí)例就可以從源實(shí)例停止時(shí)的狀態(tài)恢復(fù)運(yùn)行了。
這些步驟概括介紹了 QEMU 實(shí)時(shí)遷移的執(zhí)行過(guò)程。然而依然需要通過(guò)包含很多手工操作的方式來(lái)精確指定目標(biāo) QEMU 實(shí)例的啟動(dòng)方式。此外,上述過(guò)程中的每個(gè)操作都必須在正確的時(shí)間執(zhí)行。
Linode 實(shí)現(xiàn)實(shí)時(shí)遷移的方式
在分析過(guò) QEMU 開(kāi)發(fā)者已經(jīng)實(shí)現(xiàn)的技術(shù)后,我們?cè)摽紤]具體用怎樣的方式將其實(shí)給 Linode。這個(gè)答案恰恰是我們工作的重中之重。
在實(shí)時(shí)遷移工作流程的第 1 步,需要啟動(dòng)目標(biāo) QEMU 實(shí)例以接受傳入的實(shí)時(shí)遷移連接。在實(shí)現(xiàn)這一步時(shí),我們最初的想法是拿到當(dāng)前 Linode 實(shí)例的配置文件,隨后將其應(yīng)用到目標(biāo)計(jì)算機(jī)。理論上這應(yīng)該很簡(jiǎn)單,但進(jìn)一步思考就會(huì)發(fā)現(xiàn),實(shí)際情況要復(fù)雜很多。尤其是,配置文件雖然可以告訴我們 Linode 實(shí)例是如何啟動(dòng)的,但并不一定可以完整描述啟動(dòng)后的 Linode 實(shí)例的完整狀態(tài)。例如,用戶可以在 Linode 實(shí)例啟動(dòng)完畢后通過(guò)熱插拔的方式連接塊存儲(chǔ)設(shè)備,但這種情況并不會(huì)記錄到配置文件中。
為了在目標(biāo)主機(jī)上創(chuàng)建 QEMU 實(shí)例,必須對(duì)當(dāng)前運(yùn)行的 QEMU 實(shí)例進(jìn)行剖析。我們通過(guò)檢查 QMP 接口的方式對(duì)運(yùn)行中的 QEMU 實(shí)例進(jìn)行剖析,該接口為我們提供了與 QEMU 實(shí)例布局情況有關(guān)的豐富信息,但它無(wú)法幫助我們從來(lái)賓系統(tǒng)的視角了解實(shí)例內(nèi)部正在發(fā)生的事情。例如,對(duì)于本地 SSD 和塊存儲(chǔ),它只能告訴我們磁盤鏈接到哪里,以及虛擬磁盤連接到哪個(gè)虛擬化 PCI 插槽上。在查詢 QMP 以及檢查并分析了 QEMU 接口后,可以構(gòu)建一個(gè) Profile 來(lái)描述如何在目標(biāo)位置創(chuàng)建一個(gè)完全相同的實(shí)例。
在目標(biāo)計(jì)算機(jī)上,我們將收到完整的描述信息,借此了解源實(shí)例到底是什么樣,隨后就可以在目標(biāo)位置忠實(shí)重建這個(gè)實(shí)例,但此時(shí)還有一個(gè)差異。這個(gè)差別主要在于,目標(biāo) QEMU 實(shí)例在啟動(dòng)時(shí)使用了一個(gè)選項(xiàng),該選項(xiàng)可以讓 QEMU 接受傳入的遷移。
至此,實(shí)時(shí)遷移的記錄過(guò)程已經(jīng)基本結(jié)束,接下來(lái)需要看看 QEMU 是如何實(shí)現(xiàn)這些操作的。QEMU 進(jìn)程樹(shù)由一個(gè)控制進(jìn)程和多個(gè)工作進(jìn)程組成,其中一個(gè)工作進(jìn)程負(fù)責(zé)返回 QMP 調(diào)用或處理實(shí)時(shí)遷移等任務(wù),其他進(jìn)程需要一對(duì)一映射至來(lái)賓 CPU。來(lái)賓環(huán)境與 QEMU 端的功能相互隔離,具體行為類似于獨(dú)立的系統(tǒng)。
從這個(gè)意義來(lái)看,我們需要處理三層內(nèi)容:
- 第 1 層是管理層;
- 第 2 層是 QEMU 進(jìn)程的一部分,負(fù)責(zé)處理所有操作;
- 第 3 層是實(shí)際的來(lái)賓層,負(fù)責(zé)與 Linode 用戶進(jìn)行交互。
目標(biāo)實(shí)例啟動(dòng)并準(zhǔn)備好接受傳入的遷移后,目標(biāo)硬件會(huì)告知源硬件開(kāi)始發(fā)送數(shù)據(jù)。源端會(huì)在收到這個(gè)信號(hào)后開(kāi)始進(jìn)行處理,并會(huì)在軟件中告知 QEMU 開(kāi)始傳輸磁盤內(nèi)容。軟件會(huì)自主監(jiān)控磁盤傳輸進(jìn)度,借此檢查傳輸操作是否完成,并會(huì)在磁盤傳輸完成后自動(dòng)開(kāi)始遷移內(nèi)存內(nèi)容。此時(shí)軟件依然會(huì)自主監(jiān)控內(nèi)存遷移進(jìn)度,并在內(nèi)存遷移完畢后自動(dòng)切換至割接模式。上述全過(guò)程都是通過(guò) Linode 的 40Gbps 網(wǎng)絡(luò)進(jìn)行的,因此網(wǎng)絡(luò)方面的操作都可以快速完成。
割接:關(guān)鍵環(huán)節(jié)
割接操作是實(shí)時(shí)遷移過(guò)程中最重要的一環(huán),只有理解了它,才能完全理解實(shí)時(shí)遷移操作。
在割接點(diǎn)狀態(tài)下,QEMU 已經(jīng)確認(rèn)做好了所有準(zhǔn)備,可以進(jìn)行割接并在目標(biāo)計(jì)算機(jī)上運(yùn)行。源 QEMU 實(shí)例會(huì)讓兩端暫停運(yùn)行,這意味著:
- 來(lái)賓系統(tǒng)被“時(shí)停”。如果來(lái)賓系統(tǒng)正在運(yùn)行時(shí)間同步服務(wù)(如 NTP),NTP 會(huì)在遷移完成后自動(dòng)重新同步時(shí)間。這是因?yàn)橄到y(tǒng)時(shí)鐘會(huì)產(chǎn)生幾秒鐘的落后。
- 網(wǎng)絡(luò)請(qǐng)求停止。如果網(wǎng)絡(luò)請(qǐng)求是 TCP 請(qǐng)求(如 SSH 或 HTTP),基本上不會(huì)產(chǎn)生可感知的連接中斷;如果網(wǎng)絡(luò)請(qǐng)求是 UDP 請(qǐng)求(如流媒體視頻),可能會(huì)導(dǎo)致少量丟幀。
由于時(shí)間和網(wǎng)絡(luò)請(qǐng)求均已停止,我們希望割接能盡量快速完成。然而為保證成功割接,還需要進(jìn)行一些檢查:
- 確保實(shí)時(shí)遷移順利完成不出錯(cuò)。如果出錯(cuò)則要進(jìn)行回滾,解除源 Linode 實(shí)例的暫停狀態(tài),不再進(jìn)一步執(zhí)行其他操作。開(kāi)發(fā)過(guò)程中,我們?cè)谶@方面進(jìn)行了大量實(shí)驗(yàn)并解決了很多錯(cuò)誤,雖然這為我們?cè)斐闪撕芏囝^疼的問(wèn)題,但最終都順利解決了。
- 確保關(guān)閉源實(shí)例的網(wǎng)絡(luò),并在目標(biāo)實(shí)例上正確連接。
- 讓我們的其余基礎(chǔ)設(shè)施清楚得知遷移后的 Linode 實(shí)例是通過(guò)哪臺(tái)物理計(jì)算機(jī)運(yùn)行的。
由于割接過(guò)程時(shí)間有限,我們希望能盡快完成上述操作。解決了這些問(wèn)題后,即可繼續(xù)進(jìn)行割接了。源 Linode 實(shí)例會(huì)自動(dòng)會(huì)自動(dòng)收到 “割接完成” 信號(hào)并讓目標(biāo)實(shí)例運(yùn)行起來(lái)。目標(biāo) Linode 實(shí)例會(huì)從源實(shí)例暫停時(shí)的狀態(tài)恢復(fù)運(yùn)行。源和目標(biāo)實(shí)例上的其余內(nèi)容則會(huì)被清理。如果目標(biāo) Linode 實(shí)例在未來(lái)某個(gè)時(shí)間需要再次進(jìn)行實(shí)時(shí)遷移,則會(huì)重復(fù)執(zhí)行上述步驟。
邊緣案例概述
實(shí)時(shí)遷移的大部分過(guò)程都是直接實(shí)現(xiàn)的,但考慮到邊緣案例后,該功能本身的開(kāi)發(fā)也進(jìn)行了大量擴(kuò)展。這個(gè)項(xiàng)目的順利完成很大程度上要?dú)w功于管理團(tuán)隊(duì),他們堅(jiān)信該工具有著極大的愿景,并提供了完成該任務(wù)所需的各項(xiàng)資源,另外當(dāng)然也離不開(kāi)堅(jiān)信該項(xiàng)目能夠成功完成的大量員工。
我們?cè)谙铝羞@些領(lǐng)域遇到了很多邊緣案例:
- 通過(guò)開(kāi)發(fā)內(nèi)部工具為 Linode 客戶支持人員和硬件運(yùn)維團(tuán)隊(duì)進(jìn)行與實(shí)時(shí)遷移有關(guān)的協(xié)調(diào)工作。這些工具與我們當(dāng)時(shí)正在使用的其他同類工具較為類似,但也有些許差異,我們?yōu)榇送度肓舜罅块_(kāi)發(fā)工作:
- 該工具必須能自動(dòng)檢查數(shù)據(jù)中心內(nèi)部的所有硬件設(shè)施,進(jìn)而確定哪臺(tái)主機(jī)可以成為每個(gè)需要遷移的 Linode 實(shí)例的最佳目標(biāo)。在進(jìn)行這種選擇和決策時(shí),考慮的相關(guān)規(guī)格包括可用 SSD 存儲(chǔ)空間及內(nèi)存分配情況等。
- 目標(biāo)計(jì)算機(jī)的物理處理器必須與傳入的 Linode 實(shí)例相兼容。尤其是 CPU 必須具備用戶所運(yùn)行的軟件必不可少的某些功能(我們將其稱之為 CPU 標(biāo)記)。例如,AES 就是這樣的一種功能,該功能提供了基于硬件加速的加密能力。實(shí)時(shí)遷移的目標(biāo)計(jì)算機(jī) CPU 必須支持與源計(jì)算機(jī)相同的 CPU 標(biāo)記。我們發(fā)現(xiàn)這是一種極為復(fù)雜的邊緣用例,下文將介紹我們所采用的方法。
- 優(yōu)雅地處理故障,包括最終用戶的干預(yù)或?qū)崟r(shí)遷移過(guò)程中網(wǎng)絡(luò)連接丟失等情況。下文還將詳細(xì)介紹這些信息。
- 緊跟 Linode 平臺(tái)自身的變化,而這是一個(gè)持續(xù)不斷的長(zhǎng)期過(guò)程。對(duì)于 Linode 平臺(tái)當(dāng)前和未來(lái)所支持的每個(gè)功能,我們都需要確保這些功能可與實(shí)時(shí)遷移兼容。詳細(xì)信息請(qǐng)繼續(xù)閱讀下文。
CPU 標(biāo)記
在向來(lái)賓操作系統(tǒng)呈現(xiàn) CPU 方面,QEMU 有不同的選項(xiàng)。其中一個(gè)選項(xiàng)可將主機(jī) CPU 的型號(hào)和功能(即 CPU 標(biāo)記)直接傳遞給來(lái)賓系統(tǒng)。通過(guò)使用該選項(xiàng),來(lái)賓即可不受約束地使用 KVM 虛擬化系統(tǒng)所支持的全部能力。當(dāng) Linode 首次采用 KVM 時(shí)(當(dāng)時(shí)還沒(méi)有實(shí)時(shí)遷移功能),為了實(shí)現(xiàn)最大化性能,我們就使用了該選項(xiàng)。然而在開(kāi)發(fā)實(shí)時(shí)遷移功能的過(guò)程中,該選項(xiàng)為我們?cè)斐闪撕芏嗵魬?zhàn)。
在實(shí)時(shí)遷移的測(cè)試環(huán)境中,源和目標(biāo)主機(jī)是兩臺(tái)完全相同的計(jì)算機(jī)。但在現(xiàn)實(shí)世界中,我們的硬件集群并非 100% 完全相同的,計(jì)算機(jī)之間的某些配置差異可能導(dǎo)致產(chǎn)生不同的 CPU 標(biāo)記。這很重要,因?yàn)楫?dāng)一個(gè)程序被載入 Linode 的操作系統(tǒng)后,Linode 會(huì)向該程序呈現(xiàn) CPU 標(biāo)記,為了充分利用這些標(biāo)記,程序可以將軟件中的特定部分載入內(nèi)存。如果一個(gè) Linode 實(shí)例被實(shí)時(shí)遷移到不支持該 CPU 標(biāo)記的目標(biāo)計(jì)算機(jī),程序?qū)?huì)崩潰。這可能導(dǎo)致來(lái)賓操作系統(tǒng)崩潰,甚至導(dǎo)致 Linode 重啟動(dòng)。
我們發(fā)現(xiàn)有三個(gè)因素會(huì)影響到計(jì)算機(jī)的 CPU 標(biāo)記如何呈現(xiàn)給來(lái)賓系統(tǒng):
- 取決于購(gòu)買時(shí)間,不同 CPU 之間會(huì)存在一些細(xì)微差異。取決于 CPU 制造商何時(shí)發(fā)布新硬件,年底購(gòu)買的 CPU 可能與年初購(gòu)買的具備不同標(biāo)記。為了擴(kuò)容,Linode 會(huì)持續(xù)購(gòu)買新硬件,但就算兩個(gè)硬件訂單購(gòu)買了同款 CPU,它們的 CPU 標(biāo)記也可能存在差異。
- 不同的 Linux 內(nèi)核可能會(huì)向 QEMU 傳遞不同的標(biāo)記。尤其是,參與實(shí)時(shí)遷移的源計(jì)算機(jī)的 Linux 內(nèi)核可能會(huì)向 QEMU 傳遞與目標(biāo)計(jì)算機(jī)的 Linux 內(nèi)核不同的標(biāo)記。為源計(jì)算機(jī)更新 Linux 內(nèi)核必須重啟動(dòng),因此無(wú)法在實(shí)時(shí)遷移之前通過(guò)升級(jí)內(nèi)核版本的方式解決這種不匹配問(wèn)題,因?yàn)檫@會(huì)導(dǎo)致計(jì)算機(jī)上的 Linode 實(shí)例停機(jī)。
- 同理,不同的 QEMU 版本也會(huì)影響所呈現(xiàn)的 CPU 標(biāo)記。更新 QEMU 同樣需要重啟動(dòng)計(jì)算機(jī)。
因此在實(shí)現(xiàn)實(shí)時(shí)遷移時(shí),我們必須設(shè)法防止程序因?yàn)?CPU 標(biāo)記的不匹配而崩潰。可行的選項(xiàng)有兩個(gè):
- 讓 QEMU 模擬 CPU 標(biāo)記。但這可能導(dǎo)致原本快速運(yùn)行的軟件運(yùn)行速度變慢,并且完全無(wú)法調(diào)查原因。
- 收集源計(jì)算機(jī)的 CPU 標(biāo)記列表,確保目標(biāo)計(jì)算機(jī)具備完全相同的標(biāo)記,隨后再進(jìn)行遷移。這種方式更復(fù)雜,但不會(huì)影響用戶程序的運(yùn)行速度。我們最終選擇了這種方式。
在決定對(duì)源和目標(biāo)的 CPU 標(biāo)記進(jìn)行匹配后,我們使用下列兩種方法的組合最終實(shí)現(xiàn)了目標(biāo):
- 第一種方法更簡(jiǎn)單。將源硬件的所有 CPU 標(biāo)記發(fā)送給目標(biāo)硬件,當(dāng)目標(biāo)硬件設(shè)置新的 QEMU 實(shí)例時(shí),會(huì)通過(guò)檢查來(lái)確保自己至少擁有和源 Linode 實(shí)例相同的標(biāo)記。如果不匹配,將不進(jìn)行實(shí)時(shí)遷移。
- 第二種方法更復(fù)雜,但可以避免因?yàn)?CPU 標(biāo)記不匹配導(dǎo)致的遷移失敗。在發(fā)起實(shí)施遷移前,我們會(huì)對(duì)具備可兼容 CPU 標(biāo)記的硬件創(chuàng)建一個(gè)列表,隨后從該列表中選擇硬件來(lái)創(chuàng)建目標(biāo)計(jì)算機(jī)。
第二種方法必須能快速執(zhí)行,并且讓我們的工作變得更復(fù)雜。某些情況下,我們需要針對(duì)超過(guò) 900 臺(tái)計(jì)算機(jī)檢查最多 226 個(gè) CPU 標(biāo)記。為所有這 226 個(gè) CPU 標(biāo)記編寫檢查代碼本就很困難,而這些代碼還需要不斷進(jìn)行維護(hù)。但 Linode 的創(chuàng)始人 Chris Aker 提出的一個(gè)驚人想法最終解決了這個(gè)問(wèn)題。
方法的關(guān)鍵在于為所有 CPU 標(biāo)記創(chuàng)建一個(gè)列表,并將其表示為一個(gè)二進(jìn)制字符串。隨后,可以使用 Bitwise and(“按位與”)運(yùn)算來(lái)對(duì)比字符串。我們可以用下面這個(gè)簡(jiǎn)單的例子來(lái)演示這個(gè)算法。下面這段 Python 代碼可以使用 “按位與” 對(duì)比兩個(gè)數(shù):
>>> 1 & 1
1
>>> 2 & 3
2
>>> 1 & 3
1
要理解為何“按位與” 運(yùn)算能產(chǎn)生這樣的結(jié)果,首先需要將數(shù)字用二進(jìn)制形式表示。一起看看十進(jìn)制的“2” 和“3” 在用二進(jìn)制形式表示的情況下,“按位與” 是如何處理的:
>>> # 2: 00000010
>>> # &
>>> # 3: 00000011
>>> # =
>>> # 2: 00000010
“按位與” 會(huì)對(duì)比二進(jìn)制的“數(shù)”,也就是兩個(gè)不同數(shù)字中的“位”。該操作會(huì)從上述數(shù)字最右邊的位開(kāi)始向左處理:
- “2” 和“3” 最右側(cè)(第一)位分別是“0” 和“1”,0 & 1 的按位與結(jié)果為 “0”。
- “2” 和“3” 右數(shù)第二位都是“1”,1 & 1 的按位與結(jié)果為 “1”。
- 這兩個(gè)數(shù)的所有其他位都是“0”,0 & 0 的按位與結(jié)果為 “0”。
因此完整結(jié)果的二進(jìn)制表示就是 00000010,也就是十進(jìn)制的 “2”。
對(duì)于實(shí)時(shí)遷移,CPU 標(biāo)記完整列表會(huì)表示為一個(gè)二進(jìn)制字符串,其中每一位都代表一個(gè)標(biāo)記。如果一個(gè)位為 “0”,代表對(duì)應(yīng)的標(biāo)記不存在;如果某個(gè)位為“1”,則代表標(biāo)記存在。例如,一個(gè)位可以代表 AES 標(biāo)記,另一個(gè)位可以代表 MMX 標(biāo)記。這些標(biāo)記在二進(jìn)制字符串中的位置會(huì)維護(hù)并記錄在案,隨后用于我們數(shù)據(jù)中心內(nèi)的所有計(jì)算機(jī)。
相比維護(hù)一組 if 語(yǔ)句來(lái)檢查某個(gè) CPU 標(biāo)記是否存在,這種列表的維護(hù)工作無(wú)疑更簡(jiǎn)單也更高效。例如,假設(shè)總共需要追蹤并檢查 7 個(gè) CPU 標(biāo)記,這些標(biāo)記可以存儲(chǔ)在一個(gè) 8 位數(shù)字中(多出的一位供未來(lái)進(jìn)行擴(kuò)展)。例如這樣的字符串可能類似于 00111011,最右側(cè)的一位代表 AES 已啟用,右數(shù)第二位代表 MMX 已啟用,右數(shù)第三位代表其他標(biāo)記已啟用,以此類推。
在下文的代碼片段中,我們可以看到哪些硬件支持這些標(biāo)記的組合,這段代碼可以在一個(gè)周期內(nèi)返回所有匹配的結(jié)果。如果用一組 if 語(yǔ)句進(jìn)行對(duì)比,則需要更多周期才能獲得所需結(jié)果。如果進(jìn)行實(shí)時(shí)遷移的源計(jì)算機(jī)包含 4 個(gè) CPU 標(biāo)記,這種情況下就需要 203400 個(gè)周期才能找到匹配的硬件。
實(shí)時(shí)遷移操作會(huì)在源和目標(biāo)計(jì)算機(jī)上針對(duì) CPU 標(biāo)記字符串執(zhí)行 “按位與” 操作。如果兩臺(tái)個(gè)計(jì)算機(jī)的 CPU 標(biāo)記字符串運(yùn)算結(jié)果相等,意味著目標(biāo)計(jì)算機(jī)是兼容的。該過(guò)程可參考下列 Python 代碼片段:
>>> # The b'' syntax below represents a binary string
>>>
>>> # The s variable stores the example CPU flag
>>> # string for the source:
>>> s = b'00111011'
>>> # The source CPU flag string is equivalent to the number 59:
>>> int(s.decode(), 2)
59
>>>
>>> # The d variable stores the example CPU flag
>>> # string for the source:
>>> d = b'00111111'
>>> # The destination CPU flag string is equivalent to the number 63:
>>> int(d.decode(), 2)
63
>>>
>>> # The bitwise and operation compares these two numbers:
>>> int(s.decode(), 2) & int(d.decode(), 2) == int(s.decode(), 2)
True
>>> # The previous statement was equivalent to 59 & 63 == 59.
>>>
>>> # Because source & destination == source,
>>> # the machines are compatible
請(qǐng)注意,在上述代碼片段中,目標(biāo)計(jì)算機(jī)比源計(jì)算機(jī)支持更多的標(biāo)記。此時(shí)可以認(rèn)為目標(biāo)計(jì)算機(jī)是兼容的,因?yàn)樵吹乃?CPU 標(biāo)記都已包含在目標(biāo)計(jì)算機(jī)中,這一點(diǎn)可以由 “按位與” 運(yùn)算提供保證。
我們的內(nèi)部工具可以使用上述算法得到的結(jié)果為可兼容的硬件構(gòu)建一個(gè)列表。該列表會(huì)展示給我們的客戶支持和硬件運(yùn)維團(tuán)隊(duì),這些團(tuán)隊(duì)可以使用我們的內(nèi)部工具來(lái)編排不同的運(yùn)維任務(wù):
- 使用該工具為特定 Linode 實(shí)例挑選兼容性最高的硬件。
- 在不指定目標(biāo)的情況下發(fā)起 Linode 實(shí)例實(shí)時(shí)遷移。隨后,同一數(shù)據(jù)中心內(nèi)兼容性最高的硬件會(huì)被自動(dòng)選中并立即開(kāi)始遷移。
- 通過(guò)一個(gè)任務(wù),對(duì)一臺(tái)主機(jī)上的所有 Linode 實(shí)例發(fā)起實(shí)時(shí)遷移。針對(duì)主機(jī)執(zhí)行維護(hù)任務(wù)前通常會(huì)執(zhí)行這樣的操作。我們的工具會(huì)自動(dòng)為所有實(shí)例選擇目標(biāo),并為每個(gè)實(shí)例進(jìn)行必要的編排。
- 將需要維護(hù)的多臺(tái)計(jì)算機(jī)指定為一個(gè)列表,我們的工具可以跨越所有主機(jī),自動(dòng)為所有實(shí)例編排實(shí)時(shí)遷移。
僅僅為了讓軟件能夠“跑起來(lái)”,就需要進(jìn)行大量的開(kāi)發(fā)工作……
失敗處理
軟件領(lǐng)域有一個(gè)話題很少被人討論:優(yōu)雅地處理失敗。軟件至少應(yīng)該能夠“跑起來(lái)”。為了實(shí)現(xiàn)這一點(diǎn),往往需要進(jìn)行大量開(kāi)發(fā)工作,實(shí)時(shí)遷移功能的開(kāi)發(fā)也是如此。我們花了很多時(shí)間考慮如果該工具無(wú)法正常運(yùn)行要怎么辦,以及該如何優(yōu)雅地處理這種情況。我們考慮了很多場(chǎng)景,并確定了具體的應(yīng)對(duì)方式:
- 如果客戶希望從Cloud Manager訪問(wèn) Linode 的某項(xiàng)功能該如何處理?例如用戶可能會(huì)重啟動(dòng) Linode 或?yàn)閷?shí)例連接 Block Storage Volume。
解決方法:客戶完全可以這樣做。實(shí)時(shí)遷移會(huì)被打斷,無(wú)法繼續(xù)處理。這種處理方法是合適的,因?yàn)閷?shí)時(shí)遷移可以稍后重試。
- 目標(biāo) Linode 啟動(dòng)失敗怎么辦?
解決方法:通知源硬件,通過(guò)專門設(shè)計(jì)的內(nèi)部工具在數(shù)據(jù)中心內(nèi)自動(dòng)選擇另一個(gè)硬件。此外還將通知運(yùn)維團(tuán)隊(duì),以便調(diào)查失敗的目標(biāo)硬件。這種情況曾在生產(chǎn)環(huán)境中發(fā)生過(guò),我們的實(shí)時(shí)遷移可以順利應(yīng)對(duì)。
- 如果遷移過(guò)程中網(wǎng)絡(luò)連接丟失該怎么辦?
解決方法:自主監(jiān)測(cè)實(shí)時(shí)遷移進(jìn)度,如果過(guò)去一分鐘內(nèi)沒(méi)有產(chǎn)生任何進(jìn)展,將會(huì)取消實(shí)時(shí)遷移并通知運(yùn)維團(tuán)隊(duì)。這種情況在測(cè)試環(huán)境之外從未發(fā)生過(guò),但我們也針對(duì)這種場(chǎng)景做好了充分準(zhǔn)備。
- 如果互聯(lián)網(wǎng)的其他部分?jǐn)嚅_(kāi)了,但源和目標(biāo)硬件依然在運(yùn)行和通信,并且源和目標(biāo) Linode 實(shí)例都在正常運(yùn)行,此時(shí)會(huì)發(fā)生什么情況?
解決方法:如果實(shí)時(shí)遷移未進(jìn)行到關(guān)鍵環(huán)節(jié),將停止實(shí)時(shí)遷移,并在稍后重試。
如果已進(jìn)行到關(guān)鍵環(huán)節(jié),則將繼續(xù)遷移。這一點(diǎn)很重要,因?yàn)樵?Linode 已被暫停,目標(biāo) Linode 需要處于啟動(dòng)狀態(tài)才能繼續(xù)恢復(fù)操作。
這些場(chǎng)景都已在測(cè)試環(huán)境中進(jìn)行了模擬,我們認(rèn)為上述行為也是不同情況下的最佳應(yīng)對(duì)措施。
緊跟技術(shù)變化的步伐
成功進(jìn)行了數(shù)十萬(wàn)次實(shí)時(shí)遷移后,我們不免會(huì)考慮:“實(shí)時(shí)遷移的開(kāi)發(fā)工作何時(shí)才能結(jié)束?” 隨著時(shí)間推移,實(shí)時(shí)遷移這項(xiàng)技術(shù)的使用范圍會(huì)越來(lái)越廣,并且會(huì)不斷完善,因此該項(xiàng)目似乎會(huì)永遠(yuǎn)持續(xù)下去。回答這個(gè)問(wèn)題的一種方法是考慮該項(xiàng)目的大部分工作什么時(shí)候會(huì)結(jié)束。答案也很簡(jiǎn)單:為了獲得可靠、可信賴的軟件,我們的工作還將持續(xù)很久。
隨著時(shí)間推移,Linode 會(huì)增加新的功能,我們也許要繼續(xù)努力保證實(shí)時(shí)遷移可以兼容這些功能。引入某些新功能時(shí),可能無(wú)需圍繞實(shí)時(shí)遷移執(zhí)行新的開(kāi)發(fā)工作,但我們可能依然需要測(cè)試該功能是否可以按照預(yù)期正常工作。對(duì)于某些功能,則可能需要在開(kāi)發(fā)的早期階段,針對(duì)實(shí)時(shí)遷移進(jìn)行必要的兼容性測(cè)試和相關(guān)工作。
和其他幾乎所有軟件類似,對(duì)于同一件事,通過(guò)不斷研究,總能發(fā)現(xiàn)更好的實(shí)現(xiàn)方法。例如,從長(zhǎng)遠(yuǎn)來(lái)看,為實(shí)時(shí)遷移功能開(kāi)發(fā)更多模塊化的集成方法,無(wú)疑可以降低維護(hù)負(fù)擔(dān)。或者我們甚至可能將實(shí)時(shí)遷移的相關(guān)功能納入到底層代碼中,從而使其成為 Linode 一項(xiàng)拆箱即用的功能。
我們的團(tuán)隊(duì)已經(jīng)考慮過(guò)所有這些選項(xiàng),并且堅(jiān)信驅(qū)動(dòng) Linode 平臺(tái)的工具是活躍的,還會(huì)繼續(xù)努力,使其不斷進(jìn)化和發(fā)展。
這篇文章的內(nèi)容感覺(jué)還行吧?有沒(méi)有想要立即在 Linode 平臺(tái)上親自嘗試一下?別忘了,現(xiàn)在注冊(cè)可以免費(fèi)獲得價(jià)值 100 美元的使用額度,快點(diǎn)自己動(dòng)手體驗(yàn)本文介紹的功能和服務(wù)吧↓↓↓
最后,歡迎廣大知友們關(guān)注 Akamai,第一時(shí)間了解 Akamai 在 Web 交付性能、安全性、邊緣計(jì)算等領(lǐng)域的最新技術(shù)成果和解決方案,以及整個(gè)行業(yè)的發(fā)展趨勢(shì)。