March 11Mar 11 系統資源限制調校 Part 2 ************************************************** 之前Debian 13配置時,已做了 Part 1 現在LNMP設置完,接續 Part 2 ************************************************** 前提:已完成 Part 1(基礎系統調校),LNMP 各服務已安裝並能正常啟動 目標環境:Debian 13 VPS規格:2 vCPU/2GB RAM 服務組合:MariaDB + Nginx + PHP-FPM 8.3 -------------------------- 架構概念與調校邊界 -------------------------- 為什麼需要兩層調校? Linux的資源限制分為兩個獨立層次,兩者必須同時設定,缺一不可 層次:核心層(全域) 設定位置:/etc/sysctl.d/*.conf 控制範圍:整個作業系統的上限,是所有服務的天花板 層次:服務層(行程) 設定位置:systemd override.conf 控制範圍:單一服務的資源配額,不得超過核心層上限 常見誤區:只設定 /etc/security/limits.conf 對 systemd 管理的服務完全無效 MariaDB、Nginx、PHP-FPM 均由 systemd 啟動,行程資源限制必須透過各自的 override.conf 設定 systemd Override 機制說明 不直接修改套件提供的 .service 檔案,而是使用 override 目錄,原因如下: 套件更新時,系統不會覆蓋 override 目錄下的自訂設定 原始 .service 檔案仍保持乾淨,升級後可直接 diff 比較差異 systemd 讀取設定的優先順序 /etc/systemd/system/<service>.service.d/*.conf 優先於 /lib/systemd/system/<service>.service override 檔案的設定會「疊加」而非全部取代原始設定 若需清空某個原始的清單型參數(例如 ExecStartPre),必須先以空值重置,再寫入新值 ExecStartPre= ExecStartPre=/your/new/command ---------------------------------------- 全域核心 sysctl 調校 ---------------------------------------- 為什麼使用獨立設定檔? 直接修改 /etc/sysctl.conf 有兩個風險:套件更新可能覆蓋它,且難以追蹤哪些設定從何而來 Debian 支援將獨立設定檔放置於 /etc/sysctl.d/ 目錄,是生產環境的最佳實踐 常見錯誤:將所有 sysctl 設定堆進 /etc/sysctl.conf,升級或排查問題時難以管理建立 專用設定檔vi /etc/sysctl.d/99-lnmp-optimization.conf貼上以下內容99-lnmp-optimization.conf.txt儲存檔案並離開vi編輯器按 Esc,輸入 :wq,按 Enter ---------------------------- 立即生效 ---------------------------- 立即生效 sysctl --system ------------------------- 驗證是否已套用 ------------------------- 預期輸出 fs.file-max = 2097152 sysctl fs.file-max 預期輸出:fs.nr_open = 2097152 sysctl fs.nr_open ------------------------------------------ 服務級別限制調校 systemd Override ------------------------------------------ 以下設定以 2 vCPU / 2GB RAM VPS 為基準 請務必依實際監控數據進行微調,勿照單全收 ---------------------- MariaDB 資料庫 ---------------------- 建立目錄 mkdir -p /etc/systemd/system/mariadb.service.d/編輯vi /etc/systemd/system/mariadb.service.d/override.conf貼入以下內容(檔案內已有部分設定,此為額外補充)mariadb.service.d---override.conf.txt儲存檔案並離開vi編輯器按 Esc,輸入 :wq,按 Enter----------------------- Nginx 網頁伺服器 ----------------------- 建立目錄 mkdir -p /etc/systemd/system/nginx.service.d/ 編輯vi /etc/systemd/system/nginx.service.d/override.conf貼上以下內容nginx.service.d---override.conf.txt儲存檔案並離開vi編輯器按 Esc,輸入 :wq,按 Enter------------------------ PHP-FPM ------------------------ 注意:PHP-FPM 的套件預設 .service 檔案通常已包含部分安全設定。 此 override 為額外疊加,不會覆蓋原有設定。 若有重複的鍵值,override 的值會優先生效。 建議執行 systemctl cat php8.3-fpm 先查看原始設定,確認無衝突。 建立目錄 mkdir -p /etc/systemd/system/php8.3-fpm.service.d/編輯vi /etc/systemd/system/php8.3-fpm.service.d/override.conf貼上以下內容php8.3-fpm.service.d---override.conf.txt儲存檔案並離開vi編輯器按 Esc,輸入 :wq,按 Enter ------------------------ 套用、驗證與監控 ------------------------ 完成所有 override.conf 後,必須依序執行 以下步驟: ---------------------------- 重新載入 systemd 配置 ---------------------------- 此步驟讓 systemd 讀取新增或修改的 override 檔案。每次修改 override.conf 後都必須執行,否則設定不會生效 重新載入 systemctl daemon-reload -------------------------- 重啟並驗證各服務 -------------------------- 在重啟服務前,建議先驗證設定語法,確認無誤後再啟動,避免生產環境服務中斷。 ------------------------------- MariaDB ------------------------------- 停止服務 後驗證 systemctl stop mariadb MariaDB 驗證設定語法 mariadbd --help --verbose > /dev/null 輸出說明: 無任何輸出 → 設定檔完全正確,可以啟動服務 顯示 [Warning] → 有警告,需確認是否影響運作 顯示 [ERROR] → 有錯誤,不可啟動服務,須先修正 確認無誤後再啟動 systemctl restart mariadb 查看狀態 systemctl status mariadb ------------------------------------ Nginx ------------------------------------ Nginx 驗證設定語法 nginx -t 重啟服務 systemctl restart nginx 查看狀態 systemctl status nginx -------------------------------- PHP-FPM -------------------------------- PHP-FPM 驗證設定語法 php-fpm8.3 -t 重啟服務 systemctl restart php8.3-fpm 查看狀態 systemctl status php8.3-fpm -------------------------------- 驗證資源限制是否真正生效 -------------------------------- 查看 /proc/<PID>/limits 才是確認設定是否真正生效的唯一標準,不應只看設定檔本身 驗證各服務的 Max open files 應顯示為 65535 MariaDB 應顯示為 65535 cat /proc/$(pgrep -o mariadbd)/limits | grep "Max open files" Nginx (取 master process PID) 應顯示為 65535 cat /proc/$(pgrep -o nginx)/limits | grep "Max open files" PHP-FPM (取 master process PID) 應顯示為 65535 cat /proc/$(pgrep -o php-fpm)/limits | grep "Max open files" ---------------------------------------- 使用 systemd 指令查看詳細屬性 ---------------------------------------- systemctl show mariadb | grep -E "(LimitNOFILE|MemoryMax|CPUQuota)" systemctl show nginx | grep -E "(LimitNOFILE|MemoryMax|CPUQuota)" systemctl show php8.3-fpm | grep -E "(LimitNOFILE|MemoryMax|CPUQuota)" ------------------------------------ 查看核心檔案描述符使用狀況 ------------------------------------ 查看 cat /proc/sys/fs/file-nr 輸出格式:已使用數 未使用數 最大值 ------------------ 安裝監控工具 ------------------ 安裝監控工具 apt update -y && apt install -y htop iotop iftop nethogs lsof sysstat 即時查看 CPU / 記憶體 htop 監控磁碟 I/O(按 o 排序) iotop 即時網路流量(需指定網卡,如 eth0) iftop -i eth0 依行程分類網路流量 nethogs eth0 計算特定行程目前開啟的檔案數 lsof -p <PID> | wc -l 查看 nginx master process 開啟了多少檔案 lsof -p $(pgrep -o nginx) 2>/dev/null | wc -l 歷史效能數據收集 sysstat 進階建議:生產環境應考慮部署 Prometheus + node_exporter 或 Netdata,實現長期監控與告警,而非僅依賴即時工具 ---------------------------- 重開機驗證 ---------------------------- 重開機 reboot 重開機後,確認各服務自動啟動且資源限制仍正確套用 確認服務狀態,每個服務都應顯示 active (running) systemctl status mariadb systemctl status nginx systemctl status php8.3-fpm 重新驗證資源限制(值應為 65535) cat /proc/$(pgrep -o mariadbd)/limits | grep "Max open files" cat /proc/$(pgrep -o nginx)/limits | grep "Max open files" cat /proc/$(pgrep -o php-fpm)/limits | grep "Max open files" 查看 systemd 實際讀取結果(確認 override 有被載入) systemctl cat mariadb systemctl cat nginx systemctl cat php8.3-fpm 查看 MemoryMax systemctl show mariadb | grep MemoryMax ------------------------------------------ VPS 2 vCPU/2GB RAM 記憶體配置建議 ------------------------------------------ MariaDB 1024 MB 記憶體大戶,innodb_buffer_pool_size 建議 768M PHP-FPM 768 MB 依 worker 數量與 memory_limit 決定 Nginx 256 MB 極低,事件驅動架構 Redis 128 MB 用於 Session 或頁面快取 系統及其他 約 384 MB OS 核心、SSH、Cron 等 合計 約 2560 MB 重要提醒:systemd 的 MemoryMax 設定值總和可以略高於實體記憶體(因為服務不會同時達到尖峰), 但若所有服務同時達到峰值,仍可能觸發 OOM Killer 強制終止行程。請務必根據實際監控數據進行微調。 建議執行壓力測試(如 ApacheBench、wrk)後,觀察 free -h 與 vmstat 1 30 的輸出,再決定最終配置。 --------------- 常見問題 --------------- Q1:修改了 /etc/security/limits.conf,重啟 MariaDB 後查看 /proc/<PID>/limits 仍未改變? 因為 MariaDB 由 systemd 管理,啟動時不會讀取 limits.conf 必須在對應的 systemd override.conf 中設定 LimitNOFILE,並在修改後執行 systemctl daemon-reload 再重啟服務 Q2:如何快速確認系統或特定服務開啟了多少檔案? 系統整體(已使用 / 未使用 / 總上限) cat /proc/sys/fs/file-nr 特定服務(以 nginx master process 為例) lsof -p $(pgrep -o nginx) 2>/dev/null | wc -l Q3:修改 systemd override 並 daemon-reload 重啟後,服務無法啟動? 查看詳細錯誤日誌 journalctl -u mariadb -xe --no-pager 確認服務狀態 systemctl status mariadb 驗證 systemd 讀取到的限制值 systemctl show mariadb | grep -i "limitnofile\|memory" 常見原因: override.conf 語法錯誤(如多餘空格、缺少區段標頭 [Service]) 設定了不支援的參數名稱 MemoryMax 設定過小,服務啟動即因超限被終止 ProtectSystem=full 與服務寫入路徑衝突(改用 ProtectSystem=strict + ReadWritePaths=) MemoryDenyWriteExecute=true 與 OPcache JIT 衝突(PHP-FPM) Q4:CPUQuota 的百分比是相對於什麼? CPUQuota=80% 表示允許使用最多 80% 的 單顆CPU核心 時間。 若 VPS 有2顆 vCPU,則 CPUQuota=160% 才等於充分利用兩顆核心。 請依 VPS 實際核心數調整。 Q5:MemoryMax 和 MemoryHigh 有什麼差別? 參數:MemoryHigh 行為:軟性高水位。超過後系統積極嘗試回收該服務記憶體,但 不會 強制終止服務 參數:MemoryMax 行為:絕對硬上限。超過後行程會被 OOM Killer 立即終止 建議將 MemoryHigh 設為 MemoryMax 的 80~85%,讓系統有空間提前介入,避免直接觸發 OOM Q6:MariaDB 無法啟動 查看最近 50 行錯誤日誌 journalctl -u mariadb -n 50 驗證設定檔語法 mariadbd --help --verbose > /dev/null 若調整 innodb_log_file_size 後發生錯誤,刪除舊 redo log 讓 MariaDB 重建 systemctl stop mariadb rm /var/lib/mysql/ib_logfile* systemctl start mariadb 檢查資料目錄權限 ls -la /var/lib/mysql chown -R mariadb:mariadb /var/lib/mysql Q7:Too many connections 錯誤 暫時調高連線數(立即生效,重啟後失效) mariadb -e "SET GLOBAL max_connections = 150;" 查看目前連線狀況 mariadb -e "SHOW PROCESSLIST;" 終止閒置過久的連線 mariadb -e "SHOW PROCESSLIST;" | grep Sleep | awk '{print "KILL "$1";"}' | mariadb 永久調整請修改 /etc/mysql/mariadb.conf.d/50-server.cnf 中的 max_connections 後重啟服務 提示:應用端建議實作連線池(如 PHP PDO persistent connection),可大幅降低連線開銷 Q8:磁碟空間持續增加 檢查磁碟使用 df -h du -sh /var/lib/mysql/ 檢查 Binary Log 使用狀況 mariadb -e "SHOW BINARY LOGS;" 手動清除 7 天前的 Binary Log mariadb -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);" 檢查日誌大小 ls -lh /var/log/mysql/ 若完全不需要主從複製,可在 50-server.cnf 中將 log-bin 相關行全部註解掉 Q9:innodb_buffer_pool_size 設定後發生 OOM 檢查記憶體使用 free -h top -o %MEM 2GB 總記憶體建議 innodb_buffer_pool_size = 768M,並為系統及其他服務保留至少 512 MB。 若系統頻繁使用 Swap,應考慮升級記憶體或降低 buffer pool 大小。 Q10:設定檔改了但未生效 顯示目前生效的所有設定 mariadbd --print-defaults 改為這樣,比較好讀 mariadbd --print-defaults 2>/dev/null | tr ' ' '\n' | grep '^--' 找出所有載入的設定檔路徑 mariadbd --help --verbose 2>/dev/null | grep -A 1 "Default options" 確認特定參數值 mariadb -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';" 重新載入並重啟 systemctl daemon-reload systemctl restart mariadb Q11:PHP-FPM 啟動後 worker 被 OOM Killer 終止 查看 OOM Killer 記錄 dmesg | grep -i "oom\|killed" journalctl -k | grep -i "oom\|killed" 調整策略: 1. 降低 pm.max_children(PHP-FPM pool 設定) 2. 降低 php.ini 的 memory_limit(如 128M → 96M) 3. 提高 systemd MemoryMax(前提是整體記憶體配置允許) Q12:如何確認 override.conf 的設定有被正確讀取(而非使用舊設定)? 查看 systemd 實際讀取到的完整設定(含 override 疊加後的結果) systemctl cat mariadb systemctl cat nginx systemctl cat php8.3-fpm 輸出最後一段即為你的 override.conf 內容,確認存在且數值正確即可 Edited July 15Jul 15 by Jack
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.