本篇文章著眼于 Linux 頁(yè)面大小對(duì)數(shù)據(jù)庫(kù)性能的影響,以及如何優(yōu)化數(shù)據(jù)庫(kù) Kubernetes 節(jié)點(diǎn)。
大多數(shù)流行的數(shù)據(jù)庫(kù)都受益于 Linux 大頁(yè)面。
Kubernetes 最初旨在大規(guī)模編排容器的生命周期,用于輕量級(jí)、無(wú)狀態(tài)應(yīng)用程序,如 Ngnix、Java 和 Node.js。對(duì)于這個(gè)用例,Linux 4K 頁(yè)面是正確的選擇。
最近,通過(guò)添加Statefulsets、Persistent Volumes和大頁(yè)面等功能,Kubernetes 得到了增強(qiáng),以支持大型、有狀態(tài)、持久性數(shù)據(jù)庫(kù)。
下圖顯示了使用 Linux 大頁(yè)面對(duì)數(shù)據(jù)庫(kù)性能的影響有多大。
上圖顯示,對(duì)于相同的數(shù)據(jù)庫(kù),相同的數(shù)據(jù),相同的工作負(fù)載,使用Linux 2MB頁(yè)面而不是4K頁(yè)面時(shí)吞吐量可以提高8倍。該圖還顯示,隨著并發(fā)水平的提高,大頁(yè)面的好處也隨之增加。
文章的其余部分介紹了一些背景概念,并著眼于影響數(shù)據(jù)庫(kù)工作負(fù)載的 Linux 頁(yè)面大小的因素。
Linux 頁(yè)面大小
所有現(xiàn)代多用戶操作系統(tǒng)都使用虛擬內(nèi)存來(lái)使不同的進(jìn)程能夠使用內(nèi)存而不必?fù)?dān)心底層細(xì)節(jié)。Linux x86 64 的系統(tǒng)使用分頁(yè)進(jìn)行虛擬內(nèi)存管理。
Linux x8664 支持以下頁(yè)面大?。?/p>
4K
2MB
1GB
頁(yè)大小是可用于虛擬內(nèi)存管理的連續(xù)數(shù)據(jù)的最小單位。?
頁(yè)面的大小是一種權(quán)衡。4K 頁(yè)面最大限度地減少了小內(nèi)存分配的內(nèi)存浪費(fèi)。對(duì)于大內(nèi)存分配,使用 2MB 或 1GB 頁(yè)面總共需要更少的頁(yè)面,而且速度會(huì)明顯更快,因?yàn)?strong>將虛擬內(nèi)存轉(zhuǎn)換為物理內(nèi)存地址會(huì)產(chǎn)生相關(guān)成本。?
TLB 緩存命中和未命中
Linux 上任何進(jìn)程的每次內(nèi)存訪問(wèn)(例如,無(wú)論是 Nginx、Node.js 還是 MySQL)都需要從虛擬內(nèi)存轉(zhuǎn)換為物理內(nèi)存。由于這是一個(gè)常規(guī)的操作,所有 CPU 都有某種形式的轉(zhuǎn)換后備緩沖區(qū)[TLB],它充當(dāng)最近轉(zhuǎn)換的內(nèi)存地址的緩存。
所有從虛擬內(nèi)存到物理內(nèi)存的轉(zhuǎn)換首先查看 TLB 中是否已經(jīng)存在映射。如果映射已經(jīng)存在,則稱為 TLB 緩存命中。TLB 緩存命中非??欤⑶野l(fā)生在硬件中。當(dāng) TLB 緩存中不存在從虛擬內(nèi)存到物理內(nèi)存的轉(zhuǎn)換時(shí),稱為 TLB 緩存未命中。TLB 緩存未命中需要通過(guò)頁(yè)面遍歷在 Linux 內(nèi)核頁(yè)表中的軟件中解決映射。盡管頁(yè)面遍歷是高效的 C 代碼,但它比通過(guò) TLB 緩存在硬件中進(jìn)行映射要慢得多。
為什么 TLB 緩存未命中對(duì)數(shù)據(jù)庫(kù)很重要
所有數(shù)據(jù)庫(kù)最終都需要訪問(wèn)內(nèi)存中的數(shù)據(jù)進(jìn)行讀取或?qū)懭搿K羞@些數(shù)據(jù)庫(kù)讀取或?qū)懭攵夹枰辽龠M(jìn)行一次 TLB 查找。TLB 緩存未命中會(huì)顯著減慢數(shù)據(jù)庫(kù)的讀寫速度:
數(shù)據(jù)庫(kù)越大,訪問(wèn)的不同頁(yè)面越多,需要的 TLB 查找就越多。這實(shí)際上是數(shù)據(jù)庫(kù)工作集大小。
并發(fā)越大,單位時(shí)間需要的 TLB 查找越多
如果您有具有可變長(zhǎng)度數(shù)據(jù)類型(例如字符串、JSON、CLOB 或 BLOB)的行/記錄,那么這些行/記錄的寬度很容易超過(guò) 4KB。當(dāng) Linux 頁(yè)面大小為 4KB 時(shí),訪問(wèn)寬度為 20KB 的單行/記錄通常需要至少五次 TLB 查找。如果使用 2MB 或 1GB Linux 頁(yè)面,訪問(wèn)相同的 20KB 行/記錄通常只需要一次 TLB 查找。所以一般來(lái)說(shuō),數(shù)據(jù)庫(kù)行(rows)/記錄(record)越寬,大頁(yè)面與 4K Linux 頁(yè)面的優(yōu)勢(shì)就越大。
挑戰(zhàn)在于 CPU 具有少量 TLB 緩存條目:
4K 頁(yè)面的 L1 TLB 中64個(gè)條目,2MB 頁(yè)面的 32 個(gè)條目,1G 頁(yè)面的 8 個(gè)條目
4K + 2MB 頁(yè)面的 L2 TLB 中有1024個(gè)條目
4K + 1GB 頁(yè)面的 L2 TLB 中有1024個(gè)條目
AMD EPYC Zen 3
4K + 2MB 頁(yè)面 + 1GB 頁(yè)面的 L1 TLB 中的64 個(gè)條目
4K 和 2MB 頁(yè)面的 L2 TLB 中的512 個(gè)條目
由于 L1 CPU 緩存通常只有大約 64 個(gè) TLB 4K 條目,而最新的 Intel 和 AMD CPU 上的 L2 緩存則有 512 到 1024 個(gè) 4K 條目,如果您的數(shù)據(jù)庫(kù)具有寬行/記錄并訪問(wèn)許多不同的行/記錄,那么它幾乎總是會(huì)得到 TLB 緩存未命中。
如果您使用 2MB 頁(yè)面,那么您不太可能遇到 TLB 緩存未命中,因?yàn)槟行У厥?TLB 緩存更大:
AMD EPYC Zen 3 CPU 比?L1 和 L2 CPU?緩存大?512 倍
英特爾 Ice Lake CPU 的 L1 CPU 緩存大 256 倍,L2 CPU 緩存大 512 倍
減少 TLB 緩存未命中的數(shù)量可以對(duì)數(shù)據(jù)庫(kù)性能產(chǎn)生顯著的積極影響。
基準(zhǔn)
Linux 并不關(guān)心你的數(shù)據(jù)庫(kù)是 MySQL、PostgreSQL 還是 Oracle。Linux 并不關(guān)心您的應(yīng)用程序是用 Node.js、Java、Go、Rust 還是 C 編寫的。Linux 性能取決于諸如工作負(fù)載每單位時(shí)間發(fā)生多少 TLB 緩存未命中等指標(biāo)。
以下基準(zhǔn)測(cè)試著眼于幾種配置:
窄行(Narrow)/記錄 [128 字節(jié)],訪問(wèn) 1 億條不同的行/記錄的概率均勻
整個(gè)行/記錄應(yīng)適合單個(gè) 4KB Linux 頁(yè)面
中等行(Medium)/記錄 [8 KB],平均訪問(wèn) 1 億條不同的行/記錄的概率
行/記錄應(yīng)至少適合兩個(gè) 4KB Linux 頁(yè)面
更寬的行(Wider)/記錄 [16 KB],甚至有可能訪問(wèn) 1 億條不同的行/記錄
行/記錄應(yīng)至少適合四個(gè) 4KB Linux 頁(yè)面
16 KB 不是很寬,但結(jié)果很顯著
要最小化變量的數(shù)量:
只執(zhí)行數(shù)據(jù)庫(kù)讀取,數(shù)據(jù)庫(kù)中的所有 1 億行都可以輕松放入 DRAM 并且數(shù)據(jù)庫(kù)被“預(yù)熱”
數(shù)據(jù)庫(kù)客戶端使用 IPC 而不是 TCP 套接字來(lái)訪問(wèn)數(shù)據(jù)庫(kù)
這種配置意味著沒(méi)有磁盤 IO 或網(wǎng)絡(luò)處理,因此工作負(fù)載會(huì)在 CPU 和/或內(nèi)存訪問(wèn)上出現(xiàn)瓶頸。
128 字節(jié)行/記錄的4K Linux 頁(yè)面
上圖顯示,在 AMD EPYC 7J1C3 @ 2.55 GHz 處理器上使用 4K Linux 頁(yè)面和 128 個(gè)數(shù)據(jù)庫(kù)連接,在單臺(tái) Linux 機(jī)器上每秒可以執(zhí)行超過(guò) 350 萬(wàn)次數(shù)據(jù)庫(kù)讀取。
128 字節(jié)行/記錄的4K 與 2MB 頁(yè)面
上圖顯示,對(duì)于相同的硬件、相同的數(shù)據(jù)庫(kù)、相同的表、相同的數(shù)據(jù)、相同的查詢,2 MB 的大頁(yè)面可以實(shí)現(xiàn)比使用 4K Linux 頁(yè)面時(shí)多出 8 倍的吞吐量。
對(duì)于窄行/記錄,吞吐量提高 8 倍是一個(gè)顯著的結(jié)果。
8 KB行/記錄的4K 與 2MB 頁(yè)面
對(duì)于 8KB 寬的數(shù)據(jù)庫(kù)行/記錄,2MB 頁(yè)面可以提供比 4K 頁(yè)面多 8 倍的吞吐量。
對(duì)于中等寬度的行/記錄,吞吐量提高 8 倍是一個(gè)重要的結(jié)果。
16 KB行/記錄的4K 與 2MB 頁(yè)面
上圖顯示,對(duì)于相同的硬件、相同的數(shù)據(jù)庫(kù)、相同的表、相同的數(shù)據(jù)、相同的查詢,2 MB 的大頁(yè)面可以實(shí)現(xiàn)比使用 4K Linux 頁(yè)面時(shí)多出 5 倍的吞吐量。
對(duì)于更寬的行/記錄,吞吐量提高 5 倍是一個(gè)重要的結(jié)果。
2MB 和 1GB Linux 頁(yè)面怎么樣
很容易看出 2MB Linux 頁(yè)面與 4K 頁(yè)面的優(yōu)勢(shì),例如提高 8 倍。您是否還希望看到 2MB 和 1GB Linux 頁(yè)面之間的顯著差異?
由于所有測(cè)試的行寬都可以放入 2MB 頁(yè)面,唯一的變量是 2MB 與 1GB Linux 頁(yè)面的 TLB 緩存未命中率,用于 1 億不同的行/記錄。
對(duì)于所有經(jīng)過(guò)測(cè)試的行寬 [128 字節(jié)、8KB 和 16KB],1GB Linux 頁(yè)面的吞吐量比 2MB Linux 頁(yè)面高 1% 到 21%。
雖然高達(dá) 21% 的吞吐量改進(jìn)不如 8 倍令人印象深刻,但它仍然存在一些差異。
也許行/記錄寬于 2MB 的測(cè)試會(huì)顯示顯著差異?
Kubernetes 節(jié)點(diǎn)專業(yè)化
在 Kubernetes 的早期,工作負(fù)載往往用于小型、無(wú)狀態(tài)的“基于 Web”的應(yīng)用程序,例如負(fù)載均衡器、Web 服務(wù)器、代理和各種應(yīng)用程序服務(wù)器。對(duì)于這個(gè)用例,使用 Linux 4K 頁(yè)面是一個(gè)合適的選擇。
最近,更專業(yè)的工作負(fù)載正在 Kubernetes 集群中運(yùn)行,這些集群具有不同的硬件和/或軟件要求。例如,機(jī)器學(xué)習(xí)工作負(fù)載可以在通用 x86 64位 CPU 上運(yùn)行,但在具有 GPU 或 ASIC 的 Kubernetes 節(jié)點(diǎn)上運(yùn)行速度往往要快得多。此外,某些 Kubernetes 節(jié)點(diǎn)可能專門用于具有快速本地存儲(chǔ)、更多 RAM 或可能運(yùn)行 ARM 64 CPU。
因此,并非所有 Kubernetes 節(jié)點(diǎn)都具有完全相同的 CPU、RAM、存儲(chǔ)等,一些節(jié)點(diǎn)可以使用守護(hù)程序集或節(jié)點(diǎn)標(biāo)簽來(lái)定義和公開這些節(jié)點(diǎn)的特定功能。使用POD 標(biāo)簽[使用選擇器來(lái)匹配節(jié)點(diǎn)標(biāo)簽],允許 Kubernetes 調(diào)度程序在最合適的節(jié)點(diǎn)上自動(dòng)運(yùn)行 POD。
上圖顯示了具有四種類型的專用節(jié)點(diǎn)的 Kubernetes 集群。
你可以做些什么來(lái)優(yōu)化 Kubernetes 上的數(shù)據(jù)庫(kù)性能
通常不在您控制范圍內(nèi)的事情:
數(shù)據(jù)庫(kù)行/記錄的寬度
您的數(shù)據(jù)庫(kù)中有多少行/記錄
您的數(shù)據(jù)庫(kù)工作集大小
數(shù)據(jù)庫(kù)中數(shù)據(jù)訪問(wèn)的并發(fā)性和頻率
CPU 的 TLB 緩存大小
在范圍內(nèi)可以控制你的Kubernetes集群的事情:
Linux 內(nèi)核在 Linux x8664 Kubernetes 節(jié)點(diǎn)上使用 4KB、2MB 還是 1GB Linux 頁(yè)面
您配置了多少 Linux 大頁(yè)面 [2MB 或 1GB]
Kubernetes 應(yīng)用程序的內(nèi)存和大頁(yè)面資源?的請(qǐng)求和限制
數(shù)據(jù)庫(kù)被認(rèn)為是 Kubernetes 中的一個(gè)應(yīng)用程序
您可以選擇為要在其上運(yùn)行數(shù)據(jù)庫(kù)工作負(fù)載的一組機(jī)器配置具有 2MB 或 1GB 大頁(yè)面的 Kubernetes 節(jié)點(diǎn) [即 Linux 主機(jī)]。
在 Linux上配置大頁(yè)面的方式與Kubernetes 無(wú)關(guān)。您必須在 Linux 內(nèi)核中配置大頁(yè)面,因?yàn)槟鸁o(wú)法在 Kubernetes 或容器級(jí)別執(zhí)行此操作。通常你想關(guān)閉透明大頁(yè)面,因?yàn)樗鼈兺ǔ2粫?huì)提高數(shù)據(jù)庫(kù)性能,只會(huì)浪費(fèi)內(nèi)存。
在 Linux x8664 上配置 2MB 頁(yè)面對(duì)于任何 Linux 發(fā)行版都相當(dāng)簡(jiǎn)單,通常無(wú)需更改啟動(dòng)時(shí)間參數(shù)即可完成。
配置 1GB Linux 頁(yè)面的步驟因發(fā)行版而略有不同,并且需要啟動(dòng)時(shí)間參數(shù)。我能夠在最近的 Intel Xeon 和 AMD CPU 上配置 1 GB Linux 頁(yè)面,用于:
紅帽企業(yè) Linux 7.9 和 8.4
Oracle Linux 7.9 和 8.4
CentOS 7 和 8
Ubuntu 18.04 和 20.04
SuSE 12 和 SuSE 15
您應(yīng)該為 Kubernetes 上的數(shù)據(jù)庫(kù)配置多少大頁(yè)面
這個(gè)問(wèn)題是特定于數(shù)據(jù)庫(kù)的。這取決于您的 Kubernetes 節(jié)點(diǎn)有多少 RAM、您希望在該節(jié)點(diǎn)上運(yùn)行多少其他 [非數(shù)據(jù)庫(kù)] POD、這些 POD 需要多少 RAM,以及最終您的數(shù)據(jù)庫(kù)通過(guò)使用更多內(nèi)存而受益多少。
總結(jié)
大多數(shù)流行的數(shù)據(jù)庫(kù)在 Linux x86 64 上看到了大頁(yè)面的性能優(yōu)勢(shì)
Kubernetes 支持 4KB、2MB 和 1GB 的 Linux 頁(yè)面
由于歷史原因,大多數(shù) Kubernetes 集群使用 4KB Linux 頁(yè)面
許多 Kubernetes 集群根據(jù)工作負(fù)載優(yōu)化一些節(jié)點(diǎn) [例如機(jī)器學(xué)習(xí)、快速本地存儲(chǔ)、通用無(wú)狀態(tài) Web 應(yīng)用程序等]
考慮添加另一類經(jīng)過(guò)優(yōu)化以提高數(shù)據(jù)庫(kù)性能的節(jié)點(diǎn)。
使用 2MB 或 1GB 頁(yè)面在某些 Kubernetes 節(jié)點(diǎn)上配置 Linux 內(nèi)核以優(yōu)化它們的數(shù)據(jù)庫(kù)性能
根據(jù)您的數(shù)據(jù)庫(kù)為這些機(jī)器選擇適當(dāng)數(shù)量的大頁(yè)面和 4K Linux 頁(yè)面
編輯:黃飛
?
評(píng)論
查看更多