天天看點

Nova 的高性能虛拟機支撐

目錄

CPU 計算平台體系架構

SMP(Sysmmetric Multi-Processor System,對稱多處理器系統),顧名思義,SMP 架構由多個具有對稱關系的處理器組成。所謂對稱,即處理器之間是水準的鏡像關系,無有主從之分。SMP 架構使得一台計算機不再由單個 CPU 組成;

SMP 的結構特征就是「多處理器共享一個集中式存儲器」,每個處理器通路存儲器的時間片一緻,使工作負載能夠均勻的配置設定到所有可用處理器上,極大地提高了整個系統的資料處理能力。

Nova 的高性能虛拟機支撐

雖然系統具有多個處理器,但由于共享一個集中式存儲器,是以隻會運作一個作業系統和資料庫的副本(執行個體),能夠保持單機特性。同時也要求系統需要保證共享存儲器的資料一緻性。如果多個處理器同時請求通路這些共享資源,就會引發資源競态,需要軟硬體實作加鎖機制來解決這個問題。是以,SMP 又稱為 UMA(Uniform Memory Access,一緻性存儲器通路),所謂一緻性指的就是在任意時刻,多個處理器隻能為記憶體的每個資料儲存或共享一個唯一的數值。

很顯然,這樣的架構設計注定沒法擁有良好的處理器數量擴充性,因為共享記憶體的資源競态總是存在的,處理器使用率最好的情況隻能停留在 2 到 4 顆。

Nova 的高性能虛拟機支撐

綜合來說,SMP 架構廣泛的适用于 PC 和移動裝置領域,能顯著提升并行計算性能。但 SMP 卻不适合超大規模的伺服器端場景,例如:雲計算。

現代的計算機系統中,處理器的處理速度要遠快于主存的速度,是以限制計算機計算性能的瓶頸在存儲器帶寬上。SMP 架構因為限制了處理器通路存儲器的頻次,是以處理器可能會時刻對資料通路感到饑餓。

NUMA(Non-Uniform Memory Access,非一緻性存儲器通路)架構優化了 SMP 架構擴充性差以及存儲器帶寬窄的問題。

實際上 NUMA 和 SMP 架構是類似的,同樣隻會儲存一份作業系統和資料庫的副本,表示 NUMA 架構中的處理器依舊能夠通路到整個存儲器。兩種主要的差別在于 NUMA 架構采用了分布式存儲器,将處理器和存儲器劃分為不同的節點(NUMA Node),每個節點都包含了若幹的處理器與記憶體資源。

Nova 的高性能虛拟機支撐

NUMA 的結構特征就是「多節點」,每個節點都可以擁有多個處理器和記憶體資源,多節點的設計有效提高了存儲器的帶寬和處理器的擴充性。假設系統含有 4 個 NUMA 節點,那麼在理想情況下系統的存儲器帶寬将會是 SMP 架構的 4 倍。而且在記憶體資源充裕的情況下,再多擴充幾個節點當然也隻是水到渠成的事情。

但就如上文所提到,NUMA 節點内的處理器實際上會可以通路整體存儲器的。按照節點内外,記憶體被分為節點内部的本地記憶體以及節點外部的遠端記憶體。當處理器通路本地記憶體時,走的是内部總線,當處理器通路遠端記憶體時,走的是主機闆上的 QPI 互聯子產品。顯然,通路前者的速度要遠快于後者,NUMA(非一緻性存儲器通路)是以而得名。

Nova 的高性能虛拟機支撐

由于這個特性,基于 NUMA 架構開發的應用程式應該盡可能避免跨節點的遠端記憶體通路。因為,跨節點記憶體通路不僅僅是通信速度慢,還需要處理不同節點間記憶體、緩存的資料一緻性。可見,線程在不同的節點間切換,是需要花費大成本的。

NUMA 和 UMA(SMP) 的異同:

NUMA 與 SMP 中的處理器都可以通路整個系統的實體存儲器

NUMA 采用了分布式存儲器,提供了分離的存儲器給各個節點,避免了 SMP 中多個處理器無法同時通路單一存儲器的問題

NUMA 節點的處理器通路内部存儲器所需要的時間,比通路其他節點的遠端存儲器要快得多

NUMA 既保持了 SMP 單一作業系統副本、簡便應用程式程式設計以及易于管理的特點,又繼承了大規模并行處理 MPP 的可擴充性,是一個折中的方案

Nova 的高性能虛拟機支撐

雖然 NUMA 的多節點設計具有較好的處理器數量擴充性,最多可以支援幾百個 CPU。但因為 NUMA 沒有實作徹底的主存隔離,是以 NUMA 依舊沒有實作處理器數量的無限擴充,這是為了追求更高的并發性能所作出的妥協(一個節點也未必就能完全滿足多線程并發,還是會存在多節點間線程切換的問題)。

NUMA 結構的基本概念:

Node:包含有若幹個實體 CPU 的組.

Socket:表示一顆實體 CPU 的封裝(實體 CPU 插槽),簡稱插槽。為了避免将邏輯處理器和實體處理器混淆,Intel 将實體處理器稱為插槽。

Core:實體 CPU 封裝内的實體 Core。

Thread:使用超線程技術虛拟出來的邏輯 Core(一般的,實體 Core 和邏輯 Core 的比例是 1:2),需要 CPU 支援。為了便于區分,邏輯 Core 一般被寫作 Processor。在具有 Intel 超線程技術的處理器上,每個核心可以具有兩個邏輯處理器,這兩個邏輯處理器共享大多數核心資源(如記憶體緩存和功能單元)。此類邏輯處理器通常稱為 Thread。

NOTE:一個 NUMA Node 包含若幹個 Socket(Socket 是一顆實體 CPU 的封裝),一個 Socket 包含有若幹個 Core(實體/虛拟)。

Nova 的高性能虛拟機支撐

上圖的 NUMA Topology 表示:

兩個 Node

一個 Node 具有一個 Socket,即一個 pCPU

一個 pCPU 具有 6 個 Core

一個 Core 具有 2 個 Processor

是以總共的邏輯 CPUs Processor = 2*1*6*2 = 24

MPP(Massive Parallel Processing,大規模并行處理)架構,既然 NUMA 擴充性的限制是沒有完全實作資源的獨立性,那麼 MPP 的解決思路就是為處理器提供徹底的獨立資源。MPP 擁有多個獨立的 SMP 單元,每個 SMP 單元獨占并隻會通路自己本地的記憶體、I/O 等資源,SMP 單元間通過節點網際網路絡進行連接配接(Data Redistribution,資料重配置設定),是一個完全無共享(Share Nothing)的 CPU 計算平台結構。

Nova 的高性能虛拟機支撐

MPP 結構的特征就是「多 SMP 單元組成,單元之間完全無共享」。除此之外,MPP 結構還具有以下特征:

每個 SMP 單元内都可以包含一個作業系統副本,是以每個 SMP 單元都可以運作自己的作業系統

MPP 需要一種複雜的機制來排程和平衡各個節點的負載和并行處理過程,目前一些基于 MPP 技術的伺服器往往通過系統級軟體(e.g. 資料庫)來屏蔽這種複雜性

MPP 架構的局部區域記憶體的訪存延遲低于遠地記憶體訪存延遲,是以 Linux 會自定采用局部節點配置設定政策,當一個任務請求配置設定記憶體時,首先在處理器自身節點内尋找空閑頁,如果沒有則到相鄰的節點尋找空閑頁,如果還沒有再到遠地節點中尋找空閑頁,在作業系統層面就實作了訪存性能優化

因為完全的資源隔離特性,是以 MPP 的擴充性是最好的,理論上其擴充無限制,目前的技術可實作 512 個節點互聯,數千個 CPU 。

Nova 的高性能虛拟機

在 Icehouse 版本之前,Nova 定義的 libvirt.xml,不會考慮 Host NUMA 的情況。導緻 Libvirt 在預設情況下,有可能發生跨 NUMA node 擷取 CPU/Memory 資源的情況,導緻 Guest 性能下降。Openstack 在 Juno 版本中新增 NUMA 特性,使用者可以通過将 Guest 的 vCPU/Memory 綁定到 Host NUMA Node上,以此來提升 Guest 的性能。

Nova 的高性能虛拟機支撐

PS:Guest 是 ComputeNode 上的一個 Linux 程序,vCPU 是 Guest 程序内的一個特殊的線程,被 Host OS 排程。

基礎概念:

vCPU:虛拟 CPU,配置設定給虛拟機的邏輯 CPU。根據虛拟機拓撲的不同,一個虛拟機 CPU 可以是一個 CPU 封裝元件(socket)、一個 CPU 核(core)、或者一個 CPU 線程(thread)。

pCPU:實體 CPU, 虛拟機主機所展示的邏輯 CPU,根據主機拓撲的不同,一個實體可以是一個 CPU 封裝元件(socket)、一個 CPU 核(core)、或者一個 CPU 線程(thread)。

NUMA:非一緻記憶體通路架構,記憶體通路時間取決于記憶體頁面和處理器核心之間的位置。

Node:一個包含 CPU 或者記憶體(或二者兼具)的 NUMA 系統單元

Cell:Node 的通名詞,供 Libvirt API 使用

Socket:包含在 NUMA 系統單元内的單個獨立 CPU 封裝元件

Core:一個 CPU 封裝元件中的一個處理單元

Thread:超線程,一個 CPU 核中的一個超流水線

KSM:Linux 核心記憶體共享技術(Kernel Shared Memory)

THP:透明巨型頁,為程序提前配置設定巨型頁的一種 Linux 技術

pCPU:實體 CPU ,主機插槽上的 CPU,可以通過 /proc/cpuinfo 中的不同的 physical id 個數來統計 pCPU 的個數。 physical id 對應 socket_id

Socket:表示一顆實體 CPU 的封裝,對應主機闆上的一個 CPU 插槽

pCPU Cores:一塊實體 CPU 上所具有的晶片組(CPU 寄存器+中斷邏輯 etc.)數量,一個晶片組就是一個 CPU 的 Core,現在我們普遍認為一個實體 CPU 具有多個 Cores。

Hyper-Threading:超線程,可以将一個實體 CPU 的 Core,虛拟成若幹個(通常為 2 個)僞 Core,達到一個實體 Core 可以處理多個線程的效果。

Logical Processor,簡稱 Processor:邏輯 CPU,可以通過 /proc/cpuingo 中的 processor 字段來統計 Processor 的個數,也可以使用下述公式計算:

邏輯 CPU 數量 = 實體 CPU 數量 x 實體 CPU Cores(一個實體 CPU 具有若幹個 Core)[x 2(如果開啟了超線程,這個值通常為 2)]

e.g.

酷睿 i5 760:原生四核心四線程處理器,沒有采用超線程技術。一個實體 CPU,具有 4 個 Core,沒有超線程,是以邏輯 CPU Processor = 1*4

NOTE:一般來說,實體 CPU 個數 × 每顆核數就應該等于邏輯 CPU 的個數,如果不相等的話,則表示伺服器的 CPU 支援超線程技術

NOTE:同一個 Socket 中,具有相同 Core ID 的 Processor 是同一個實體 CPU Core 的超線程

NOTE:具有相同 Physical ID 的 Processor 是同一個實體 CPU 封裝的 Thread(僞 Core)或 Core

作業系統供應商許可規則,可能會嚴格限制作業系統所支援的 CPU 封裝元件(sockets) 的數目。此時,為虛拟機配置設定的虛拟 CPU,應該偏向處理單元(core),而不是封裝單元(socket)。

作業系統許可的影響,意味着使用者在上傳鏡像到 glance 時,需要指明一個運作鏡像的最佳的 CPU 拓撲,包含處理單元(core)與封裝元件(socket)的配置設定。雲平台管理者也可以修改程式的預設值,以避免使用者超出常見的許可限制。也就是說,對于一個 4 虛拟 CPU 核的虛拟機,如果使用預設值限制最大的封裝元件(socket)數目為 2,則可以設定其處理單元為 2(在 Socket 數量沒有超出限制的前提下,虛拟機也能達到具有 4 Core 的效果),此時 windows 鏡像也能夠正常處理。

NOTE:OpenStack 管理者應該遵從作業系統許可需求,限制虛拟機使用的拓撲(例如:​<code>​max_sockets==2​</code>​)。設定預設的拓撲參數,以保證虛拟機作業系統鏡像能夠滿足正常作業系統許可,而不必每一個使用者都去設定鏡像屬性。

各種 CPU 拓撲的性能并不一緻。例如,兩個主機線程運作在同一個處理單元(core)上時,其性能就會低于運作在不同的處理單元(core)上。而當一個處理單元(core)有多個超線程(thread)時,作業系統排程器将決定線程的具體運作位置。超線程性能的影響,意味着除非指定将虛拟機超線程與主機的超線程一一綁定,否則無法為虛拟機指定超線程。如果不綁定虛拟機 CPU(vCPU) 與實體 CPU(pCPU) 的關系,則虛拟機應當始終不使用超線程(threads==1),而隻是用 CPU 封裝元件(sockets)與 CPU 處理單元(core),而沒有必要向使用者暴露超線程的配置能力。如果使用者的虛拟機對負載比較敏感,那麼使用者最多會希望他們的鏡像不運作在兄弟超線程(同一個處理單元上的超線程)上。

NOTE:如果不綁定 vCPU 和 pCPU,那麼虛拟機不應該使用超線程(vCPU 會在不同 Core 的 thread 上浮動),而是虛拟機應該使用 Socket/Core。如果使用者對虛拟機的性能要求比較高,那麼不應該讓虛拟機的 vCPU 運作在 Thread 上,而應該将 vCPU 運作在 Socket/Core 上。是以應該将 siblings Thread 過濾掉。

從 Intel 和 VMware 對外宣稱的資料看,開啟超線程後,實體核總計算能力是否提升以及提升的幅度和業務模型相關,平均提升在 20%-30% 左右。超線程對實體核執行資源的争搶,業務的執行時延會相應增加。當超線程互相競争時,超線程的計算能力相比不開超線程時的實體核會下降30%左右。是以,超線程應該關閉還是開啟,主要還是取決于應用模型:

對于時延敏感性任務,比如使用者需要及時等待任務運作結果的,在節點負載過高,引發超線程競争時,任務的執行時長會顯著增加,影響使用者體驗。

對于背景計算型任務,比如超算中心上運作的背景計算型任務(一般要運作數小時或數天),建議開啟超線程提高整個節點的吞吐量。

現在虛拟化主機都支援 NUMA 拓撲,會将記憶體與實體 CPU 分布在 2 個或者更多的 NUMA 節點上。

主要驅動 NUMA 應用的因素是高存儲帶寬,有效的緩存效率以及靈活 PCIe I/O 裝置的布局。也就是說,每一個 NUMA 單元内部都由自己專有的記憶體總線,用于通路專用記憶體,而所有 NUMA 單元使用共享總線通路遠端的記憶體。假如有一個具有 4 個 NUMA 單元的系統,每一個單元内部有 1GB/s 的存儲帶寬,同時共享總線也具有 1GB/s 的帶寬。如果所有的處理器總是使用 NUMA 單元内部記憶體,那麼系統就擁有了 4GB/s 的存儲帶寬潛力。如果所有處理器都是用遠端存儲,那麼系統就隻有了 1GB/s 的存儲帶寬潛力。使用共享的總線可能觸發 NUMA 單元之間的緩存異常同步,對于記憶體密集型工作負載的性能會産生顯著影響。當 I/O 性能至關重要時,加上共享總線上的無效 Cache 資源浪費,連接配接到遠端 PCIe 總線上的裝置(也就是說連接配接不同NUMA單元)作業性能将會急劇下降。

是以,虛拟機在 NUMA 單元上的錯誤布局,或者不正确的 PCI 裝置配置設定選擇,将會導虛拟化主機資源的嚴重浪費。這點影響将會抹掉任何記憶體與 CPU 決策所帶來的好處,包括 guest CPU topology,vCPU 與 pCPU 綁定,以及使用大頁記憶體。是以标準的政策将是一個虛拟機完全局限在單個 NUMA 節點。

NOTE:NUMA topology 具有高存儲帶寬,高緩存效率,高擴充性以及 PCIe I/O 裝置布局靈活性好的優點。

NOTE:跨 NUMA node 具有 node 間緩存異常同步,總線延時高,存儲帶寬低,浪費緩存資源等導緻性能急劇下降的缺點,尤其在記憶體密集型工作負載場景中。

NOTE:标準的 NUMA topology 政策是将一個虛拟機完全局限在單個 NUMA 節點中。

如果虛拟機的虛拟 CPU 或者記憶體配置設定大過了 NUMA 節點,或者 NUMA 節點可用的 PCIe 裝置不足時,必須針對虛拟機做出合适的政策,或者禁止建立過大 NUMA 節點的虛拟機,或者允許虛拟機跨越多 NUMA 運作。在虛拟機遷移時,可以更改這些政策,也就是說,在對主機進行維護而疏散主機時,會選擇接受臨時降低性能而選擇次優的 NUMA 布局。布局的問題還要考慮到虛拟機的具體使用場景,例如,NFV 的部署就要求嚴格的 NUMA 布局。

如果一個虛拟機具有多個 guest NUMA 節點,為了作業系統能夠最大化利用其配置設定到的資源,主機的 NUMA 拓撲必須暴露給虛拟機。虛拟機的 guest NUMA單元應該與虛拟化主機的 host NUMA單元進行映射。這樣可以映射大塊的虛拟機記憶體到虛拟化主機記憶體節點,設定虛拟 CPU 與實體 CPU 的映射。

也就是說,如果虛拟機有 4 個虛拟 CPU 需要跨越兩個虛拟化主機 NUMA 單元,虛拟 CPU 0/1 綁定到第一個主機 NUMA 節點,而虛拟 CPU 2/3 将會綁定到第二個主機 NUMA 節點上,但是并不強制綁定每一個 vCPU 與 host NUMA 單元内特定 pCPU 的關系,這将由作業系統排程器指定。此時,如果虛拟主機具有超線程特性,則暴露超線程特性給虛拟機,同時在 NUMA 單元内綁定 vCPU 與 pCPU 的關系。

NOTE:如果 guest 的 vCPU/RAM 配置設定大于單個 host NUAM node,那麼應該劃分為多個 guest NUMA topology,并分别映射到不同的 host NUMA node 上。

NOTE:如果 host 開啟了超線程,那麼應該在單個 host NUMA node 上進行 vCPU 和 pCPU 的綁定,否則 vCPU 會被配置設定給 siblings thread,性能不如實體 Core 好。

絕大多數現代 CPU 支援多種記憶體頁尺寸,從 4KB 到 2M/4M,最大可以達到 1GB;所有處理器都預設使用最小的 4KB 頁。如果大量的記憶體可以使用大頁進行配置設定,将會明顯減少 CPU 頁表項,是以會增加頁表緩存的命中率,降低記憶體通路延遲。

如果作業系統使用預設的小頁記憶體,随着運作時間,系統會出現越來越多的碎片,以至于很難申請到大頁的記憶體。在大頁記憶體大小越大時,該問題越嚴重。是以,如果有使用大頁記憶體的需求,最好的辦法是在系統啟動時就預留好記憶體空間。

目前的 Linux 核心不允許針對特定的 NUMA 節點進行這樣的設定,不過,在不久的将來這個限制将被取消。更進一步的限制是,由于 MMIO 空洞的存在,記憶體開始的 1GB 不能使用 1GB 的大頁。Linux 核心已經支援透明巨型頁(THP,transparent huge pages)特性。該特性會嘗試為應用程式預配置設定大頁記憶體。依賴該特性的一個問題是,虛拟機的擁有者,并不能保證給虛拟機使用的是大頁記憶體還是小頁記憶體。

記憶體塊是直接指定給特定的 NUMA 節點的,這就意味着大頁記憶體也是直接存在于 NUMA 節點上的。是以在 NUMA 節點上配置設定虛拟機時,計算服務需要考慮在 NUMA 節點或者主機上可能會用到的大頁記憶體(NUMA node 或 host 存在哪一些大頁記憶體類型和數量狀況)。為虛拟機記憶體啟用大頁記憶體時,可以不用考慮虛拟機作業系統是否會使用。

NOTE:有使用大頁記憶體的需求,需要在系統啟動時就預留好記憶體空間,Linux 核心使用 THP 來實作,但也存在着問題。

NOTE:如果希望讓虛拟機使用大頁記憶體,那麼應該收集 NUMA 節點所擁有的記憶體頁類型和數量資訊。

計算節點可以配置 CPU 與記憶體的超配比例,例如,16 個實體 CPU 可以執行 256 個虛拟 CPU,16GB 記憶體可以允許使用 24GB 虛拟機記憶體。

超配的概念可以擴充到基本的 NUMA 布局,但是一旦提到大頁記憶體,記憶體便不能再進行超配。當使用大頁記憶體時,虛拟機記憶體頁必須與主機記憶體頁一一映射,并且主機作業系統能通過交換分區配置設定大頁記憶體,這也排除了記憶體超配的可能。但是大頁記憶體的使用,意味着需要支援記憶體作為專用資源的虛拟機類型。盡管設定專用資源時,不會超配記憶體與 CPU,但是 CPU 與記憶體的資源仍然需要主機作業系統提前預留。如果使用大頁記憶體。必須在主機作業系統中明确預留。

對于 CPU 則有一些靈活性。因為盡管使用專用資源綁定 CPU,主機作業系統依然會使用這些 CPU 的一些時間。不管怎麼樣,需要預留一定的實體 CPU 專門為主機作業系統服務,以避免作業系統過多占用虛拟機 CPU,而造成對虛拟機性能的影響。Nova 可以保留一部分 CPU 專門為作業系統服務,這部分功能将會在後續的設計中加強。

允許記憶體超配時,超出主機記憶體的部分将會使用到 Swap。Swap 将會影響主機整體 I/O 性能,是以盡量不要把需要專用記憶體的虛拟機與允許記憶體超配的虛拟機放在同一台實體主機上。

如果專用 CPU 的虛拟機與允許超配的虛拟機競争 CPU,由于 Cache 的影響,将會嚴重影響專用 CPU 的虛拟機的性能,特别在同一個 NUMA 單元上時。是以,最好将使用專用 CPU 的虛拟機與允許超配的虛拟機放在不同的主機上,其次是不同的 NUMA 單元上。

NOTE:确定 VMware 虛拟機支不支援使用大頁記憶體

NOTE:大頁記憶體需要明确的在實體主機中預留

NOTE:為了虛拟機能夠更加好的“獨占”實體 CPU,一般的,也會預留一些實體 CPU 資源給實體主機使用

NOTE:盡量不要将占用專用記憶體的虛拟機與使用記憶體超配的虛拟機放到同一個實體主機中運作

NOTE:盡量不要将占用專用 CPU 的虛拟機與使用 CPU 超配的虛拟機放到同一個實體主機中運作,其次是不要放到同一個 NUMA node 中運作

Linux 核心有一項特性,叫做核心共享存儲(KSM),該特性可以使得不同的處理器共享相同内容的記憶體頁。核心會主動掃描記憶體,合并内容相同的記憶體頁。如果有處理器改變這個共享的記憶體頁時,會采用 CoW 的方式寫入新的記憶體頁。

當一台主機上的多台虛拟機使用相同作業系統或者虛拟機使用很多相同内容記憶體頁時,KSM 可以顯著提高記憶體的使用率。因為記憶體掃描的消耗,使用 KSM 的代價是增加了 CPU 的負載,并且如果虛拟機突然做寫操作時,會引發大量共享的頁面,此時會存在潛在的記憶體壓力峰值。虛拟化管理層必須是以積極地監控記憶體壓力情況并做好現有虛拟機遷移到其他主機的準備,如果記憶體壓力超過一定的水準限制,将會引發大量不可預知的 Swap 操作,甚至引發 OOM。ZSwap 特性允許壓縮記憶體頁被寫入 Swap 裝置,這樣可以大量減少 Swap 裝置的 I/O 執行,減少了交換主機記憶體頁面中固有的性能下降。

NOTE:虛拟化管理層應該積極的監控記憶體壓力,适時的将虛拟機遷移到其他實體主機。

PCI 裝置與 NUMA 單元關系密切,PCI 裝置的 DMA 操作使用的記憶體最好在本地 NUMA 節點上。是以,在哪個 NUMA 單元上配置設定虛拟機,将會影響到 PCI 裝置的配置設定。

NOTE:将 PCI 裝置和虛拟機配置設定到同一個 NUMA node 上。

從上述背景知識我們能夠清晰的認識到,為了最大化利用主機資源,好好利用 NUMA 與大頁記憶體等工具顯得尤為重要。即使使用預設配置,Nova 也能夠做到 NUMA 布局的優化以及考慮到大頁記憶體的使用。顯式的配置(通過配置虛拟機套餐類型 Flavor)隻是為了滿足性能優化或者虛拟機個性化需求,亦或者雲平台提供商希望為不同的價格方案設定認為的設定。顯示配置還能夠限制使用者可使用的拓撲,以防止使用者使用非最優 NUMA 拓撲方案。

NOTE:隻有當虛拟機的虛拟 CPU 與主機的實體 CPU 一一綁定時,配置超線程參數(threads != 1)才有意義。這不是一個最終使用者需要考慮的東西,但是雲平台管理者希望能夠通過設定虛拟機類型明确避免使用主機超線程(如果 vCPU 和 pCPU 沒有綁定,那麼應該過濾實體主機的超線程 ID)。這可以通過使用主機聚合排程的方式實作。

超線程技術僅僅是在一個實體核心上使用了兩個實體任務描述符,實體計算能力并沒有增加。現在很多程式如 WEB Application,都采用多 Worker 設計,在超線程的幫助下,兩個被排程到同一核心不同超線程的 Worker,通過共享 Cache,TLB,大幅降低了任務切換的開銷。另外,在某個 Worker 不忙的時候,超線程允許其它的 Worker 也能使用實體計算資源,有助于提升實體核整體的吞吐量。但由于超線程對實體核執行資源的争搶,業務的執行時延也會相應增加。

Nova 的高性能虛拟機支撐

對于 CPU 密集型任務的測試:僅運作一個負載和同時在一個核的兩個超線程上運作負載的時間對比,可以看出在存在超線程競争時,超線程計算能力大概是實體核的 60% 左右。

Nova 的高性能虛拟機支撐

不同數量負載同時運作時的平均編譯時間,此時沒有兩個負載運作在同一個核的兩個超線程上。可以看出,不存在超線程競争時,負載平均運作時間基本不變。

Nova 的高性能虛拟機支撐

在同一個核兩個超線程上的負載,其運作時間大幅增加。

Nova 的高性能虛拟機支撐

在 vSphere 的 ESXi 主機上運作兩個 1CPU 的虛拟機,分别綁定到一個核的兩個超線程上,在虛拟機内部運作計算任務,確定虛拟機内部 CPU 占用率在 50% 左右,可以看到,ESXi 主機上兩個超線程使用率在 45% 左右,實體核負載已經達到 80%。

Nova 的高性能虛拟機支撐

NOTE:将對于計算型虛拟機的 vCPU 綁定到主機的一個 thread 上,虛拟機的性能是不好的。對于時延敏感性任務,比如使用者需要及時等待任務運作結果的,在節點負載過高(NFV),引發超線程競争時,任務的執行時長會顯著增加,影響使用者體驗;對于背景計算型任務,比如超算中心上運作的背景計算型任務(一般要運作數小時或數天),建議開啟超線程提高整個節點的吞吐量。

CPU 綁定:将虛拟機的 vCPUs 綁定到 pCPUs,vCPU 隻會在指定的 pCPU 上運作,避免 pCPU 間線程切換(上下文切換,記憶體資料轉移)帶來的性能開銷。

使用此屬性參數,将虛拟機的 vCPUs 連接配接到實體主機的 pCPUs 上。該配置能夠提高虛拟機的性能。

CPU-POLICY 具有下列兩種參數類型

shared:(預設的)允許 vCPUs 跨 pCPUs 浮動,盡管 vCPUs 收到了 NUMA node 的限制也是如此。

dedicated:guest 的 vCPUs 将會嚴格的 pinned 到 pCPUs 的集合中。在沒有明确 vCPU 拓撲的情況下,Drivers 會将所有 vCPU 作為 sockets 的一個 core 或一個 thread(如果啟動超線程)。如果已經明确的将 vCPUs Topology Pinned 到 CPUs Topology 中時,會嚴格執行 CPU pinning,将 guest CPU 的拓撲比對到已經 pinned 的 CPUs 的拓撲中。此時的 overcommit ratio 為 1.0。例如:虛拟機的兩個 vCPU 被 pinned 到了一個實體主機的 core 的兩個 thread 上,那麼虛拟機将會獲得一個 core(對應的兩個 thread)的拓撲。

NOTE:這裡常結合 NUMA topology 來一起使用。如果設定為 shared,那麼即便為虛拟機配置設定了一個 NUMA node,但 vCPUs 仍會在 NUMA node 所擁有的 pCPUs 間浮動;如果設定為 dedicated,那麼虛拟機就會嚴格按照 guest NUMA topology 和 host NUMA topology 的映射關系将 vCPUs pinned to pCPUs,實作 CPU 的綁定。而且這種映射,往往是一個 vCPU 被綁定到一個 pCPU 的 Core 或 Thread 上(如果開啟超線程)。

CPU-THREAD-POLICY

prefer:(預設的)主機也許是 SMT 架構,如果是 SMT 架構,那麼将會優先将一個 vCPU 綁定到一個實體主機的 thread siblings 上,否則按照一般的方式将 vCPU 綁定到 core 上。

isolate:主機不應該是 SMT 架構,或者能夠識别 thread siblings 并從邏輯上屏蔽它。每一個 vCPU 都将會被 pinned 到一個實體 CPU 的 Core 上(如果是多核 CPU)。如果實體機是 SMT 架構支援超線程,那麼實體 Cores 就具有 Thread siblings,這樣的話,如果一個 guest 不同的 vCPU 被 pinned 到不同的實體 Core 上,那麼這個實體 Core 将不會再繼續接受其他 guest 的 vCPU。是以,需要保證實體 Core 上沒有 Thread siblings。

Nova 的高性能虛拟機支撐

NOTE:<code>unpin_cpus_with_siblings</code>、<code>pin_cpus_with_siblings</code> 将屬于同一個 thread siblings 的 CPUs 一次性 Pinned 掉,等同于消耗掉了一顆實體 Core。這兩個方法是為了在超線程場景中,能夠消除超線程帶入的重疊 Thread,保持了實體 Core 的唯一性。

require:實體主機必須是 SMT 架構,每一個 vCPU 都配置設定給 thread siblings。但如果沒有足夠的 thread siblings,則會排程失敗。如果主機不是 SMT 架構,則配置無效。

NOTE:隻有設定 ​<code>​hw:cpu_policy=dedicated​</code>​ 時,​<code>​hw:cpu_thread_policy​</code>​ 才會生效。可見,後者設定的是 vCPU pinning to pCPU 的政策。

NOTE:在啟動了超線程的 SMT-Base(simultaneous multithreading-based,基于同步多線程) 架構中,Core 通常被成為 hardware thread,而使用超線程技術虛拟出來的 Cores 被稱為 thread siblings。

NOTE:SMT 架構,也就是以前的 Hyper-Threading 超線程技術,支援将一個實體 Core 虛拟為多個 Thread(僞核)。

NOTE:應該使用 HostAggregate 來區分開 pinned 和 unpinned 的虛拟機,因為 unpinned 的虛拟機不會考慮到 pinned 的虛拟機的資源需求,避免發生資源占用。

NOTE:一個虛拟機在實體主機上就是一個程序,一個 vCPU 在實體主機上就是一個特殊的線程。

NOTE:專有 CPU 限制,如果為虛拟機設定實體 CPU 綁定,那麼其他虛拟機要避免使用該虛拟機的專有實體 CPU。

在主機配置時,為所有虛拟機建立兩個資源組,為兩個組配置設定不同的實體。CPU。使用專有資源的虛拟機與共享資源的虛拟機分别使用兩個不同的資源組。

準備一些不超配的主機隻用于專用資源。

當出現一個需要專有資源的虛拟機時,動态更新所有現有虛拟機的實體 CPU 綁定。

為所有的虛拟機預先設定實體 CPU 親和性,以預留一部分實體 CPU 為後面的專有資源虛拟機使用。

為虛拟機設定固定的排程時間片,允許他們在實體 CPU 之間自由排程。

​<code>​_get_host_numa_topology​</code>​:

cells:對應 NUMA nodes

online_cpus:表示所有的 Logical Processors 邏輯核,對應 CPU ID,例如:set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23])

cpuset:表示同一個 Socket 中的 Logical Processors 邏輯核,例如:Socket 0 的 cpuset=set([0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16, 17])

siblings:同一個實體 CPU Core 虛拟出來的 Logical Processors 的集合(通常為 2 個)。cpuset 中的 CPU 所擁有的 Logical Processors 的集合。例如 cpu 0 和 cpu 12 所擁有的 siblings 都是 set([0, 12]) 表示 0 和 12 是「超線程虛拟出來的兄妹 CPU」,兩者均在同樣的 Socket 和同樣的 Core 中。

基本上 siblings[X] &amp; cpuset == siblings[X],因為 siblings[X] 集合的元素就是 cpuset 中的 cpu id 的組合。

NUMA 親和:将虛拟機綁定 NUMA Node,guest vCPUs/RAM 都配置設定在同一個 NUMA node 上,充分使用 NUMA node local memory,避免通路 remote memory 的性能開銷。

使用此屬性參數,将虛拟機的 vCPUs 線程限制到指定的 NUMA node 中,保證每一個 vCPU 都使用同一個 NUMA node 的 pCPU/RAM。若虛拟機所需要的 pCPU/RAM 資源需求大于一個 host NUAM node 資源時,可以通過下列屬性參數定義劃分為若幹個在 host NUMA node 資源範圍内的 guest NUMA topologys,再将 guest NUMA topologys 分别映射到不同的 host NUMA node 上。

FLAVOR-NODES:整數,設定 Guest NUMA nodes 的個數。如果不指定,則 Guest vCPUs 可以運作在任意可用的 Host NUMA nodes 上。

N:整數,Guest NUMA nodes ID,取值範圍在 [0, FLAVOR-NODES-1]。

FLAVOR-CORES:逗号分隔的整數,設定配置設定到 Guest NUMA node N 上運作的 vCPUs 清單。如果不指定,vCPUs 在 Guest NUMA nodes 之間平均配置設定。

FLAVOR-MEMORY:整數,機關 MB,設定配置設定到 Guest NUMA node N 上 Memory Size。如果不指定,Memory 在 Guest NUMA nodes 之間平均配置設定。

NOTE:隻有在設定了 hw:numa_nodes 後 hw:numa_cpus.N 和 hw:numa_mem.N 才會生效。另外,隻有當 Guest NUMA node 存在非對稱通路 CPUs/RAM 時(一個 Host NUMA node 無法滿足虛拟機的 vCPUs/RAM 資源需求時),才需要去設定這些參數。

NOTE:N 僅僅是 Guest NUMA node 的索引,并非實際上的 Host NUMA node 的 ID。例如,Guest NUMA node 0,可能會被映射到 Host NUMA node 1。類似的,FLAVOR-CORES 的值也僅僅是 vCPU 的索引。是以,Nova 的 NUMA 特性并不能用來限制 Guest vCPUs/RAM 綁定到某一個 Host NUMA node 上。要完成 vCPU 綁定到指定的 pCPU,需要借助 CPU Pinning policy 和 Nova 底層隐式實作的 CPU binding(映射)機制。

WARNING:如果 ​<code>​hw:numa_cpus.N​</code>​ 和 ​<code>​hw:numa_mem.N​</code>​ 設定的值大于虛拟機本身可用的 CPUs/Memory 的話,則觸發異常。

EXAMPLE:Flavor 定義 Guest 有 4 個 vCPU,4096MB 記憶體,設定 Guest 的 NUMA topology 為 2 個 NUMA node,vCPU 0、1 運作在 NUMA node 0 上,vCPU 2、3 運作在 NUMA node 1上。并且占用 NUMA node 0 的 Memory 2048MB,占用 NUMA node1 的 Memory 2048MB。

使用該 flavor 建立的虛拟機,将會具有上述 Guest NUMA topology,并由 Libvirt Driver 隐射到 Host NUMA node 上。

Nova 配置設定 NUMA 的兩種方式:

自動配置設定 NUMA 的限制和限制:僅指定 Guest NUMA nodes 的個數,然後由 Nova 根據 Flavor 的規格平均将 vCPU/Memory 分布到不同的 Host NUMA nodes 上(預設從 Host NUMA node 0 開始配置設定,依次遞增)。這将最大程度的降低配置參數的複雜性。如果沒有 NUMA 節點的定義,管理程式可以在虛拟機上自由使用 NUMA 拓撲。

不能設定 ​<code>​numa_cpus​</code>​ 和 ​<code>​numa_mem​</code>​

自動從 0 節點開始平均配置設定

手動指定 NUMA 的限制和限制:不僅指定 Guest NUMA nodes 的個數,還指定了每個 Guest NUMA nodes 上配置設定的 vCPU ID 和 Memory Size,設定了 Guest NUMA topology。由 Nova 來完成 Guest NUMA nodes 和 Host NUMA nodes 的映射關系。

設定的 vCPU 總數需要和虛拟機 flavor 中的 CPU 總數一緻

設定的 Memory 大小需要和虛拟機 flavor 中的 memory 大小一緻

必須設定 ​<code>​numa_cpus​</code>​ 和 ​<code>​numa_mem​</code>​

需要從 Guest NUMA node 0 開始指定各個 numa 節點的資源占用參數

NOTE 1:nova-compute 的 ResourceTracker 會定時上報 Host NUMA 的資源資訊。

NOTE 2:Setup Flavor extra-specs 實際上是設定 Guest NUMA Topology。

NOTE 3:Guest vCPU/Memory 不能大于虛拟機自身 flavor 所擁有的 CPU/Memory 規格。

NOTE 4:如果 Guest NUMA node 的 vCPU/Memory 規格大于 Host NUMA node 的 CPU/Memory 規格,則應該講 Guest NUMA node 劃分為多個 nodes。

NOTE 5:如果 ​<code>​hw:numa_cpus.N​</code>​ 或 ​<code>​hw:numa_mem.N​</code>​ 設定的值比 Host 可用 CPU/Memory 大,則會引發錯誤。

NOTE 6:​<code>​hw:numa_cpus.N​</code>​ 與 ​<code>​hw:numa_mem.N​</code>​ 隻在設定了 hw:numa_nodes 後有效。

NOTE 7:N 是 Guest NUMA node 的索引 ID,并非實際上的 Host NUMA node ID。例如,Guest NUMA node(​<code>​hw:numa_mem.0​</code>​),可能會被映射到 Host NUMA node 1。類似的,FLAVOR-CORES 也值是 vCPU 的編号,并不對應 pCPU。是以,Nova 的 NUMA 特性并不能用來限制 Guest vCPU/Memory 所處于的 Host NUMA node。要完成 vCPU 綁定到指定的 pCPU,還需要應用 Nova 的 CPU binding 機制。

NOTE 8:在最終的 XML 檔案裡面可能并沒有 numatune 資訊,是以從 XML 無法看出 Guest NUMA node 的 Memory 是從哪個 Host NUMA node 上配置設定的,在 RHEL 中,預設的 Memory 配置設定方式與 CPU 配置設定方式是一緻的,但是在 SUSE OS 上,就需要指定 numatune 資訊才能生效。

除了通過 Flavor extra-specs 來設定 Guest NUMA topology 之外,還可以通過 Image Metadata 來設定。e.g.

NOTE:當使用者鏡像的 NUMA 限制與虛拟機類型的 NUMA 限制沖突時,以虛拟機類型限制為準。

排程器使用虛拟機類型的參數 ​<code>​numa_nodes​</code>​ 決定如何布置虛拟機。如果沒有設定 ​<code>​numa_nodes​</code>​ 參數, 排程器将自由決定在哪裡運作虛拟機,而不關心單個 NUMA 節點是否能夠滿足虛拟機類型中的記憶體設定,盡管仍然會優先考慮一個 NUMA 節點可以滿足情況的主機。

如果參數 ​<code>​numa_nodes​</code>​ 設定為 1,排程器 将會選擇單個 NUMA 節點能夠滿足虛拟機類型中記憶體設定的主機。

如果參數 ​<code>​numa_nodes​</code>​ 設定大于 1,排程器将會選擇 NUMA 節點數量與 NUMA 節點中記憶體能夠滿足虛拟機類型中 numa_nodes 參數與記憶體設定的主機。

ComputeNode 将會暴露他們的 NUMA 拓撲資訊(例如:每個 NUMA 節點上有多少 CPU 和記憶體),以及目前的資源使用率。這些資料會被加入到計算節點的資料模型(compute_nodes)中。

應用場景:

- ​<code>​hw:huma_nodes=1​</code>​,應該讓 Guest 的 vCPU/Memory 從一個固定的 Host NUMA node 中擷取,避免跨 NUMA node 的 Memory 通路,減少不可預知的通信延時,提高 Guest 性能。

<code>hw:huma_nodes=N</code>,當 Guest 的 vCPU/Memory 超過了單個 Host NUMA node 占有的資源時,手動将 Guest 劃分為多個 Guest NUMA node,然後再與 Host NUMA node 對應起來。這樣做有助于 Guest OS 感覺到 Guest NUMA 并優化應用資源排程。(e.g. 資料庫應用)

<code>hw:huma_nodes=N</code>,對于 Memory 通路延時有高要求的 Guest,即可以将 vCPU/Memory 完全放置到一個 Host NUMA node 中,也可以主動将 Guest 劃分為多個 Guest NUMA node,再配置設定到 Host NUMA node。以此來提高總的訪存帶寬。(e.g. NFV/搜尋引擎)

如果 N == 1,表示 Guest 的 vCPU/Memory 固定從一個 Host NUMA node 擷取

如果 N != 1,表示為 Guest 劃分 N 和 Guest NUMA node,并對應到 N 個 Host NUMA node 上

大頁記憶體:使用大頁來進行記憶體配置設定,那麼将會明顯減少 CPU 頁表項,是以會增加頁表緩存的命中率,降低記憶體通路延遲。

與 NUMA 不同,如果虛拟機類型中聲明了大頁記憶體,則需要主機能夠進行預留該記憶體塊。因為這些記憶體同時也作為該主機上的 NUMA 節點專用記憶體,是以必須提前顯式聲明。例如,如果主機配置了大頁記憶體,也應該從 NUMA 節點中配置設定。

透明巨型頁技術允許主機出現記憶體超配,并且排程程式可以使用該特性。如果主機支援記憶體預配置設定,主機将會上報是否支援保留記憶體或者 THP,甚至在嚴格條件下,可以上報剩餘可用記憶體頁數。如果虛拟機使用的主機類型中将 huge_pages 參數設定為 strict 時,并且沒有主機在單 NUMA 節點中擁有足夠的大頁記憶體可用,排程器将會傳回失敗。

PAGE_SIZE

small:(預設)使用最小的 page size,例如:4KB on x86 架構

large:隻為 Guest 使用的 larger page size,例如:2MB 或 1GB on x86 架構

any:有 Nova virt drivers 決定,不同的 driver 具有不同的實作。

​<code>​&lt;pagesize&gt;​</code>​:字元串,顯式自定義 page size,例如:4KB/2MB/2048/1GB

NOTE:針對虛拟機的 RAM 可以啟動 large page 特性,可以有效提供虛拟機性能。

NOTE:将大頁記憶體配置設定給虛拟機,可以不考慮 GuestOS 是否使用。如果 GuestOS 不使用,則會識别小頁記憶體。相反,如果 GuestOS 是需要使用大頁記憶體的,則必須要為虛拟機配置設定大頁記憶體,否則虛拟機的性能将達不到預期。

NOTE:專有記憶體限制

為專有資源虛拟機使用大頁記憶體。這需要主機擁有足夠的可用大頁記憶體,并且虛拟機記憶體大小是大頁記憶體大小的倍數。

在主機配置時,為所有虛拟機建立兩個資源組,為兩個組配置設定不同的實體記憶體區域。使用專有資源的虛拟機與共享資源的虛拟機分别使用兩個不同的資源組。

專用記憶體的配置設定的複雜性還在于,主要虛拟機之外,KVM 還有許多不同的記憶體配置設定的需求,有些虛拟機處理視訊内容,會在 KVM 過程處理 I/O 請求時,配置設定任意大小的記憶體。有些情況下,這也會影響虛拟 CPU 的使用,因為 KVM 模拟程式線程代表的就是虛拟機行為。更進一步講,主機作業系統也需要記憶體與 CPU 資源。

隻有當系統中有可用大頁記憶體時,虛拟化程式才啟動虛拟機。設定虛拟機類型參數 ​<code>​page_sizes=large​</code>​

虛拟化管理程式将會優先嘗試大頁記憶體,不可用時,使用小頁記憶體啟動虛拟機。設定虛拟機類型參數 page_sizes=any

虛拟機程式将不選擇大頁記憶體啟動虛拟機,即使大頁記憶體可用。設定虛拟機類型參數 ​<code>​page_sizes=small​</code>​

隻有當系統中有可用的 1GB 大頁記憶體時,虛拟化管理程式才啟動虛拟機,并且将不會使用 2MB 的大頁記憶體。設定虛拟機類型參數 ​<code>​page_sizes=1GB​</code>​

可以通過下述屬性參數來配置設定 PCI 直通裝置給虛拟機。

ALIAS:字元串,在 nova.conf 中配置的特定 PCI 裝置的 alias。(DEFAULT pci_alias)

COUNT:整數,配置設定給虛拟機的 ALIAS 類型的 PCI 裝置數量

1.nova-api 對 flavor metadata 或 image property 中的 NUMA 配置資訊進行解析,生成 Guest NUMA topology,儲存為 instance[‘numa_topology’]

2.nova-scheduler 通過 NUMATopologyFilter 判斷 Host NUMA topology 是否能夠滿足 Guest NUMA topology,進行 ComputeNode 排程

Nova 的高性能虛拟機支撐

3.nova-compute 再次通過 instance_claim 檢查 Host NUMA 資源是否滿足建立 Guest NUMA。

Nova 的高性能虛拟機支撐

4.nova-compute 建立 Guest NUMA node 和 Host NUMA node 的映射關系,并根據映射關系調用 libvirt driver 生成 XML 檔案。

Resource Tracker 會重新整理 Host NUMA 資源的使用情況:

Nova 的高性能虛拟機支撐

對 NUMA 相關資料的解析和處理,提供了以下 class:

vim nova/virt/hardware.py

class VirtNUMATopologyCell(object):

NUMA 單元,定義了 NUMA cell 内的基本資料成員。

class VirtNUMATopologyCellLimit(VirtNUMATopologyCell):

NUMA 限制量單元,定義了 NUMA cell 内可以使用資源的最大限。

class VirtNUMATopologyCellUsage(VirtNUMATopologyCell):

NUMA 使用量單元,定義了 NUMA cell 内已使用的資源。

class VirtNUMATopology(object):

NUMA 拓撲單元,定義了 NUMA 的基本資料成員,即 cells[]

class VirtNUMAInstanceTopology(VirtNUMATopology):

為 guest VM 提供 NUMA 相關的操作。

class VirtNUMAHostTopology(VirtNUMATopology):

為 Host 提供 NUMA 相關的操作。

檢視 Host NUMA topology:

檢視 Guest NUMA topology:

從 libvirt.xml 檢視

Nova 的高性能虛拟機支撐

Host OS 上執行 numastat -c qemu-system-x86_64

Nova 的高性能虛拟機支撐

檢視 Instance 的 NUMA Topology 資訊

Nova 的高性能虛拟機支撐

NFV 支撐:

Nova 的高性能虛拟機支撐
下一篇: 虛拟桌面

繼續閱讀