PHP 預設使用檔案儲存 Session(session.save_handler = files),資料寫入 session.save_path 指定目錄(預設 /tmp 或 /var/lib/php/sessions),檔名為 sess_<session_id>。隨著流量增長,目錄下檔案數可能達數十萬甚至百萬,導致:
df -i 顯示 100% 使用率)session_start() 延遲明顯; php.ini session.gc_probability = 1 session.gc_divisor = 1000 ; 1/1000 機率觸發 session.gc_maxlifetime = 1440 ; 24 分鐘視為過期
gc_probability / gc_divisor 機率啟動 GC。save_path 下所有 sess_*,刪除 mtime > gc_maxlifetime 的檔案。save_path(非系統預設),系統 cron 不會自動清理,必須自行處理。在 php.ini 設定 N 階層:
session.save_path = "3;/var/lib/php/sessions"
16^3 = 4096 個子目錄(0-9, a-f),大幅降低單目錄檔案數。ext/session/save_path.php 腳本,或自行撰寫:#!/bin/bash
BASE="/var/lib/php/sessions"
for a in {0..9} {a..f}; do
for b in {0..9} {a..f}; do
for c in {0..9} {a..f}; do
mkdir -p "$BASE/$a/$b/$c"
done
done
done
chown -R www-data:www-data "$BASE"
chmod -R 1777 "$BASE"
將 Session 目錄掛載到記憶體,I/O 極快,重啟自動清空:
# /etc/fstab tmpfs /var/lib/php/sessions tmpfs defaults,size=512m,mode=1777 0 0
mount -a
| 方案 | 優點 | 缺點 |
|---|---|---|
| Redis | 高效能、支援叢集、資料結構豐富、可持久化 | 需額外維護 Redis 服務 |
| Memcached | 簡單、多節點自動分散 | 無持久化、重啟資料遺失、無備份機制 |
| MySQL/PostgreSQL | 統一備份、ACID、易查詢 | 寫入延遲較高、連線數壓力大 |
設定範例(Redis):
session.save_handler = redis session.save_path = "tcp://127.0.0.1:6379?auth=yourpass&database=0"
或使用 phpredis 擴充套件搭配 Symfony NativeSessionStorage 自訂儲存類別。
放入 crontab -e 每小時執行:
#!/bin/bash # 清理超過 gc_maxlifetime(秒)的空檔與過期檔 SAVE_PATH="/var/lib/php/sessions" MAX_LIFE=1440 # 需與 php.ini 一致 find "$SAVE_PATH" -type f -name 'sess_*' -cmin +$((MAX_LIFE/60)) -size 0 -delete find "$SAVE_PATH" -type f -name 'sess_*' -cmin +$((MAX_LIFE/60)) -delete
chmod 1777),防止他人刪除檔案。ls -1 /var/lib/php/sessions | wc -l 與 df -i,設定告警閾值。