此篇文章介紹學習 Linux KVM 時所需要了解的 Memory 相關知識
前言
Memory 在作業系統是用來暫時存放 cpu 要執行的指令以及資料,所有 process 都必須先載入到 memory 中才能正確執行。
而在虛擬化的環境中,virtual machine 中 memory 的使用是需要額外的 mapping 機制對應到 host machine,在這個部分的效率的高低,當然也就會決定 virtual machine 整體的系統性能。
VM 可以使用多少記憶體?
也許這是很多人想要了解的,在 host machine 上安裝了一大堆實體記憶體,究竟可以分配給 VM 的可以有多少呢? 以下有兩個簡單公式可以計算:
實體記憶體 <= 64 GB
RAM - 2 GB = Amount of RAM available to VMs in GBs
實體記憶體 > 64GB
RAM - (2 GiB + .5* (RAM/64)) = Amount of RAM available to VMs in GBs
假設 host machine 記憶體有 32GB,則一共可以配置 32 - 2 = 10
GB 的記憶體給 VM。
假設 host machine 記憶體有 256GB,則一共可以配置 256 - (2 + 0.5 * (256 / 64)) = 252
GB 的記憶體給 VM
配置 VM 記憶體
幫 virtual machine 配置記憶體是很容易的,只要使用 -m 參數即可,預設的格式是:
-m megs
預設是以 MB 作為預設的單位,也可以使用 G 表示要使用 GB 為單位,例如:
1 | # 記憶體大小為 2048 MB |
EPT
傳統要把 virtual machine 中運行的應用程式所使用的 memory 對應到 host machine 的 memory,一共是有三層關係的,下圖可做個簡單說明:
Guest Virtual Address(GVA) <–> Guest Physical Address(GPA) <–> Host Physical Address(HPA)
但由於上面三層的轉換效率是很差的,因此後來透過軟體實作了稱為 Shadow Page Tables 的機制,將三層中的第二層拿掉,直接讓 Guest Virtual Address 與 Host Physical Address 可以有直接對應的機制:
此時 hypervisor 就可以把 shadow page tables 載入到 MMU(Memory Management Unit) 中進行 address translation 的工作。
但 shadow page tables 實作起來不僅複雜,也會 memory 的額外消耗(每一個 virtual machine 都需要一個 shadow page table);因此 Intel 提出了 EPT(Extended Page Tables),AMD 提出了 NPT(Nested Page Tables),在硬體層直接提供了 GVA <--> GPA <--> HPA
的轉換,不僅提升了 memory 虛擬化的效能,也降低了 memory 虛擬化的複雜度。
以下是 Intel EPT 技術的概觀:
其中可以看到 Intel 在硬體中增加了 CR3(Control Registor 3) 來處理 GVA <–> GPA 的轉換,以及 EPT 來處理 GPA <–> HPA 的轉換。
由於所有的轉換都在硬體層級完成,因此速度很快;而且由於整個轉換過程只需要一個 EPT Page Table,因此在 memory 的消耗上也相對的低。
VPID
要了解 VPID,首先要知道 TLB(Translation Lookaside Buffer) 是什麼? 可以參考以下連結:
分配給 virtual machine 的每一個 vCPU 都會有一個 TLB
而 VPID 則是在硬體層級對 TLB 資源管理的優化,在 virtual machine 進行 migration / VM Entry / VM Exit 時,避免對 TLB 進行轉存 & 清除,進而降低 memory 的額外消耗,對於 live migration 有顯著的效能提升。
查詢 EPT & VPID 的支援度
1 | # 查詢 CPU 是否支援 EPT & VPID |
Huge Page
x86 架構的 CPU 預設的 memory page table 大小為 4KB,而 x86-64 則可以支援到 2MB 大小的 memory page table(亦稱為 Huge Page),在 Linux 2.6 以上的 kernel 都支援這個特性。
而使用 Huge Page 有何優缺點呢?
優點:
page table 數量減少,更節省 memory
由於 memory address translation 的工作減少了,因此 page fault 機率降低為 Huge Page Size / 4KB 分之一
提升了 memory 存取的效能
提高 TLB 命中率,因而減少 CPU cache 的使用,最後提升了系統整體效能
適合用在 memory 存取密集的 virtual machine 上
缺點:
Huge Page 無法被 swap out 到硬碟上
無法使用 Ballooning 的方式自動增長
並非適合所有不同工作類型的 virtual machine
在 KVM 中使用 Huge Page
1、檢查 host machine 中 Huge Page 的設定資訊:
1 | # 目前預設的 page size |
2、掛載 hugetlbfs 檔案系統
1 | # 掛載 hugetlbfs 檔案系統 |
3、設定 Huge Page 的數量
假設要啟動一個 memory 為 2048 MB 的 virtual machine,可以算出 Huge Page(2048 KB) 的數量為:
2048 * 1024 / 2048 = 1024
因此這邊設定 Huge Page 的數量為 1024 個:
1 | # 設定 Huge Page 的數量為 1024 個 |
4、啟動 virtual machine 使用 Huge Page
1 | $ kvm -vnc 0.0.0.0:1 -smp 4 -m 2048 -hda /kvm/storage/vm_disks/ubnutu1604.img -mem-path /dev/hugepages |
可以看出 virtual machine 的確消耗了一些 huge page,但其實並不是全部,因為 virtual machine 實際上並沒有完整分配到 2048 MB 的 memory;若要完整分配指定的 memory,則需要加上 -mem-prealloc
參數。
Memory Overcommit
除了之前介紹 CPU 可以 overcommit 之外,memory 也可以設定一定程度的 overcommit,原因是因為每台電腦在運作時一般都不會耗盡記憶體。對 host machine 來說,virtual machine 也只是一個 QEMU process,在啟動的當下是不會分配完整記憶體的,而是隨著 virtual machine 的更多要求下逐步分配到位,因此可以在此行為的前提下設定 memory overcommit。
在 KVM 中有三種方式可以達到 memory overcommit:
**Swapping**:透過 system swap(一般為硬碟空間) 來彌補 memory 不足的問題
**Ballooning**:透過
virtio_balloon
driver 來達成**Page Sharing**:使用
KSM(Kernel Samepage Merging)
合併多台 virtual machine 中相同的 memory page
關於第一個方式的 swap,根據 RedHat RHEL 7 官方文件所提供的建議,swap 大小的設定建議如下:
系統記憶體 | 建議 swap 大小 |
---|---|
⩽ 2 GB | 2 x memory size |
> 2 GB – 8 GB | 等同 memory size |
> 8 GB – 64 GB | 至少 4 GB |
> 64 GB | 至少 4 GB |