Memcached::getMulti() 預設返回關聯陣列,順序不保證(取決於內部哈希分佈)。多節點時,返回順序與請求鍵順序不一致,導致業務邏輯難以對應。
<?php
$md = new Memcached();
$md->addServers([['10.0.0.1', 11211], ['10.0.0.2', 11211]]);
// 啟用一致性哈希(前提)
$md->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$md->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$keys = [
'line_31639', 'line_33878', 'line_177410', 'line_9735', 'line_589',
'line_12076', 'line_25953', 'line_22447', 'line_15368', 'line_15358',
'line_33853', 'line_26658', 'line_26659', 'line_12477', 'line_15366'
];
// 關鍵:第三參數傳入常量
$cas = null;
$results = $md->getMulti($keys, $cas, Memcached::GET_PRESERVE_ORDER);
// $results 陣列順序與 $keys 完全一致
// 未命中鍵值為 false,$cas 陣列同序對應 CAS token
foreach ($keys as $i => $key) {
if ($results[$i] === false) {
echo "Miss: $key\n";
} else {
echo "Hit: $key = {$results[$i]}\n";
}
}
?>
<?php
// 找出未命中鍵
$missedKeys = [];
foreach ($keys as $i => $key) {
if ($results[$i] === false) $missedKeys[] = $key;
}
if ($missedKeys) {
// 從資料庫/上游獲取
$fetched = fetchFromDb($missedKeys); // 返回關聯陣列 [key=>val]
// 回填 Memcached
$md->setMulti($fetched, 3600);
// 合併結果
foreach ($missedKeys as $key) {
$idx = array_search($key, $keys);
$results[$idx] = $fetched[$key];
}
}
// 現在 $results 完整且順序正確
processResults($results);
?>
GET_PRESERVE_ORDER 內部實現:客戶端按鍵順序發送請求、接收響應,而非並行管線化。略微增加延遲(串行 vs 並行),但保證順序。$cas 參數同序返回各鍵 CAS token,配合 cas() 實現批量樂觀鎖更新。順序保證犧牲部分並行度。若鍵數量大(>100),考慮分批並行獲取,或接受無序並在應用層排序(array_replace、array_intersect_key)。