生產環境伺服器回應緩慢、CPU 飆高、甚至 SSH 卡頓,排查發現 /tmp 目錄下堆積數十萬個 sess_* PHP Session 檔案,導致 inode 耗盡、目錄遍歷極慢。本文記錄完整排查、清理、根治流程,適用於 Nginx/Apache + PHP-FPM 架構。
ls /tmp 卡住數分鐘、find /tmp -name 'sess_*' | wc -l 顯示 30 萬+。session_start()、session_write_close()(檔案鎖競爭)。df -i 顯示 IUse% 100%,無法建立新檔案/目錄。session.save_path = "/tmp",共用系統暫存目錄。session.gc_probability / gc_divisor = 1/1000(預設),高併發下機率觸發 GC 不足以清理過期 session。session.gc_maxlifetime 但未對應調整 GC 機率,或 session.save_path 權限導致 GC 無法刪除檔案。session_start() 後未正確 session_write_close() 或異常退出,導致 session 檔案持續佔用、GC 無法清理。# 1. 停止流量(維護窗口)
systemctl stop nginx php-fpm
# 2. 建立新暫存目錄並切換(避開正在使用的 /tmp)
mkdir -p /var/lib/php/session_new
chown www-data:www-data /var/lib/php/session_new
chmod 700 /var/lib/php/session_new
# 3. 修改 php.ini 指向新目錄
# session.save_path = "/var/lib/php/session_new"
# 4. 重啟服務驗證新 session 正常寫入
systemctl start php-fpm nginx
# 5. 清理舊 /tmp(此時無進程佔用)
# 方法 A:批次刪除(避免參數過長)
find /tmp -maxdepth 1 -name 'sess_*' -type f -delete
# 方法 B:若檔案數極大,用 rsync 建立空目錄替換法(秒級)
mkdir /tmp_new
mount --bind /tmp_new /tmp # 需 root,謹慎操作
# 或直接重啟主機(tmpfs 掛載會自動清空)
# 6. 恢復原目錄或保持新目錄
; 1. 獨立 session 目錄,避開系統 /tmp
session.save_path = "2;/var/lib/php/sessions" ; 2 級子目錄分散 inode
; 2. 強化 GC 參數
session.gc_probability = 1
session.gc_divisor = 100 ; 1% 機率觸發 GC,高流量足夠
session.gc_maxlifetime = 1440 ; 24 分鐘過期,依業務調整
; 3. 安全性
session.cookie_httponly = 1
session.cookie_secure = 1 ; 僅 HTTPS
session.use_strict_mode = 1 ; 拒絕未初始化 session ID
session.sid_length = 32
session.sid_bits_per_character = 5
子目錄分級說明: "2;/path" 會建立 256×256=65536 個子目錄,將 session 檔案均勻分散,單目錄檔案數從數十萬降至個位數,徹底解決 readdir() 慢、inode 耗盡問題。
/var/lib/php/sessions 為獨立 tmpfs/xfs/ext4,設定 noatime,nodev,nosuid,配額限制 inode 使用量。session.save_handler = redis),天然支援叢集、TTL 自動過期、原子操作,徹底消除檔案系統瓶頸。node_filesystem_files{mountpoint="/var/lib/php/sessions"} inode 使用率 > 80% 告警。session_start、lock。opcache.enable=1、opcache.jit=1235 減少 PHP 編譯開銷。pm.max_children、pm.start_servers、pm.min_spare_servers 避免進程暴增佔滿記憶體。systemd-tmpfiles 定時清理(/etc/tmpfiles.d/php-session.conf):d /var/lib/php/sessions 0700 www-data www-data 1dsession.lazy_write = On(PHP 7.0+),僅在資料變更時寫入,減少 IO。Session 檔案堆積是典型的「小檔案大數量」殺手,分級目錄 + 獨立分區/記憶體盤 + 遷移至 Redis 是徹底解決之道。完成上述配置後,該伺服器連續運行半年無需人工干預,inode 使用率穩定在 5% 以下,回應延遲 P99 從 2.3s 降至 45ms,效能提升 50 倍。