php-memcache)/usr/bin/memcached)php-memcached,基於 libmemcached)本文針對 php-memcache(舊版擴展),新專案建議改用 php-memcached 或 Redis。
# Ubuntu/Debian
sudo apt install memcached
# 配置 /etc/memcached.conf
# -m 1024 # 1GB 記憶體
# -p 11211 # 埠
# -l 127.0.0.1 # 僅本地回環(安全)
# -u memcache # 低權限用戶
sudo systemctl restart memcached
# Ubuntu PHP 8.2
sudo apt install php8.2-memcache
sudo systemctl restart php8.2-fpm
| 方法 | 用途 | 關鍵參數 |
|---|---|---|
connect(host, port) | 短連線 | timeout(秒) |
pconnect(host, port) | 持久連線(跨請求復用) | timeout |
addServer(host, port, ...) | 加入伺服器池(延遲連線) | persistent, weight, timeout, retry_interval, status, failure_callback |
set(key, var, flag, expire) | 儲存(存在則覆蓋) | flag: MEMCACHE_COMPRESSED, expire: 秒/Unix時間戳 |
add(key, var, flag, expire) | 儲存(不存在才寫入) | 同 set |
replace(key, var, flag, expire) | 覆蓋(必須存在) | 同 set |
get(key/keys[]) | 讀取單鍵/多鍵 | 返回值/關聯陣列 |
delete(key, timeout) | 刪除(可延遲) | timeout: 秒後真正刪除 |
increment/decrement(key, value) | 原子增減 | 返回新值 |
flush() | 標記所有項過期(不釋放記憶體) | 無參數 |
getStats() | 統計資訊 | type: slabs, items, sizes... |
getVersion() | 版本號 | 字串 |
close() | 關閉短連線 | 持久連線不受影響 |
setCompressThreshold(size, ratio) | 大值自動壓縮 | 預設 20KB, 0.2 |
<?php
declare(strict_types=1);
class MemcacheManager {
private \Memcache $mc;
private string $prefix = '';
private int $defaultTtl = 3600;
public function __construct(array $servers, string $prefix = '', array $options = []) {
$this->prefix = $prefix;
$this->defaultTtl = $options['default_ttl'] ?? 3600;
$this->mc = new \Memcache();
foreach ($servers as $srv) {
$this->mc->addServer(
$srv['host'],
$srv['port'] ?? 11211,
$srv['persistent'] ?? true,
$srv['weight'] ?? 1,
$srv['timeout'] ?? 1,
$srv['retry_interval'] ?? 15,
$srv['status'] ?? true,
$srv['failure_callback'] ?? null
);
}
// 可選:設定壓縮閾值
if (isset($options['compress_threshold'])) {
$this->mc->setCompressThreshold($options['compress_threshold'][0], $options['compress_threshold'][1] ?? 0.2);
}
}
private function key(string $key): string {
return $this->prefix . $key;
}
public function set(string $key, mixed $value, int $ttl = 0): bool {
return $this->mc->set($this->key($key), $value, 0, $ttl ?: $this->defaultTtl);
}
public function get(string $key, mixed &$flags = null): mixed {
return $this->mc->get($this->key($key), $flags);
}
public function getMulti(array $keys): array {
$prefixed = array_map([$this, 'key'], $keys);
return $this->mc->get($prefixed);
}
public function add(string $key, mixed $value, int $ttl = 0): bool {
return $this->mc->add($this->key($key), $value, 0, $ttl ?: $this->defaultTtl);
}
public function replace(string $key, mixed $value, int $ttl = 0): bool {
return $this->mc->replace($this->key($key), $value, 0, $ttl ?: $this->defaultTtl);
}
public function delete(string $key): bool {
return $this->mc->delete($this->key($key));
}
public function increment(string $key, int $offset = 1): int|false {
return $this->mc->increment($this->key($key), $offset);
}
public function decrement(string $key, int $offset = 1): int|false {
return $this->mc->decrement($this->key($key), $offset);
}
public function flush(): bool {
return $this->mc->flush();
}
public function getStats(): array|false {
return $this->mc->getStats();
}
}
// 使用示例
$mem = new MemcacheManager(
[
['host' => '10.0.1.10', 'weight' => 2],
['host' => '10.0.1.11', 'weight' => 1],
],
'myapp:',
['default_ttl' => 1800, 'compress_threshold' => [50000, 0.3]]
);
$mem->set('user:1001', ['name' => 'John', 'vip' => true], 3600);
$data = $mem->get('user:1001');
$mem->increment('counter:pageview');
$mem->delete('temp:token:xyz');
Memcache 客戶端內建一致性雜湊(addServer 時指定 weight),自動將鍵分散至多節點。進階路由策略:
user:{uid}:profile → 依 uid % N 固定節點,利於批量操作。tag:article:123、tag:user:456 → 同標籤鍵路由至同節點,支援 flush_by_tag(需自建索引)。<?php
function getUserProfile(int $uid, PDO $pdo, MemcacheManager $mc): array {
$key = "user:profile:{$uid}";
if ($data = $mc->get($key)) return $data;
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$uid]);
$data = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
if ($data) $mc->set($key, $data, 3600); // 1 小時
return $data;
}
function updateUserProfile(int $uid, array $fields, PDO $pdo, MemcacheManager $mc): bool {
$set = implode(', ', array_map(fn($k) => "$k = :$k", array_keys($fields)));
$sql = "UPDATE users SET $set WHERE id = :uid";
$fields['uid'] = $uid;
$ok = $pdo->prepare($sql)->execute($fields);
if ($ok) $mc->delete("user:profile:{$uid}"); // 失效緩存
return $ok;
}
注意: 緩存非強一致性,接受「短暫髒讀」。強一致性場景直接查 DB 或用分散式鎖。
| 層級 | 措施 | 實施 |
|---|---|---|
| 網路 | 內網隔離 | Memcached 僅綁定內網 IP (-l 10.0.1.10),安全組/防火牆僅放行應用伺服器 IP |
| 防火牆 | iptables/nftables | iptables -A INPUT -p tcp -s 10.0.1.0/24 --dport 11211 -j ACCEPTiptables -A INPUT -p tcp --dport 11211 -j DROP |
| 認證 | SASL (需 memcached 1.4.3+ + php-memcached) | 啟用 -S 參數,客戶端設定用戶/密碼。php-memcache 不支援 SASL,升級 php-memcached |
| 監控 | 異常存取告警 | Prometheus memcached_exporter + Grafana 儀表板,監控 cmd_get/cmd_set 突增、連線數異常 |
touch、cas、getDelayed),直接替換類名即可遷移 90% 代碼。Memcache 以極簡的 K-V 記憶體存儲、原子增減、多節點一致性雜湊,成為「緩存層」的經典選擇。掌握 addServer 池管理、set/get/increment 核心操作、鍵設計與安全隔離,即可構建高效能緩存體系。新專案優先選擇 php-memcached + Redis 混合架構,發揮各自優勢。