實體主機 NVMe 效能如何驗收:檔案級測試與延遲判讀

實體主機 NVMe 效能如何驗收:檔案級測試與延遲判讀

實體主機 NVMe 效能如何驗收:檔案級測試與延遲判讀

新機器準備承載資料庫或檔案服務時,單憑複製一個大檔案的速度,並不足以驗收儲存效能。檔案可能命中快取,寫入資料可能尚未持久化,背景工作也可能影響結果。較可靠的做法是固定測試檔案、區塊大小與並行條件,分別觀察吞吐量和延遲,並保留可供重測的原始紀錄。

CloudUDP 的實體主機標準配備兩顆 1TB NVMe,各自直連,沒有硬體 RAID。以下以 Debian 13 為例,使用 fio(可設定 I/O 負載的測試工具)測試指定檔案系統,不寫入原始裝置,也不將測試結果視為業務效能承諾。

一、先確認測試範圍與實際儲存位置

檔案級測試涵蓋的是「檔案系統到儲存裝置」的路徑,並非單獨測量磁碟的效能極限。加密、磁碟區管理、鏡像及掛載選項,都可能影響結果。兩顆磁碟各自直連,也不代表某個目錄會同時使用兩顆磁碟。

先安裝工具並檢查目標目錄。以下將 /srv 作為待確認的測試位置;若它不在目標檔案系統上,應改用實際的掛載目錄。

sudo apt-get install fio
findmnt -T /srv -o TARGET,SOURCE,FSTYPE,OPTIONS
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
df -h /srv
df -i /srv
fio --version

核對可用空間、掛載狀態與目錄權限。不要只看磁碟的標稱容量;檔案系統本身的空間開銷與既有資料都會占用空間。測試檔案寫滿後,仍須保留業務成長所需的空間。

不要將 /dev/nvme… 這類裝置路徑傳給寫入測試。獨立檔案能降低誤覆寫的風險,但無法消除資源競爭;應優先在業務上線前執行。若業務延遲異常、可用空間接近預留底線,或出現 I/O 錯誤,請立即停止。

二、建立獨立目錄並準備完整測試檔案

所有命令都在同一個 Bash 工作階段中執行。由管理員建立僅供目前操作帳號使用的暫存目錄,將測試檔案與結果都放在其中,避免影響既有業務檔案。

TESTDIR=$(sudo mktemp -d /srv/fio-acceptance.XXXXXX)
sudo chown "$(id -u):$(id -g)" "$TESTDIR"
chmod 700 "$TESTDIR"
export TESTDIR
printf '%s\n' "$TESTDIR"
findmnt -T "$TESTDIR"

範例使用 1GiB 檔案,作為驗證流程的起點,不代表整體儲存容量或長期穩態表現。fio 會將 size=1G 解讀為二進位單位,不能與裝置標稱容量混算。確認空間充足後,先以循序寫入填滿檔案:

fio --name=prepare \
  --filename="$TESTDIR/test.bin" \
  --size=1G --rw=write --bs=1M \
  --ioengine=libaio --direct=1 \
  --iodepth=1 --numjobs=1 --end_fsync=1 \
  --group_reporting --output-format=json \
  --output="$TESTDIR/prepare.json"

務必檢查結束狀態與 JSON 中的錯誤欄位。若不支援直接 I/O,應先核對檔案系統與掛載方式,不要逕自改成快取 I/O 後繼續比較。準備階段若出現錯誤,後續讀取測試就沒有可信的基礎。

direct=1 通常會繞過檔案資料的頁面快取,但不會繞過所有裝置快取。end_fsync=1 會在工作結束時要求同步,不代表每次寫入都在模擬資料庫提交。

三、固定參數,分別測試隨機讀取與隨機寫入

先執行單一工作的隨機讀取,再執行隨機寫入,避免混合負載掩蓋問題。測試期間不要同時複製資料或執行其他儲存測試。

fio --name=randread \
  --filename="$TESTDIR/test.bin" \
  --size=1G --rw=randread --bs=4k \
  --ioengine=libaio --direct=1 \
  --iodepth=8 --numjobs=1 \
  --time_based --runtime=30 --ramp_time=5 \
  --group_reporting --output-format=json \
  --output="$TESTDIR/randread-q8.json"
fio --name=randwrite \
  --filename="$TESTDIR/test.bin" \
  --size=1G --rw=randwrite --bs=4k \
  --ioengine=libaio --direct=1 \
  --iodepth=8 --numjobs=1 \
  --time_based --runtime=30 --ramp_time=5 \
  --end_fsync=1 --group_reporting \
  --output-format=json \
  --output="$TESTDIR/randwrite-q8.json"

這裡的執行時間與暖機時間只是測試參數。短時間測試可能受到裝置快取、溫度與背景整理作業影響,不能據此推論長時間寫入的效能。

補做低佇列深度的對照測試

將讀取測試的 iodepth 改為 1,輸出檔案改為 randread-q1.json,其餘參數保持不變。佇列深度表示允許同時尚未完成的 I/O 請求數,不等於 CPU 核心數,也不是業務的並行連線數。

若提高佇列深度後,吞吐量增加、尾端延遲卻明顯變差,只能說明該負載下存在吞吐量與等待時間之間的取捨。不要直接將這個設定套用到資料庫連線池。

四、一起判讀吞吐量、IOPS 與尾端延遲

IOPS 是每秒完成的 I/O 次數。區塊大小固定時,IOPS 與吞吐量有對應關係;不同區塊大小的結果,不能只按 IOPS 排名。fio JSON 中的 bw 通常以 KiB/s 表示,讀取時應核對版本與欄位單位。

重點查看 read 或 write 內的 iops、頻寬欄位,以及 clat_ns 的平均值與百分位數。完成延遲不完全等於應用程式端的回應時間,應用程式的排隊與處理時間並不包含在這條測量路徑中。

P99 表示約九成九請求的延遲不超過該值,不是最大延遲。平均值相近但 P99 上升,可能意味著少量請求出現較長的等待時間;必須配合實際佇列深度與重複測試來判斷。

驗收紀錄至少應包含:

也要查看 fio 的實際 I/O 深度分布。設定為 8 不代表執行期間一直達到該深度;若引擎或檔案系統的行為不同,即使名義參數相同,結果也未必能直接比較。

五、透過重測、封存與清理完成驗收流程

每種負載都應重複執行,使用不同的輸出檔名,不要覆蓋前一次結果。比較波動範圍,而不是挑選最高數字。擴大測試檔案或延長測試時間前,應重新檢查空間,並確認增加的寫入量與資源競爭。

若要分別驗收兩顆磁碟,應選擇各自檔案系統中的目錄,再以相同參數依序測試。如果目錄實際位於同一個磁碟區,換個目錄並不能算是第二顆磁碟的獨立驗收。

讀寫測試若出現錯誤,先保留原始輸出與核心相關紀錄,再排查檔案系統及裝置連接路徑。若沒有錯誤但結果波動較大,先排除同機工作與測試條件變化,不要立即認定為硬體異常。

完成後,將 JSON、掛載資訊與命令紀錄複製到受控的封存位置。確認封存資料可讀取,再核對測試目錄,並僅刪除本次產生的檔案:

printf '%s\n' "$TESTDIR"
ls -lh -- "$TESTDIR"
rm -- "$TESTDIR/test.bin"

確認其餘結果檔案已封存後,再逐一清理;目錄清空後以 rmdir 刪除,不要對裝置掛載點使用遞迴刪除。最終結論應寫成「在這些參數與負載條件下得到這些結果」,而不是「這顆磁碟始終能達到某個速度」。檔案級基準測試用來找出明顯偏差;應用程式上線前,仍須以真實讀寫模式驗收。

常見問題

檔案級 fio 測試完全不會影響正式服務嗎?

不會覆寫既有檔案不代表沒有影響。測試仍會競爭磁碟、CPU 與檔案系統資源,應優先在服務上線前執行;已有負載時,必須先評估競爭情況並設定停止條件。

direct=1 能避開所有快取並代表資料庫提交效能嗎?

不能。direct=1 通常使用直接 I/O 避開檔案資料的頁面快取,但不會避開全部裝置快取,也不等同於資料庫持久化提交。交易落盤仍需搭配應用程式與同步寫入語意驗收。

EPYC 7543P 獨享實體主機,每月 $454 起

實體主機整機月租

結帳前可核對所選規格與本期應付金額,所有價格均以美元結算。