Linux I/O Scheduler Tuning: mq-deadline, none, BFQ
16 分鐘閱讀 - 2026年6月1日

如何針對 NVMe、SATA 和 HDD 工作負載挑選和調整正確的 Linux I/O 排程器,並提供 sysfs 指令、udev 規則和 fio 基準測試步驟。
Linux I/O 調度器調校:mq-deadline、none 及 BFQ
Linux I/O 調度器決定讀取與寫入請求傳送至儲存裝置的順序,而正確的選擇幾乎完全取決於您的硬體。請使用 none 適用於 NVMe, mq-deadline 適用於執行混合工作負載的 SATA SSD 和 HDD,以及 bfq 當您需要防止某個程序佔用過多資源而導致其他程序資源匱乏時。本指南涵蓋這三種主要調度器的運作原理、如何根據工作負載選擇合適的調度器,以及如何進行調校與驗證結果。
若您希望在閱讀前先進行實作操作,這段影片將介紹如何透過終端機切換及測試排程器的基礎知識。
mq-deadline、none 與 BFQ 的差異
每種排程器處理請求的策略各不相同。了解它們之間的差異,才能讓您有意識地做出選擇,而非僅是接受系統開機時內核所選用的預設設定。
mq-deadline
該 mq-deadline 此排程器確保沒有任何請求會無限期等待。它為讀取和寫入分別維護獨立的排序佇列,並根據邏輯區塊位址 (LBA) 進行排序以縮短尋道時間,同時強制執行時限:預設讀取為 500 毫秒,寫入為 5 秒。當請求達到其時限時,該請求會跳至佇列最前端。
讀取請求優先於寫入請求,因為讀取通常會阻塞應用程式,而寫入則是異步處理的。為了避免寫入請求完全被飢餓,調度器會在處理完設定數量的讀取請求後,處理一批逾期的寫入請求。其結果是能維持一致的低延遲,這使得它非常適合資料庫伺服器以及任何混合了讀取與寫入的工作負載。
無
該 none 排程器幾乎不做任何處理。它會按照先入先出(FIFO)的順序將請求直接傳遞給裝置,不進行任何重新排序、合併或優先級設定。這非常適合現代 NVMe 硬碟,因為它們能自行管理內部佇列,並能同時追蹤數萬個正在處理中的請求。移除軟體排程層,能提供從應用程式到裝置的最短路徑,這正是高吞吐量 NVMe 工作負載所需要的。
但問題在於,這僅在硬體能自行進行智慧調度時才有效。對於硬碟(HDD)或具淺層佇列的 SATA SSD,跳過軟體重新排序通常會導致效能變差,而非變好。
BFQ
BFQ(預算公平排隊)將公平性置於首位。它不採用時間片段機制,而是為每個進程分配以磁碟區為單位的預算。大型連續讀取作業會獲得較大的預算以維持吞吐量,而對延遲敏感的任務則獲得較小的預算,以便迅速獲得服務;同時,一個回饋迴路會在運行過程中動態調整這些預算。
即使在高負載下,BFQ 也能確保互動式任務保持響應性,因此即使在背景執行大型檔案傳輸時,影片播放或資料庫查詢仍能保持流暢。這種公平性需以 CPU 資源為代價。其每請求的開銷約為 1.9 微秒,約為 mq-deadline 的三倍;在較慢的 ARM 核心上,該開銷會使吞吐量遠低於相同排程器在快速 x86 晶片上所能達到的水準。 在最重視原始吞吐量與 CPU 效率的伺服器上,這種取捨很難被合理化。
| 調度器 | 演算法 | CPU 開銷 | 最佳硬體 | 主要目標 |
|---|---|---|---|---|
mq-deadline | 帶有截止時間的排序 LBA | 低(約 0.7 微秒/請求) | SATA SSD、HDD、虛擬磁碟 | 可預測的低延遲 |
none | FIFO,無重新排序 | 可忽略不計 | NVMe SSD | 最大吞吐量 |
bfq | 比例分配資源 | 中等(約 1.9 微秒/請求) | HDD、共用及桌上型系統 | 公平性與響應速度 |
根據工作負載選擇合適的排程器
選擇合適調度器的關鍵在於兩點:您的儲存硬體與應用程式的存取模式。首先從硬體著手。若裝置本身已具備請求重新排序功能(例如配備相應韌體的 NVMe 硬碟),軟體調度只會增加額外開銷,因此 none 勝出。在尋道時間佔主導地位的機械硬碟上,軟體重新排序可降低延遲,因此 mq-deadline 或 bfq 是較佳的選擇。SATA SSD 則介於兩者之間:速度雖快於 HDD,但缺乏 NVMe 的深度佇列,這正是 mq-deadline 便適用於此。
當已有其他機制為您進行調度時,同樣的邏輯也適用。運行於 virtio-blk 上的虛擬機器依賴主機來調度 I/O,而具備寫回快取的硬體 RAID 控制器則會自行優化順序。在這兩種情況下 none 皆可避免重複處理相同工作。
存取模式是第二個考量因素。每秒執行數千次 4K 隨機讀取的資料庫,與從 NVMe 陣列串流大量連續區塊的訓練工作完全不同,因此需要不同的排程器。下表將常見工作負載對應至起點。
| 工作負載 | 儲存 | 排程器 | 原因 |
|---|---|---|---|
| AI/ML 訓練 | NVMe SSD | none | 高順序吞吐量;韌體負責排程 |
| OLTP 資料庫 | NVMe SSD | none | 低延遲隨機 I/O;避免軟體開銷 |
| OLTP 資料庫 | SATA SSD | mq-deadline | 防止寫入飢餓;尾部延遲可預測 |
| 資料倉儲 / OLAP | NVMe / 高速 SSD | none | 深度並行佇列;最大吞吐量 |
| 一般網頁託管 | SATA SSD / HDD | mq-deadline | 混合小檔案 I/O 的穩定響應 |
| 共享 / 多租戶主機 | HDD / SSD | bfq | 租戶間的公平性;防止 I/O 壟斷 |
| 虛擬機器來賓 | virtio-blk | none | 主機已進行調度;雙重調度會浪費 CPU |
| 備份 / 歸檔 | HDD | mq-deadline | 具備飢餓防護的順序吞吐量 |
有一個例外情況值得特別指出。即使在 NVMe 上,若您關注的指標是 p99 或 p999 的尾部延遲(例如在金融系統中), mq-deadline 可以勝過 none 透過強制執行嚴格的截止時間並防止偶發的延遲請求。
變更與調整調度器參數
無論是切換排程器還是調整其參數,皆透過 sysfs 進行,且無需重新開機即可測試變更。
切換活躍排程器
檢查裝置可用的排程器清單,其中方括號內的值即為當前活躍的排程器:
cat /sys/block/sda/queue/scheduler在運行時切換至其他排程器。此變更會立即生效,但重啟後將失效:
echo bfq | sudo tee /sys/block/sda/queue/scheduler若 bfq 未列於清單中,請先載入模組:
sudo modprobe bfq若要使設定永久生效,請使用 udev 規則,而非舊式的 elevator= 核心參數,因為該參數在 RHEL 9 及類似版本中已不再能變更排程器。此規則會將 mq-deadline 設定 /etc/udev/rules.d/60-io-scheduler.rules:
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"無需重新開機即可重新載入並套用:
sudo udevadm control --reload-rules && sudo udevadm trigger在基於 RHEL 的系統上,TuneD 設定檔會透過全系統設定檔而非單一裝置規則來執行相同功能。
值得調整的參數
每個排程器皆將其可調整參數公開於 /sys/block/<device>/queue/iosched/下公開其可調參數。對於 mq-deadline而言,時限是主要的調整槓桿。位於 SATA SSD 上的延遲敏感型資料庫,若設定較短的時限將更為有利:
echo 100 | sudo tee /sys/block/sda/queue/iosched/read_expire
echo 1000 | sudo tee /sys/block/sda/queue/iosched/write_expire對於 bfq 在高吞吐量系統上,停用延遲啟發式演算法可提升吞吐量:
echo 0 | sudo tee /sys/block/sda/queue/iosched/low_latency
echo 0 | sudo tee /sys/block/sda/queue/iosched/slice_idle| 調度器 | 參數 | 預設 | 調校目標 |
|---|---|---|---|
mq-deadline | read_expire | 500 毫秒 | 降低此值可加快讀取反應 |
mq-deadline | write_expire | 5000 毫秒 | 調低此值可減少寫入延遲 |
mq-deadline | writes_starved | 3 | 若為讀取密集型負載,請調高此值 |
mq-deadline | fifo_batch | 16 | 設定為 1 以獲得最低延遲 |
bfq | low_latency | 1 | 設定為 0 以獲得最大吞吐量 |
bfq | slice_idle | 8 毫秒 | 若使用 SSD 或 RAID,請設定為 0 |
bfq | strict_guarantees | 0 | 若需嚴格的頻寬共享,請設定為 1 |
對於共享主機,BFQ 與 cgroups v2 搭配使用效果極佳。設定 io.weight 值,可讓您將資料庫程序的 I/O 配額設定為備份任務的十倍,例如,如此一來,背景作業便不會淹沒互動式流量。無論您進行何種變更,BFQ 較高的每請求成本在 CPU 受限且高 IOPS 的系統上會累積,因此請在正式啟用前進行效能測試。
調校後的效能驗證
在進行任何變更前,務必先建立基準數據。若無基準數據,便無法判斷調整是否有效。
fio 是執行此任務的標準工具。它透過區塊大小、佇列深度及 I/O 引擎設定,重現特定的工作負載模式。請務必傳入 --direct=1 參數,使其繞過頁面快取,直接測量排程器與裝置的效能,而非快取讀取。測試應與實際工作負載相符:
| 工作負載 | fio 參數 |
|---|---|
| OLTP 資料庫 | --rw=randread --bs=4k --iodepth=32 --direct=1 |
| 資料倉儲 | --rw=read --bs=1m --iodepth=32 --direct=1 |
| 預寫 / 重做日誌 | --rw=write --bs=4k --iodepth=1 --direct=1 |
| 物件儲存 | --rw=randrw --bs=64k --iodepth=64 --direct=1 |
在 iodepth 1 到 256 的數值範圍內執行相同的測試,以找出裝置的飽和點,即 IOPS 停止攀升且延遲飆升的深度。針對變更後的即時監控, iostat -x 1 彙整關鍵指標: r_await 以及 w_await 讀寫完成延遲, aqu-sz 表示平均佇列深度,以及 %util 代表裝置使用率。當 %util 值接近 100% 時,即表示硬體已達極限,此時無論如何調整排程器都無濟於事。
若要區分軟體成本與硬體成本,請搭配 btt 執行 blktrace。此工具會將延遲拆分為 Q2D(軟體佇列所耗費的時間)與 D2C(裝置處理請求所需的時間)。若 Q2D 佔主導地位,則排程器是您的瓶頸;若 D2C 佔主導地位,則瓶頸在於硬體。
解讀結果時需注意一點:調度程式的選擇主要影響延遲分佈的尾部,而非中位數。從 none 切換至 mq-deadline ,可能會使中位數延遲增加幾微秒,但同時將 p99 和 p999 延遲減半。對於受 SLA 約束的用戶端服務而言,這種取捨幾乎總是值得的,這正是為何測量尾部延遲(而非平均吞吐量)才是此項工作的重點。
選擇合適的排程器
調校排程器旨在將演算法與硬體及存取模式相匹配,並透過量測驗證其成效。簡而言之:
- NVMe:使用
none並讓韌體負責排程。 - 混合 I/O 的 SATA SSD 和 HDD:使用
mq-deadline以獲得可預測的延遲。 - 共用或多租戶主機:使用
bfq以防止單一工作負載壟斷資源,導致其他工作負載受限。 - 監測尾部延遲而非中位數:調度器變動會反映在 p99 和 p999 指標上,因此應以此為衡量標準。
- 確保設定持久化:使用 udev 規則或 TuneD,切勿使用已廢棄的
elevator=參數。
要充分發揮任何排程器的效能,首先需要能跟上需求的硬體。若您需要專為高吞吐量、低延遲工作負載打造的 NVMe 後端伺服器,歡迎探索 FDC 的 VPS 方案。
Linux 記憶體管理:交換、OOM 殺手與 Cgroups
12 分鐘閱讀 - 2026年5月31日