通俗理解一致性哈希
把各服务器节点映射放在钟表的各个时刻上, 把 key 也映射到钟表的某个时刻上. 该 key 沿钟表顺时针走,碰到的第 1 个节点即为该 key 的存储节点

疑问 1: 时钟上的指针最大才 11 点,如果我有上百个 memcached 节点怎么办?
答: 时钟只是为了便于理解做的比喻,在实际应用中,我们可以在圆环上分布[0,2^32-1]的数字, 这样,全世界的服务器都可以装下了.
疑问 2: 我该如何把”节点名”,”键名”转化成整数?
答: 你可以用现在的函数,如 crc32(),也可以自己去设计转化规则,但注意转化后的碰撞率要低. 即不同的节点名,转换为相同的整数的概率要低. 一致性哈希对其他节点的影响通过图可以看出,当某个节点 down 后,只影响该节点顺时针之后的 1 个节点,而其他节点 不受影响.因此,Consistent Hashing 最大限度地抑制了键的重新分布

一致性哈希+虚拟节点对缓存命中率的影响
由图中可以看到,理想状态下, 1) 节点在圆环上分配分配均匀,因此承担的任务也平均,但事实上, 一般的 Hash 函数对于节 点在圆环上的映射,并不均匀. 2) 当某个节点 down 后,直接冲击下 1 个节点,对下 1 个节点冲击过大,能否把 down 节点上的 压力平均的分担到所有节点上? 完全可以—引入虚拟节点来达到目标 虚拟节点即----N 个真实节点,把每个真实节点映射成 M 个虚拟节点, 再把 M*N 个虚拟节点, 散列在圆环上. 各真实节点对应的虚拟节点相互交错分布 这样,某真实节点 down 后,则把其影响平均分担到其他所有节点上

<?php
/**
* 一致性哈希
*
* @author jinpeng
* @date 2022/10/26
*/
class Content{
protected $_node = [];
protected $_position = [];
protected $_mul = 64; //散列成64个虚拟节点
// 查找key所处的位置
public function find($key)
{
$point = $this->_hash($key);
echo "<br/>";
echo 'key节点位置:'. $point;
echo "<br/>";
$node = current($this->_position);
foreach ($this->_position as $key => $item)
{
if ($point <= $key)
{
$node = $item;
break;
}
}
return $node;
}
// 排序节点
protected function _sortNode()
{
ksort($this->_position, SORT_REGULAR);
}
// 新增节点
public function addNode($node)
{
// 分布散列点
for ($i =1; $i < $this->_mul; $i ++)
{
$posName = $node . '_' . $i;
$this->_position[$this->_hash($posName)] = $node;
}
$this->_sortNode();
}
// 删除节点
public function delNode($node)
{
foreach ($this->_position as $key => $item)
{
if ($node == $item)
{
unset($this->_position[$key]);
}
}
}
protected function _hash($str)
{
return sprintf("%u", crc32($str)); // 无符号的 0-2^32
}
// 测试方法
public function getPosition()
{
echo "<pre>";
print_r($this->_position);
}
}
$con = new Content();
$con->addNode('a');
$con->addNode('b');
$con->addNode('c');
$con->getPosition();
echo '获取到环上节点:'. $con->find('name');