php简单一致性hash,PHP一致性hash代码

c90cadccf06ff6fb04b20ae3486314e8.png

PHP实现一致性hash

bash命令

因为下面PHP代码的模拟用户用的是随机数,所以统计结果达不到绝对的均衡.

php ./hash.php | sort | uniq -c | sort

PHP代码

这是之前学的时候留下来的测试代码,原理方面就不赘述了.

/**

* @class ConsistentHash

* @desc 无符号的一致性hash

* @author liuhao

*/

class ConsistentHash

{

protected $nodeList = []; //服务器列表

protected $virtualNodeSite = []; //虚拟节点的位置

protected $virtualNodeCount = 20; //每个节点对应20个虚节点

/**

* @desc 在服务器列表中, 为用户匹配合适的服务器

* @action getNodeAction

* @param string $key 键名

* @return string 服务器IP地址

* @author liuhao

*/

public function getNode($key)

{

//获取当前下标的hash值

$keyHash = $this->crc32Hash($key);

//先把hash环上上最小的一个节点临时当作是我们需要的节点

$resultHost = current($this->virtualNodeSite);

foreach ($this->virtualNodeSite as $nodeHash => $host) {

if ($keyHash <= $nodeHash) {

$resultHost = $host;

break;

}

}

//重置圆环的指针为第一个

reset($this->virtualNodeSite);

return $resultHost;

}

/**

* @desc 将字符串转换成32位无符号整数hash值

* @action crc32HashAction

* @param string $str

* @return string

* @author liuhao

*/

protected function crc32Hash($str)

{

//由于 PHP 的整数是带符号的,所以在 32 位系统上许多 crc32 校验码将返回负整数。 尽管在 64 位上所有 crc32() 的结果将都是正整数。

//因此你需要使用 sprintf() 或 printf() 的“%u”格式符来获取表示无符号 crc32 校验码的字符串。

$str = crc32(md5($str));

return sprintf("%u", $str);

}

/**

* @desc 向服务器列表,添加一个新的服务器

* @action addNodeAction

* @param string $host 服务器IP地址

* @return bool

* @author liuhao

*/

public function addNode($host)

{

if (!isset($this->nodeList[$host])) {

for ($i = 0; $i < $this->virtualNodeCount; $i++) {

$hostHash = $this->crc32Hash($host."-".$i);

$this->virtualNodeSite[$hostHash] = $host;

$this->nodeList[$host][] = $hostHash;

}

ksort($this->virtualNodeSite, SORT_NUMERIC);

}

return true;

}

/**

* @desc 循环所有的虚节点,删除值为该服务器地址的虚节点

* @action delNodeAction

* @param string $host

* @return bool

* @author liuhao

*/

public function delNode($host)

{

if (isset($this->nodeList[$host])) {

//删除对应虚节点

foreach ($this->nodeList[$host] as $pos) {

unset($this->virtualNodeSite[$pos]);

}

//删除对应服务器

unset($this->nodeList[$host]);

}

return true;

}

}

//节点服务器列表

$ipArr = [

"192.168.1.100",

"192.168.1.102",

"192.168.1.103",

"192.168.1.104",

"192.168.1.105",

"192.168.1.106",

"192.168.1.107",

"192.168.1.108",

"192.168.1.109",

"192.168.1.110",

"192.168.1.111",

"192.168.1.112",

"192.168.1.113",

"192.168.1.114",

"192.168.1.115",

"192.168.1.116",

"192.168.1.117",

"192.168.1.118",

"192.168.1.119",

"192.168.1.120",

];

$hashServer = new ConsistentHash();

//添加节点

foreach ($ipArr as $key => $value) {

$hashServer->addNode($value);

// echo "节点服务器{$key}: ======> {$value}".PHP_EOL;

}

echo PHP_EOL;

//模拟访问函数

$fakeVisit = function () use (&$hashServer) {

//用户访问总次数

$visitsTotal = 100;

for ($i = 0; $i < $visitsTotal; $i++) {

//假定5个用户随机访问

$rand = mt_rand(0, 5);

echo "用户{$rand} 连接的节点是: ".$hashServer->getNode($rand).PHP_EOL;

}

};

//模拟访问

$fakeVisit();

exit;

//随机删除一台服务器

$randIPFunc = function () use ($ipArr) {

return $ip = $ipArr[array_rand($ipArr, 1)];

};

echo PHP_EOL;

$randIP = $randIPFunc();

echo "用户删除的节点服务器是:{$randIP}".PHP_EOL;

echo PHP_EOL;

$hashServer->delNode($randIP);

//模拟访问

$fakeVisit();

echo PHP_EOL;

$randIP = $randIPFunc();

echo "用户删除的节点服务器是:{$randIP}".PHP_EOL;

echo PHP_EOL;

$hashServer->delNode($randIP);

//模拟访问

$fakeVisit();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值