Ceph 新版本 Reef 下:RGW 性能
背景
Ceph 社區(qū)最近凍結(jié)了即將發(fā)布的 Ceph Reef 版本,今天我們研究一下 Reef 在 10 個節(jié)點、60 個 NVMe 驅(qū)動器集群上的 RGW 性能。
我們部署了 20 個 RGW 實例和 200 個 hsbench S3 客戶端來在 512 個bucket 中執(zhí)行高度并行的工作負載。
在多次的測試中,我們發(fā)現(xiàn)Reef 通常比 Quincy 快 1-5%。
在 3X 復(fù)制時,4MB GET 的速度大約為 53GB/s,4MB PUT 的速度為 18.6GB/s。
這兩種情況下我們都達到了網(wǎng)絡(luò)的瓶頸。Reef 在 3X 復(fù)制時也實現(xiàn)了大約 312K 4KB GET/s 和 178K 4KB PUT/s。
在大對象測試中,不同版本之間的 CPU 使用率是相等的。然而,在 4KB PUT 和 GET 測試中,Reef 使用的 CPU 資源比 Quincy 多 23%。隨著 Reef 版本發(fā)布的臨近,我們將時刻關(guān)注這一點。
最后,我們注意到 OSD 和 RGW 之間的總 CPU 使用率存在顯著偏差,具體取決于正在運行的工作負載類型。同時這也對我們的硬件選型有很大的影響。
介紹
在本系列的第 1 部分(https://ceph.io/en/news/blog/2023/reef-freeze-rbd-performance/)中,我們研究了如何使用 CBT (https://github.com/ceph/cbt)工具來了解 RBD 性能在多個 Ceph 版本之間的變化。
在第 1 部分中,CBT 使用 Jens Axboe 的 fio (https://github.com/axboe/fio)工具針對 RBD 鏡像進行性能測試。CBT 還可以利用 S3 基準測試工具來測試 RGW。
在之前的 Ceph 版本中,我們已經(jīng)使用此功能來對性能進行測試。結(jié)合 CBT、hsbench (https://github.com/markhpc/s3bench.git) S3 基準測試和 git bisect,我們發(fā)現(xiàn)有兩個代碼的提交更新會損害 Ceph Pacific 版本中的 RGW 性能和效率。
一旦確定了這些代碼問題,Ceph 開發(fā)人員就能很快進行修復(fù),使性能和 CPU 使用率恢復(fù)到我們在 Nautilus 中看到的水平。
在本文中,我們將使用相同的工具來測試 Reef 在凍結(jié)后的性能。
集群設(shè)置
Nodes | 10 x Dell PowerEdge R6515 |
CPU | 1 x AMD EPYC 7742 64C/128T |
Memory | 128GiB DDR4 |
Network | 1 x 100GbE Mellanox ConnectX-6 |
NVMe | 6 x 3.84TB Samsung PM983 |
OS Version | CentOS Stream release 8 |
Ceph Version 1 | Quincy v17.2.5 (built from source) |
Ceph Version 2 | Reef 9d5a260e (built from source) |
所有節(jié)點都連接到同一臺 Juniper QFX5200 交換機上,并通過單個 100GbE QSFP28 連接。同時我們部署了 Ceph 并使用 CBT (https://github.com/ceph/cbt/)啟動了 fio 測試。
除非特別說明,否則每個節(jié)點都安裝 6 個 OSD,同時 fio 運行 6 個 librbd 類型的進程。
基于英特爾的系統(tǒng)可以配置 "latency-performance" 以及 "network-latency" 來對系統(tǒng)進行調(diào)優(yōu)。這避免與 CPU C/P 狀態(tài)轉(zhuǎn)換帶來延遲。
基于 AMD Rome 的系統(tǒng)在這方面的調(diào)優(yōu)并沒有太大的改變,而且我們還沒有確認 tuned 實際上限制了 C/P 狀態(tài)轉(zhuǎn)換,但是對于這些測試,tuned 配置文件仍然設(shè)置為 “network-latency”。
測試設(shè)置
CBT 需要針對所部署的 Ceph 集群調(diào)整幾個參數(shù)。每個 OSD 都配置 8GB 內(nèi)存,并且在禁用 cephx 的情況下使用 msgr V1。沒有對 RGW 進行特殊調(diào)整。hsbench (https://github.com/markhpc/hsbench.git) 用于 S3 測試。
每個節(jié)點都啟動了 20 個 hsbench 進程,每個進程都連接到一個不同的 RGW 實例。
因此,每個 RGW 進程都有一個關(guān)聯(lián)的 hsbench 進程從不同的節(jié)點連接到它(總共 200 個 hsbench 進程)。每個 hsbench 進程都配置為使用 64 個線程并使用 512 個公共的 bucket 。
同時,也禁用了部分 Ceph 的后臺服務(wù)進程,如 scrub、deep scrub、pg autoscaling 和 pg balancing。在所有 RGW 池中使用了 3X 復(fù)制。
數(shù)據(jù)和索引池各有 8192 個 PG,而 root,control,meta,以及 log 池各有 64 個 PG。分別使用 200 萬個 4MiB 對象和 2 億個 4KiB 對象為 quincy 和 reef 運行了兩個單獨的測試 case。
每個測試 case 按以下順序運行:
Test | Description |
cxi | Clear all existing objects from buckets, delete buckets, initialize buckets |
p | Put objects into buckets |
l | List objects in buckets |
g | Get objects from buckets |
d | Delete objects from buckets |
4MB PUT
Reef 比 Quincy 要快一些,在所有三個測試中保持大約 2% 的領(lǐng)先優(yōu)勢。RGW 和 OSD 進程的 CPU 使用率在這兩個測試中是相似的。
令人驚訝的是,Quincy 和 Reef 都顯示 RGW CPU 使用在 5 個核心左右,但當測試大約 2-3 分鐘后翻倍至 10 個核心。
在本系列的第 1 部分(https://ceph.io/en/news/blog/2023/reef-freeze-rbd-performance/)中,我們研究了 4MB 的順序?qū)懭胪掏铝?,發(fā)現(xiàn)使用 librbd,我們可以保持大約 25GB/s(復(fù)制時為 75GB/s)。
為什么我們在這里看到 4MB PUT 的速度只有大約 18.5GB/s?很大一部分原因是我們傳輸了兩次數(shù)據(jù)。一次從客戶端到 RGW,然后再次從 RGW 到 OSD。一些傳輸將發(fā)生在位于同一節(jié)點上的 RGW 實例或 OSD 上。
同時,我們也不能忽略復(fù)制,因為至少有 2 次從主 OSD 到次 OSD 的額外傳輸,這些傳輸必須落在其他節(jié)點上。
Probability of 2 transfers = 1/10 * 1/10 = 1/100
Probability of 4 transfers = 9/10 * 9/10 = 81/100
Probability of 3 transfer = 1 - 1/100 - 81/100 = 18/100
相對于最大網(wǎng)絡(luò)吞吐量,我們應(yīng)該期望的一般最佳情況下的性能是:
100 / (2 * (1/100) + 4 * (81/100) + 3 * (18/100)) = 26.31%
在 librbd 的情況下,我們總是以 3X 復(fù)制進行 3 次傳輸(1 次到主 OSD,然后 1 次到另外兩個次 OSD):
100 / 3 = 33.3%
用上述的結(jié)果乘以我們的期望性能:
25GB/s * 26.31/33.3 = 19.75GB/s
看起來我們做的比 RBD 稍微差一點,但一旦考慮到額外的網(wǎng)絡(luò)開銷,那么則差不了太多。
4MB LIST
LIST測試的完成時間完全由對象的數(shù)量決定。在這種情況下,因為我們總共只有 2M 個對象分布在 512 個桶中,所以單個桶列 LIST 時間非常短。Reef 再次與 Quincy 一樣快或略快。
4MB GET
在此測試中,RGW 和 OSD 進程的 CPU 使用率非常一致。與 PUT 測試一樣,我們必須考慮必須傳輸數(shù)據(jù)的次數(shù)。
因為我們使用的是復(fù)制,所以我們總是只將數(shù)據(jù)從 OSD 傳輸?shù)?RGW 一次,然后再傳輸?shù)娇蛻舳恕?/span>
Probability of 0 transfers = 1/10 * 1/10 = 1/100
Probability of 2 transfers = 9/10 * 9/10 = 81/100
Probability of 1 transfer = 1 - 1/100 - 81/100 = 18/100
100 / (0 * (1/100) + 2 * (81/100) + 1 * (18/100)) = 55.6%
在這里,我們?yōu)?Quincy 維持約 51GB/s,為 Reef 維持約 53GB/s。這非常接近這些 100GbE NIC 應(yīng)該能夠提供的最大值。
4MB DELETE
這里的 DELETE 測試“吞吐量”數(shù)字似乎高得驚人,但是 DELETE 性能主要取決于被刪除對象的數(shù)量而不是對象的大小,并且實際刪除過程是異步的。話雖如此,Reef 的平均速度似乎再次略快于 Quincy。
在第 3 次測試迭代中,兩者似乎都具有更快的刪除速度。其原因尚不清楚。
4KB PUT
與之前的測試一樣,Reef 比 Quincy 快一點。兩者的 OSD CPU 使用率大致相同,但 RGW CPU 使用率似乎上升了大約 15%。
從好的方面來說,在 Quincy 的 RGW 中,每次測試迭代結(jié)束時 CPU 消耗都會急劇上升,這在 Reef 中沒有發(fā)生。
這里的一個重點是 OSD 和 RGW 都盡可能地保持 180K PUT/s。RGW 要求每個 PUT 操作到主 OSD 的 3 次往返(2 次同步,1 次異步)以正確寫入數(shù)據(jù)并保持桶索引正確同步。
4KB LIST
與之前的測試相比,對象越多,桶 LIST 時間就越長。Reef 在第一次迭代中只是稍微快一點,但 Quincy 和 Reef 在其他方面差不多。
4KB GET
首先,Reef 中的 GET 性能比 Quincy 中更快、更穩(wěn)定。話雖如此,這里有一些非常有趣的行為。
在 Quincy 中,測試的前 2 分鐘主要是極高的 CPU 使用率。一旦完成,穩(wěn)定狀態(tài)的 CPU 使用率比 Reef 低很多。OSD CPU 使用率同樣較低。
在此測試中,Reef 在 RGW 端使用了大約 10-20% 的 CPU,在 OSD 端使用了大約 17-23% 的 CPU。Reef 的行為似乎更加一致。
雖然 RGW CPU 使用率在測試開始時較高,但遠不及 Quincy 測試中發(fā)生的變化。
4KB DELETE
最后,Reef 在刪除 4K 對象時平均要快 5%。同樣,這是一個異步過程,因此結(jié)果可能與 RGW 在后臺刪除內(nèi)容的速度不匹配。
結(jié)論
這些測試僅展示了 RGW 性能特征的一小部分。我們沒有在本文中查看單操作延遲,或嘗試不同的客戶端來進行測試。盡管如此,在我們的測試中,我們看到了兩種趨勢:
1. Reef 的性能比 Quincy 高出約 1-5%,并且在所有測試中都相當一致,并且發(fā)生在大多數(shù)測試迭代中。
2. 在某些測試中,尤其是 4K GET 測試中,Reef 的 CPU 使用率高于 Quincy。這在 RGW 中表現(xiàn)的很明顯,另外我們在 OSD 中也發(fā)現(xiàn)了這個問題。我們希望在發(fā)布 Reef 之前能跟進解決這個問題。
關(guān)于這些結(jié)果,還有一些額外的事情需要注意。
在之前的測試中,我們?yōu)橐粋€ 60 NVMe 集群使用了 10 個 RGW 實例。
在這些測試中,我們使用了 20 個 RGW 實例,發(fā)現(xiàn)小對象 PUT 和 GET 測試的性能明顯高于我們之前看到的性能。很有可能將 RGW 數(shù)量增加到更高的比率,也許每 2 個甚至每 1 個 OSD 有 1 個 RGW 實例可能會產(chǎn)生更好的小對象性能。
第二個有趣的事情是,在這些測試中,CPU 消耗差異很大,RGW 和 OSD 進程之間的 CPU 消耗比率也發(fā)生了變化。
如果我們查看 Reef 結(jié)果并計算 RGW 和 OSD 使用的大概核心數(shù),我們得到:
4MB
Test | Result | Total RGW Cores | Total OSD Cores | Total Cores | RGW/OSD Core Ratio |
4MB PUT | 18.6GB/s | 184 Cores | 152 Cores | 336 Cores | 6/5 |
4MB GET | 53GB/s | 88 Cores | 55 Cores | 143 Cores | 8/5 |
4KB
Test | Result | Total RGW Cores | Total OSD Cores | Total Cores | RGW/OSD Core Ratio |
4KB PUT | 178K IOPS | 269 Cores | 475 Cores | 744 Cores | 11/20 |
4KB GET | 312K IOPS | 302 Cores | 102 Cores | 404 Cores | 3/1 |
除了了解這些測試中使用的內(nèi)核數(shù)量之外,還可以從這些結(jié)果中獲取另外一個結(jié)論:在容器中運行 Ceph 是非常不錯的。
因為 Ceph 的最新版本有大量的外部依賴項,這使包管理變的非常麻煩。除此之外,很多用戶已經(jīng)采用了容器化管理應(yīng)用程序,并希望以同樣的方式部署 ceph。
對此的一個需求是,大家希望在容器級別分配 Ceph 守護進程靜態(tài)資源分配:一定數(shù)量的內(nèi)存和一定數(shù)量的內(nèi)核來運行。這是也是可能比較麻煩的地方。
關(guān)于內(nèi)存配額的問題我們放到以后再進行討論,但簡而言之:在非專門設(shè)計的應(yīng)用程序中保證內(nèi)存使用是極其困難的。
默認情況下,我們能做的就是讓 Ceph 進程監(jiān)視它們的映射內(nèi)存并自動調(diào)整非必要內(nèi)存使用量。因為 Ceph 包含了底層內(nèi)存自動調(diào)整和緩存管理代碼。
限制 CPU 核心數(shù)通常不會導(dǎo)致與限制內(nèi)存相同的問題。在這些測試中,PUT 和 GET 之間的差距接近 6 倍。
如果我們只針對一種場景進行優(yōu)化,那么我們要么會影響到另一種場景,要么會有大量多余的 CPU 核心在不同的時間點處于空閑狀態(tài)。
如果我們需要更多的 4K GET 吞吐量,那么也許在 Ceph 的某個未來版本中,我們可以按需啟動或關(guān)閉 RGW 容器。
但就目前而言,我們需要靈活變通從而實現(xiàn) Ceph RGW 存儲的高性能和高效率。