本文展示一個完整的 PHP 應用架構:Memcached 叢集(多實例模擬多台)搭配 MySQL 主從複寫(寫入 Master、讀取 Slave),並透過一致性雜湊(以鍵名前綴分叢集)分配快取節點。程式碼包含連線管理、查詢分離、快取策略與設定檔範例。
class Memcached {
private $mem;
public $pflag = ''; // 是否使用持久連線
private function memConnect($serkey) {
require 'config.php';
$server = $memcached;
$this->mem = new Memcache;
$link = !$this->pflag ? 'connect' : 'pconnect';
$this->mem->$link($server[$serkey][0], $server[$serkey][1]) or $this->errordie('memcached connect error');
}
public function set($ser_key, $values, $flag = '', $expire = '') {
$this->memConnect($this->tag($ser_key));
return $this->mem->set($ser_key, $values, $flag, $expire);
}
public function get($ser_key) {
$this->memConnect($this->tag($ser_key));
return $this->mem->get($ser_key) ?: false;
}
// 依鍵名前綴決定叢集(如 cn_xxx → cn 叢集)
private function tag($ser_key) {
return explode('_', $ser_key)[0];
}
private function errordie($errmsg) { die($errmsg); }
}
class Mysql {
private $mysqlmaster;
private $mysqlslave;
private static $auid = 0;
public function __construct() {
require 'config.php';
$msg = $mysql;
$this->mysqlmaster = new mysqli($msg['master'][0], $msg['master'][1], $msg['master'][2], $msg['master'][3]);
$this->mysqlslave = $this->autotranscat($msg); // 輪詢 Slave
if(mysqli_connect_errno()) exit("Connect failed: " . mysqli_connect_error());
$this->mysqlmaster->set_charset("latin1");
$this->mysqlslave->set_charset("latin1");
}
// Session 輪詢選擇 Slave
private function autotranscat($mysql) {
session_start();
$_SESSION['SID'] = ($_SESSION['SID'] ?? 0) + 1;
if($_SESSION['SID'] >= count($mysql)) $_SESSION['SID'] = 1;
$key = 'slave_' . $_SESSION['SID'];
return new mysqli($mysql[$key][0], $mysql[$key][1], $mysql[$key][2], $mysql[$key][3]);
}
public function mquery($sql) { return $this->mysqlmaster->query($sql); } // 寫入
public function squery($sql) { return $this->mysqlslave->query($sql); } // 讀取
public function fetArray($sql) {
if($result = $this->squery($sql)) {
while($row = $result->fetch_array(MYSQLI_ASSOC)) $resultraa[] = $row;
return $resultraa;
}
return false;
}
}
array('192.168.254.144', 11211),
'en' => array('192.168.254.144', 11212)
);
$mysql = array(
'master' => array('192.168.254.213', 'root', '1', 'mydz'),
'slave_1' => array('192.168.254.144', 'root', '1', 'mydz')
);
?>
require 'init.php';
$mem = new Memcached;
$sq = new Mysql;
$sql = "insert into mybb(pid) values(200)";
$mdsql = md5($sql); // SQL 雜湊作為快取鍵一部分
// 快取未命中 → 寫入 Master → 從 Slave 讀取最新資料 → 存入快取
if(!$result = $mem->get('cn_' . $mdsql)) {
$sq->mquery($sql); // 寫入主庫
$result = $sq->fetArray("select * from mybb"); // 從從庫讀取
foreach($result as $var) echo $var['pid'];
$mem->set('cn_' . $mdsql, $result); // 存入 cn 叢集
} else {
foreach($result as $var) echo $var['pid']; // 快取命中直接輸出
}
settings_init → 解析參數 → daemon() 建立守護進程 → 初始化 slab/hash/event → 進入 drive_machine 事件循環\r\n,支援 get/set/add/replace/incr/decr/stats 等指令Memcached::addServer 建立連線池,而非單一連線