首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP Memcache 操作類完整封裝:連線管理、快取操作、叢集支援與統計監控

     編輯:PHP 綜合知識

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(可調整但不建議)
  • 容錯設計:快取失效不可導致業務失敗,必須有資料庫回退機制

常見問題排查

Memcache 仍是輕量快取的經典選擇,但新專案強烈建議使用功能更完整的 memcached 擴展 或 Redis 以獲得更好的叢集支援、資料結構豐富度與維護活躍度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題可能原因解決
連線失敗防火牆、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