使用 Ubuntu cgroups 限制指令的 CPU 和記憶體使用量

如果某個指令導致您的 Ubuntu 桌面運作緩慢或伺服器記憶體不足,請將該指令及其子程序放入由 systemd 管理的 cgroup 中,並設定 CPU 配額和記憶體上限。在目前的 Ubuntu 版本中,systemd-run --scope這是最方便的方案:它會在臨時作用域中啟動該命令,然後 systemd 透過 cgroup 控制來套用這些限制。

以下範例將工作負載限制為單一 CPU 效能的一半和 1 GiB 記憶體。這些限制適用於整個範圍,包括子進程;它們並不保證程式將以特定速度運行。

為什麼進程需要 cgroup 限制

繁忙的進程可能會與互動式應用程式爭用資源,而佔用大量記憶體的進程則可能導致機器進入記憶體回收或記憶體不足狀態。 cgroup 將進程及其子進程分組,以便核心可以管理並約束該群組進程。 Ubuntu 的 systemd 提供了一個方便的介面來控制這些進程。

CPU 和記憶體設定的行為有所不同。 `cgroup.memory`CPUQuota=50%將 CPU 時間限制為單一 CPU 容量的一半,並按調度週期進行平均。 `cgroup.memory` 的值200%表示最多可以使用兩個 CPU 的可用時間。這是一個上限,而不是 CPU 優先權或預留。 `cgroup.memory`MemoryMax=1G為分配給 cgroup 的記憶體設定硬性上限;如果工作負載無法保持在該上限以下,核心可能會回收記憶體或對該 cgroup 中的進程執行記憶體不足終止操作。選擇一個足以滿足應用程式及其子進程需求的上限值。

1. 檢查 Ubuntu 是否正在使用 cgroup v2

使用 systemd 的 Ubuntu 系統通常採用統一的 cgroup v2 層級結構。在依賴後續顯示的路徑之前,請確認目前配置是否正確:

stat -fc %T /sys/fs/cgroup
systemctl --version | head -n 1

第一個命令應該會報告cgroup2fs檔案系統類型。如果它報告的是其他檔案系統類型,則本文中提供的 cgroup v2 檔案路徑將不再適用。 systemd 屬性可能仍然受支持,但請使用相應的發行版文檔,而不是直接複製 v2 路徑。

如果某個屬性被拒絕,也要檢查 systemd 的確切版本。 Ubuntu 的 Noble 文件將CPUQuota=其描述MemoryMax=為資源控制設定;較舊的 Ubuntu 版本可能打包了不同版本的 systemd。

2. 在有限的範圍內開始工作。

透過運行程序systemd-run,替換為實際的可執行檔及其參數。對於目前目錄中的命令,請使用./並傳遞所有參數--:

systemd-run --scope \
  -p CPUQuota=50% \
  -p MemoryMax=1G \
  -- ./my-program --input data.csv
Ubuntu 終端機運行 systemd-run,CPU 配額設定為 50%,記憶體最大設定為 1G,用於執行指令
在具有 CPU 和記憶體限制的瞬態 systemd 作用域內啟動命令。

對於使用者擁有的命令,請先嘗試不執行該命令sudo。如果 systemd 報告請求的控制器或屬性不可用,則可能是使用者管理員沒有權限委派該控制器或屬性;對於系統級工作負載,以 root 使用者身分重試可能合適,但這會改變命令的安全上下文。切勿隨意以 root 使用者身分執行不受信任的程式。如果必須以 root 使用者身分使用系統管理器,請sudo systemd-run --scope ...務必在考慮此變更後再使用。

命令運作時,終端機會一直連接到示波器。按下按鈕Ctrl+C會中斷前台操作。示波器是臨時的,通常會在進程退出後消失。這是一種在限制條件下啟動命令的便捷方式,而不是為未來的啟動設定持久策略。

3. 確定範圍並檢查其限制

systemd-run列印它所建立的單元名稱,通常類似於run-….scope。命令仍在運行時,列出 cgroup 樹:

systemd-cgls

找到瞬態作用域,並確認目標程式及其子程式都位於其下方。這一點很重要,因為在作用域之外運行的子程式將不受相同的 cgroup 上限的保護。

終端機 cgroup 樹顯示了一個瞬態運行範圍,其中包含一個程式和兩個工作進程。
使用 cgroup 樹確認程式及其工作進程是否分組在瞬態作用域下。

在下一個指令中使用列印出的作用域名稱。將 `<scope name>` 替換run-abc.scope為實際名稱:

systemctl show run-abc.scope \
  -p ControlGroup -p CPUQuotaPerSecUSec -p MemoryMax

CPUQuotaPerSecUSec=50000當 systemd 的配額週期為 100 毫秒時,這與 50% 的配額一致;MemoryMax=1073741824大小為 1 GiB 位元組。即時值比假設每個主機都會原封不動地接受每個請求更有用,因為父 cgroup 和可用控制器可能會限制實際結果。

systemctl 顯示瞬態範圍內的控制組、CPU 配額和記憶體最大值的輸出
檢查範圍報告的控制組以及配置的 CPU 和記憶體上限。

4. 驗證內核 cgroup 檔案並進行安全調整

此ControlGroup屬性提供相對於目前位置的 cgroup 路徑/sys/fs/cgroup。將其儲存在 shell 變數中,以便命令遵循電腦上實際分配的路徑:

UNIT=run-abc.scope
CG=$(systemctl show "$UNIT" -p ControlGroup --value)
printf 'Group: %s\n' "$CG"
cat "/sys/fs/cgroup$CG/cpu.max"
cat "/sys/fs/cgroup$CG/memory.max"

cgroup v2 中cpu.max包含以微秒為單位的配額和週期。例如,50000 100000表示每 100 毫秒週期內分配 50 毫秒的 CPU 時間。memory.max顯示以位元組為單位的記憶體上限。如果檔案缺失,請確認作用域是否仍然有效,以及核心是否正在使用 cgroup v2。

終端機正在讀取 sysfs cgroup v2 下 systemd 作用域中的 cpu.max 和 memory.max 值
讀取核心的 cgroup v2 文件,以驗證配置的配額和記憶體上限。

如果您啟動了一個已命名的長時間運行單元,並且需要調整其限制,systemd 支援更改活動單元的資源屬性,例如 `systemd.configure("username")` sudo systemctl set-property --runtime my-worker.service CPUQuota=50% MemoryMax=1G。這適用於該服務的 cgroup,並且需要相應的權限。 systemd 不會因為知道進程 ID (PID) 就附加任意已運行的進程;對於一次性進程,請將其正常停止,然後透過受限範圍重新啟動。對於持久性服務,請在服務單元或 systemd drop-in 中配置屬性,並在適當的維護視窗期間重新啟動它。

查看結果

檢查時請保持工作負載處於活動狀態。確認systemd-cgls進程及其子進程已置於預期的作用域內,已systemctl show報告請求的屬性,並且相應的cpu.maxcgroupmemory.max檔案存在且具有有限值。當進程退出時,瞬態作用域將被移除,因此其 cgroup 檔案可能會消失。

配額限制 CPU 時間,但不保證在桌面顯示器上顯示固定百分比,而硬性記憶體上限則可能導致應用程式運行失敗。如果工作負載變得不穩定,請停止該工作負載,並將限制提高到一個經過驗證的安全值,或使用更寬鬆的MemoryHigh=壓力閾值並配合更高的MemoryMax=記憶體使用率。有關具體行為,請查閱已安裝的 systemd 和核心文件;權威參考資料包括Ubuntu systemd-run 手冊、Ubuntu systemd resource-control 手冊和Linux 核心 cgroup v2 文件。

留下評論

如何轉換三相電壓、電流、千瓦 (kW)、千伏安 (kVA) 和功率因數

如何轉換三相電壓、電流、千瓦 (kW)、千伏安 (kVA) 和功率因數

學習平衡三相公式,並逐步轉換線電壓、電流、kW、kVA 和功率因數,並提供範例和檢查極限。

使用 Ubuntu cgroups 限制指令的 CPU 和記憶體使用量

使用 Ubuntu cgroups 限制指令的 CPU 和記憶體使用量

在 systemd 範圍內運行工作負載,並設定 CPUQuota 和 MemoryMax,然後透過 cgroup v2 驗證限制。

在 Ubuntu Server 24.04 上加密 Pi-hole 上游 DNS

在 Ubuntu Server 24.04 上加密 Pi-hole 上游 DNS

在 Ubuntu 24.04 上將 dnscrypt-proxy 設定為 Pi-hole 的本地 DoH 橋,設定僅限 localhost 的監聽器、解析器選擇以及切換 DNS 前的檢查。

讓 Ubuntu 24.04 在 Wayland 上啟用觸控板手勢

讓 Ubuntu 24.04 在 Wayland 上啟用觸控板手勢

在排查應用程式或硬體故障之前,請檢查 Ubuntu 的觸控板設定、確認 Wayland 以及測試 GNOME 的內建滑動功能。

使用 mdadm 建置 Debian 12 RAID 1 鏡像

使用 mdadm 建置 Debian 12 RAID 1 鏡像

建立並驗證一個雙磁碟 Debian 12 RAID 1 資料陣列,安全地格式化它,並配置它在重新啟動後組裝和掛載。

每次啟動時使用新金鑰加密 Debian 12 交換分割區。

每次啟動時使用新金鑰加密 Debian 12 交換分割區。

為現有的 Debian 12 交換分區設定隨機金鑰加密,驗證活動的 dm-crypt 映射,並了解休眠的權衡。

如何在 Ubuntu 24.04 上限制 SSH 使用者只能存取特定目錄(SFTP Chroot 指南)

如何在 Ubuntu 24.04 上限制 SSH 使用者只能存取特定目錄(SFTP Chroot 指南)

使用 chroot、適當的權限、匹配規則和安全測試,將 Ubuntu 24.04 SSH 帳戶限製到指定的 SFTP 資料夾,而不授予 shell 存取權限。

安全釋放 Ubuntu 的 APT 鎖定並完成更新

安全釋放 Ubuntu 的 APT 鎖定並完成更新

找到擁有 Ubuntu dpkg 前端鎖定的進程,讓軟體包工作完成,並在不刪除鎖定檔案的情況下修復中斷的安裝。

如何在 Ubuntu 桌面系統上設定 Btrfs 自動快照

如何在 Ubuntu 桌面系統上設定 Btrfs 自動快照

使用 Timeshift 在 Ubuntu Desktop 上設定定時 Btrfs 系統快照,驗證 Ubuntu 子磁碟區佈局,選擇保留策略,並了解快照無法保護的內容。

如何在不破壞依賴關係的情況下將 Debian 12 遷移到 Testing 版本

如何在不破壞依賴關係的情況下將 Debian 12 遷移到 Testing 版本

規劃更安全的 Debian 12 到 Testing 遷移:透過 Stable 版本升級,備份,清理 APT 來源,模擬依賴項更改,並驗證更改的內容。