一致性哈希虚节点解决雪崩问题
http://www.cnblogs.com/23lalala/p/3588553.html 引用,收藏学习
一致性哈希的基本原理大家都知道,就是找一个最近的节点或者顺时针,逆时针找一个节点,而不是通过模一个N去找节点,这样做的好处就是当其中一台磬机的时候,一致性哈希还可以继续工作,而模N的方法,所有定位在磬机节点上都会失败。如下代码是一个简单的一致性哈希:
<?php
class Redis {
//redis实例的id
public $id;
public function __construct($id) {
$this->id = $id;
}
public function set($key, $value) {
echo 'redis '.$this->id.': set key '. $key.'</br>';
}
public function ok() {
return true;
}
}
class RedisGlobal {
public $redis = array();
public function addServer($redis) {
$this->redis[md5($redis->id)] = $redis;
}
public function set($key, $value) {
$hash = md5($key);
$serverFind = $hash;
ksort($this->redis, SORT_REGULAR);
foreach ($this->redis as $serverIndex=>$redis) {
if ($serverIndex > $serverFind) {
//找到一个server节点,检测该节点上redis是否可用
if ($redis->ok()) {
$redis->set($key, $value);
break;
}
}
}
}
}
$global = new RedisGlobal();
$global->addServer(new Redis(1));
$global->addServer(new Redis(2));
$global->addServer(new Redis(3));
for ($i=0; $i<10; $i++) {
$global->set($i, $i);
}
?>
//output
redis 3: set key 0
redis 2: set key 1
redis 3: set key 2
redis 1: set key 4
redis 3: set key 5
redis 1: set key 6
redis 1: set key 7
redis 3: set key 8
redis 1: set key 9
以上代码基本OK,不过上面的代码主要有三个问题,也是一致性哈希基本思想存在的问题。面试中也经常考察一个方案的弊端。
1.分布不均匀。
2.当一台磬机以后,磬机节点的所有请求会落到下一台主机,这样就有可能使下一台主机也磬机,这就是雪崩问题。
3.不同主机处理能力不同如何配置量。
解决以上两个问题,是通过配虚节点,也就是一个主机映射N个节点,下面的例子中默认映射100个节点,处理能力较强的主机可以配200或者更高的虚节点数量。
<?php
class Redis {
//redis实例的id
public $id;
public function __construct($id) {
$this->id = $id;
}
public function set($key, $value) {
echo 'redis '.$this->id.': set key '. $key.'</br>';
}
public function ok() {
return true;
}
}
class RedisGlobal {
public $redis = array();
public function addServer($redis, $weight=100) {
for ($i=0; $i<$weight; $i++) {
$this->redis[md5($redis->id.'-'.$i)] = $redis;
}
}
public function set($key, $value) {
$hash = md5($key);
$serverFind = $hash;
ksort($this->redis, SORT_REGULAR);
foreach ($this->redis as $serverIndex=>$redis) {
if ($serverIndex > $serverFind) {
//找到一个server节点,检测该节点上redis是否可用
if ($redis->ok()) {
$redis->set($key, $value);
break;
}
}
}
}
}
$global = new RedisGlobal();
$global->addServer(new Redis(1));
$global->addServer(new Redis(2));
$global->addServer(new Redis(3));
for ($i=0; $i<10; $i++) {
$global->set($i, $i);
}
?>
//output
redis 1: set key 0
redis 1: set key 1
redis 3: set key 2
redis 1: set key 3
redis 2: set key 4
redis 1: set key 5
redis 2: set key 6
redis 2: set key 7
redis 3: set key 8
redis 1: set key 9


浙公网安备 33010602011771号