APCu (Alternative PHP Cache - User Cache) 是 APC 移除 opcode 緩存後的用戶數據緩存分支。專注於進程內共享內存鍵值存儲,適合單機、多進程(PHP-FPM worker)場景。不支援分佈式,集群環境請用 Redis/Memcached。
# PHP 7+ pecl install apcu # PHP 8+ pecl install apcu-5.1.22 # 指定兼容版本 # 編輯 php.ini extension=apcu.so apc.enabled=1 apc.shm_size=128M # 共享內存大小,根據業務調整 apc.ttl=3600 # 條目默認 TTL(秒),0=永不過期 apc.gc_ttl=3600 # 垃圾回收間隔 apc.entries_hint=10000 # 預估條目數,優化哈希表大小 apc.serializer=php # 序列化器:php/igbinary/msgpack apc.enable_cli=1 # CLI 模式啟用(調試用)
php_apcu.dll(官方發布頁)。ext/ 目錄,php.ini 添加 extension=apcu,配置同 Linux。php -m | grep apcu php -r "var_dump(apcu_cache_info());"
| 函數 | 說明 | 返回值 |
|---|---|---|
| apcu_store($key, $var, $ttl=0) | 存儲(覆蓋) | bool |
| apcu_fetch($key, &$success=null) | 獲取,$success 區分「不存在」與「存儲 false」 | mixed |
| apcu_delete($key) | 刪除 | bool |
| apcu_exists($key) | 檢查存在 | bool |
| apcu_inc($key, $step=1, &$success=null) | 原子遞增(整數) | int|false |
| apcu_dec($key, $step=1, &$success=null) | 原子遞減 | int|false |
| apcu_cas($key, $old, $new) | 比較並交換(樂觀鎖) | bool |
| apcu_clear_cache() | 清空所有緩存 | bool |
| apcu_cache_info() | 獲取緩存統計(命中率、內存使用、條目數) | array |
| apcu_key_info($key) | 單條目信息(創建時間、訪問時間、TTL) | array|false |
<?php
namespace App\Cache;
use Psr\SimpleCache\CacheInterface;
class ApcuCache implements CacheInterface {
public function get($key, $default = null) {
$val = apcu_fetch($this->prefixKey($key), $success);
return $success ? $val : $default;
}
public function set($key, $value, $ttl = null): bool {
return apcu_store($this->prefixKey($key), $value, $ttl ?? 0);
}
public function delete($key): bool {
return apcu_delete($this->prefixKey($key));
}
public function clear(): bool {
return apcu_clear_cache();
}
public function has($key): bool {
return apcu_exists($this->prefixKey($key));
}
// ... 實現 getMultiple, setMultiple, deleteMultiple
private function prefixKey(string $key): string {
return 'app:' . $key; // 防止鍵衝突
}
}
apcu_cache_info()['mem_size'] 與 'num_entries',保持內存使用率 < 80%。igbinary 或 msgpack 擴展,序列化速度提升 2-5 倍、體積縮小 30-50%。官方提供 apc.php(解壓安裝包或從 GitHub 獲取),配置用戶名密碼後部署,可視化查看:
| 坑點 | 現象 | 解決 |
|---|---|---|
| 跨進程不共享 | CLI 寫入,FPM 讀不到 | APCu 僅共享於同一主進程派生的子進程(如 PHP-FPM pool)。CLI 獨立進程不可用。 |
| 緩存穿透/雪崩 | Key 失效瞬間大量請求擊穿 DB | 互斥鎖重建(apcu_cas 實現分佈式鎖)、隨機 TTL、預熱。 |
| 存儲大對象導致內存碎片 | shm 碎片率高、分配失敗 | 大對象拆分、壓縮序列化、遷移至 Redis。 |
| TTL=0 導致無法自動清理 | 內存耗盡、OOM | 設置合理 TTL、定時腳本調用 apcu_clear_cache() 或遍歷刪除過期 Key。 |
| 序列化器不一致 | 多機器/多池數據讀取失敗 | 統一 apc.serializer 配置,或手動 igbinary_serialize/unserialize。 |