Memcache 介紹
Memcache 是高效能分散式記憶體快取系統,廣泛用於減輕資料庫負載、加速頁面回應。PHP 透過 `memcache` 擴展(非 `memcached`)操作,提供基本的 Key-Value 存取、過期管理、壓縮、叢集支援。
完整操作類封裝
<?php
/**
* Memcache 封裝類
* 功能:連線管理、CRUD、壓縮、叢集、統計監控
* 需求:PHP memcache 擴展
*/
class MemcacheManager {
private $connection = null;
private array $servers = [];
private bool $connected = false;
// ==================== 連線管理 ====================
/**
* 連線單台伺服器
* @param string $host
* @param int $port
* @param int $timeout 連線逾時秒數
* @return bool
*/
public function connect(string $host, int $port = 11211, int $timeout = 1): bool {
if (!function_exists('memcache_connect')) {
trigger_error("memcache 擴展未安裝", E_USER_ERROR);
return false;
}
$this->connection = @memcache_connect($host, $port, $timeout);
if ($this->connection) {
$this->servers[] = ['host' => $host, 'port' => $port, 'weight' => 100];
$this->connected = true;
return true;
}
return false;
}
/**
* 加入叢集伺服器(需先 connect 主節點)
* @param string $host
* @param int $port
* @param bool $persistent
* @param int $weight 權重
* @param int $timeout
* @param int $retryInterval 重試間隔
* @param bool $status 伺服器狀態
* @return bool
*/
public function addServer(
string $host,
int $port = 11211,
bool $persistent = true,
int $weight = 100,
int $timeout = 1,
int $retryInterval = 15,
bool $status = true
): bool {
if (!$this->connected) return false;
return @memcache_add_server($this->connection, $host, $port, $persistent, $weight, $timeout, $retryInterval, $status);
}
/**
* 批次設定叢集
* @param array $servers [['host'=>'', 'port'=>11211, 'weight'=>100], ...]
*/
public function setServers(array $servers): bool {
if (!$this->connected) return false;
$serverList = [];
foreach ($servers as $s) {
$serverList[] = [
$s['host'],
$s['port'] ?? 11211,
true,
$s['weight'] ?? 100,
1, 15, true
];
}
return @memcache_set_servers($this->connection, $serverList);
}
public function close(): bool {
if ($this->connection) {
$result = @memcache_close($this->connection);
$this->connection = null;
$this->connected = false;
$this->servers = [];
return $result;
}
return false;
}
public function isConnected(): bool {
return $this->connected && $this->connection !== null;
}
// ==================== 基本快取操作 ====================
/**
* 設定快取
* @param string $key
* @param mixed $value 任意可序列化資料
* @param int $flags 壓縮旗標:0=無壓縮, MEMCACHE_COMPRESSED=壓縮
* @param int $expire 過期秒數(0=永不過期,>2592000 視為 Unix 時間戳)
* @return bool
*/
public function set(string $key, mixed $value, int $flags = 0, int $expire = 3600): bool {
if (!$this->connected) return false;
return @memcache_set($this->connection, $key, $value, $flags, $expire);
}
/**
* 取得快取
* @param string $key
* @param int $flags 參考旗標:回傳時會被設定為實際旗標值
* @return mixed|false
*/
public function get(string $key, int &$flags = 0): mixed {
if (!$this->connected) return false;
return @memcache_get($this->connection, $key, $flags);
}
/**
* 刪除快取
* @param string $key
* @param int $timeout 刪除延遲秒數(舊版參數,通常設 0 或 1)
* @return bool
*/
public function delete(string $key, int $timeout = 0): bool {
if (!$this->connected) return false;
return @memcache_delete($this->connection, $key, $timeout);
}
/**
* 替換現有快取(Key 不存在時失敗)
*/
public function replace(string $key, mixed $value, int $flags = 0, int $expire = 3600): bool {
if (!$this->connected) return false;
return @memcache_replace($this->connection, $key, $value, $flags, $expire);
}
/**
* 原子性增減操作(僅限數值)
*/
public function increment(string $key, int $value = 1): int|false {
if (!$this->connected) return false;
return @memcache_increment($this->connection, $key, $value);
}
public function decrement(string $key, int $value = 1): int|false {
if (!$this->connected) return false;
return @memcache_decrement($this->connection, $key, $value);
}
/**
* 清空所有快取(不釋放記憶體)
*/
public function flush(): bool {
if (!$this->connected) return false;
return @memcache_flush($this->connection);
}
// ==================== 進階功能 ====================
/**
* 設定大值自動壓縮閾值
* @param int $threshold 位元組數,超過此大小自動壓縮
* @param float $minSavings 最小壓縮率(0.2 = 20%)
*/
public function setCompressThreshold(int $threshold, float $minSavings = 0.2): bool {
if (!$this->connected) return false;
return @memcache_set_compress_threshold($this->connection, $threshold, $minSavings);
}
/**
* 取得伺服器狀態
* @return int 0=離線, 1=線上, 2=連線中
*/
public function getServerStatus(string $host, int $port = 11211): int {
if (!$this->connected) return 0;
return @memcache_get_server_status($this->connection, $host, $port);
}
/**
* 取得擴展統計資訊
* @param string $type 統計類型:reset, malloc, maps, cachedump, slabs, items, sizes
* @param int $slabId slab ID(cachedump 時使用)
* @param int $limit 限制筆數
* @return array|false
*/
public function getExtendedStats(string $type = '', int $slabId = 0, int $limit = 100): array|false {
if (!$this->connected) return false;
return @memcache_get_extended_stats($this->connection, $type, $slabId, $limit);
}
/**
* 取得版本資訊
*/
public function getVersion(): string|false {
if (!$this->connected) return false;
return @memcache_get_version($this->connection);
}
}
// ==================== 使用範例 ====================
$mem = new MemcacheManager();
// 單機連線
if ($mem->connect('127.0.0.1', 11211)) {
echo "連線成功\n";
// 設定壓縮閾值:超過 2KB 自動壓縮
$mem->setCompressThreshold(2048, 0.2);
// 基本操作
$mem->set('user:1001', ['name' => 'John', 'email' => 'john@example.com'], 0, 1800);
$mem->set('counter', 100, 0, 3600);
$user = $mem->get('user:1001');
var_dump($user);
// 原子計數器
$mem->increment('counter');
$mem->increment('counter', 5);
echo "Counter: " . $mem->get('counter') . "\n"; // 106
// 叢集支援
$mem->addServer('192.168.1.10', 11211, true, 50); // 權重 50
$mem->addServer('192.168.1.11', 11211, true, 50); // 權重 50
// 監控統計
echo "版本: " . $mem->getVersion() . "\n";
echo "主節點狀態: " . $mem->getServerStatus('127.0.0.1') . "\n";
$stats = $mem->getExtendedStats('slabs');
print_r($stats);
$mem->close();
} else {
echo "連線失敗\n";
}
Memcache vs Memcached 擴展差異
| 特性 | memcache (舊) | memcached (新/推薦) |
| 支援協定 | 純文字協定 | 文字 + 二進制協定 |
| 序列化 | 內建 PHP serialize | 支援 igbinary、json、msgpack |
| 叢集一致性雜湊 | 不支援(客戶端簡單分散) | 支援 Ketama 一致性雜湊 |
| 多鍵操作 | 無 | getMulti, setMulti, deleteMulti |
| 非同步操作 | 無 | 支援 |
| SASL 認證 | 無 | 支援 |
| PHP 版本支援 | PHP 5/7/8 (PECL) | PHP 7/8 核心支援較好 |
生產環境最佳實踐
- Key 命名規範:`module:entity:id`,如 `user:profile:1001`、`product:list:cat_5:page_1`
- 過期時間策略:熱點資料長過期 + 隨機抖動(避免雪崩),冷資料短過期
- 序列化選擇:改用 `memcached` 擴展 + `igbinary` 序列化,效能更好、體積更小
- 監控指標:命中率 (>90%)、記憶體使用率、驅逐率、連線數
- 失效策略:資料更新時主動 `delete`/`replace`,不要只依賴過期
- 大物件處理:>1MB 建議拆分或改用其他儲存,Memcache 單項限制 1MB(可調整但不建議)
- 容錯設計:快取失效不可導致業務失敗,必須有資料庫回退機制
常見問題排查
| 問題 | 可能原因 | 解決 |
| 連線失敗 | 防火牆、Port 未開放、Memcached 未啟動 | telnet host 11211 測試、檢查 security group |
| 資料莫名消失 | 記憶體不足觸發 LRU 驅逐、過期時間太短 | 增加記憶體、調整過期、監控 evictions 指標 |
| PHP Fatal error: Class 'Memcache' not found | 擴展未安裝或未啟用 | pecl install memcache、php.ini 加 extension |
| 叢集資料不均勻 | 舊版 memcache 無一致性雜湊 | 升級 memcached 擴展、啟用 Ketama |
Memcache 仍是輕量快取的經典選擇,但新專案強烈建議使用功能更完整的 memcached 擴展 或 Redis 以獲得更好的叢集支援、資料結構豐富度與維護活躍度。
- 上一篇文章: PHP 多資料庫抽象操作類:支援 MySQL/MSSQL/PostgreSQL 統一介面
- 下一篇文章: PHP PDO 資料庫操作類:模仿 Spring JdbcTemplate 設計的現代化封裝
Copyright ©
程式碼之家 All Rights Reserved