分布式缓存方案之一致性hash

2 篇文章 0 订阅

当服务器数量会发生变化时,普通hash算法就不可用了。因为hash得到值要除以服务器数量取余数来确定数据存放哪一台,如果服务器数量改变了,最终得到的服务器会不同,就无法精确的存取数据了。

而一致性hash就解决了这个问题,它的原理如下:

我们可以想象现在有一个逆时针的环,然后把多台机器的ip都进行hash运算,最终分布在这个环上,如下图所示的server1,server2,server3(按顺序分布):
图1

同时将我们要存储的数据的key也进行hash运算,得出的结果也分布在这个环上,如图中所示的k1~k4。

那么我们就可以把k1和k2的数据存到server2中,k3存到server3中,k4存到server1中。这样我们就找到了数据的归属服务器。

当新增服务器时,假设增加了server5服务器,如下图:
2

那么我们就将k1搬到server5,k2还是在server2中,其他数据维持不变。这就是一致性hash。

减少一台服务器时,原理和增加服务器是一样的

注意,上图中所示的server的hash值在环上是按顺序排列的,这样我们才能根据大小来找到对应关系。

一致性hash代码展示

<?php
/**
 * Created by PhpStorm.
 * User: zhoujun
 * Date: 2017/4/26
 * Time: 20:43
 */

function mhash($key){
    $md5 = substr(md5($key),0,8);
    $seed = 31;
    $hash = 0;

    for($i = 0;$i<strlen($md5);$i++){
        $hash = $hash * $seed + ord($md5[$i]);
    }
    return $hash & 0x7FFFFFFF;
}


class serverHash{

    public $server_list = [];
    public $is_sort = false;

    /**
     * @param $server_ip
     * 新增服务器
     */
    function addServer($server_ip){
        $hash = mhash($server_ip);
        if(!isset($this->server_list[$hash])){
            $this->server_list[$hash] = $server_ip;
            //要查找key所对应的服务器ip时,需先对服务器进行排序,这里先标记它为未排序状态
            $this->is_sort = false;
        }
    }

    /**
     * @param $key
     * 查询这个key所对应的服务器ip
     */
    function lookup($key){
        $hash = mhash($key);
        if($this->is_sort == false){
            krsort($this->server_list,SORT_NUMERIC);
            $this->is_sort = true;
        }
        foreach ($this->server_list as $pos => $ip){
            if($hash >= $pos){
                return $ip;
            }
        }
        return end($this->server_list);
    }
}

$server = new serverHash();
$server->addServer('192.168.3.100');
echo 'k1所在服务器:'.$server->lookup('k1').PHP_EOL;
echo 'k2所在服务器:'.$server->lookup('k2').PHP_EOL;

$server->addServer('192.168.3.101');
echo 'k1所在服务器:'.$server->lookup('k1').PHP_EOL;
echo 'k2所在服务器:'.$server->lookup('k2').PHP_EOL;
echo 'k3所在服务器:'.$server->lookup('k3').PHP_EOL;
echo 'k4所在服务器:'.$server->lookup('k4').PHP_EOL;

$server->addServer('192.168.3.102');
echo 'k5所在服务器:'.$server->lookup('k5').PHP_EOL;
echo 'k6所在服务器:'.$server->lookup('k6').PHP_EOL;

执行 php -f hash.php输出的结果

k1所在服务器:192.168.3.100
k2所在服务器:192.168.3.100
k1所在服务器:192.168.3.101
k2所在服务器:192.168.3.100
k3所在服务器:192.168.3.100
k4所在服务器:192.168.3.101
k5所在服务器:192.168.3.102
k6所在服务器:192.168.3.102
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值