首页 > 编程语言 >Memcache分布式布置方案--一致性Hash分布机制PHP实现

Memcache分布式布置方案--一致性Hash分布机制PHP实现

时间:2024-04-08 15:36:34浏览次数:29  
标签:127.0 hash -- server Memcache hserver 服务器 Hash echo

一致性Hash分布简介
在服务器数量不发生改变时,普通的Hash分布可以很好地运作。当服务器的数量发生改变时,问题就出来了,试想,增加一台服务器时,同一个key经过Hash之后,与服务器取模的结果跟没增加服务器之前的结果会不一样,这就导致之前保存的数据丢失。为了把丢失的数据减少到最少,可以采用一致性hash算法。

一致性hash算法分为6个步骤:

步骤1:

将一个32位整数0~2^32 -1想象成一个环,将0作为圆环的头,2^32 -1作为圆环的尾,把它连接起来。当然这只是想象。
在这里插入图片描述

步骤2:

通过Hash函数把key处理成整数。

function mHash($key){
    $md5 = substr(md5($key),0,8);
    $seed = 31;
    $hash = 0;
   for($i = 0; $i < 8; $i++){
        $hash = $hash*$seed + ord($md5{$i});
        $i++;
    }
    return $hash & 0x7FFFFFFF;

}

$key1 = mHash("key1");
$key2 = mHash("key2");
$key3 = mHash("key3");
$key4 = mHash("key4");

把key处理成整数后,就可以在环中找到一个位置与之对应,如下图

 

步骤3:

把memcached群映射到环上,使用Hash函数处理服务器所使用的IP地址。

假如有3台服务器,分别使用IP(127.0.0.1),IP(127.0.0.2),IP(127.0.0.3),使用下面的方法映射到环上。

$server1 = mHash("127.0.0.1");
$server2 = mHash("127.0.0.2");
$server3 = mHash("127.0.0.3");

步骤4:把数据映射 到服务器上

沿着环顺时针方向的key出发,知道遇到下一个服务器为止,把key对应的数据保存到这个服务器上。根据上面的方法,key4和key3保存到server2上,key2保存到server1上,key1保存到server3上。

 

步骤5:移除服务器

考虑一下,如果server2服务器崩溃了,那么受最大影响的仅是沿着server2逆时针出发直到下一个服务器之间的数据,也就是映射到server2上的那些数据。然后依照规则,将server2服务器上的数据移植下一个服务器上即可。

在上例中,需要进行变动的有key3和key4对应的数据,把这些数据重新映射到server1上即可。

步骤6:添加服务器。

再考虑一下,如果要添加一个服务器server4,用之前的方法把它映射到key3和key4之间,这时受到的影响是沿着server4逆时针出发直至遇到下一个服务器之间的数据,把这些数据重新映射到server4上即可。

在这里仅需要变动的只有key4对应的数据,将其重新映射到server4上即可。

 

使用PHP实现一致性Hash分布算法的代码如下:(注:个人理解所编写,并不权威)

<?php
class FlexiHash
{
    private $serverList = array();//保存服务器列表
    private $isSorted = FALSE;//记录服务器列表是否已经排过序
/*添加服务器*/
function addServer($server){
    $hash = $this->mHash($server);

    if(!isset($this->serverList[$hash])){
        $this->serverList[$hash] = $server;
    }

    $this->isSorted = FALSE;
    return TRUE;
}

/*移除服务器*/
function removeServer($server){

    $hash = $this->mHash($server);

    if(isset($this->serverList[$hash])){
        unset($this->serverList[$hash]);//unset只是销毁了某个变量,并不会重建数组索引
    }

    $this->isSorted = FALSE;
    return TRUE;
}

/*根据值查找所在服务器*/
function lookup($key){
    $hash = $this->mHash($key);
    /*将数组按键由小到大排序*/
    if(!$this->isSorted) {
        ksort($this->serverList);
        $this->isSorted = TRUE;
    }
    /*由于数组是按键由小到大排列的,如果$hash小于等于数组的键,则返回该键的value,即服务器IP*/
    foreach($this->serverList as $pos => $server) { 
        if($hash <= $pos) {
            return $server;
        }
    }
    /*如果上述遍历没有找到合适的值,则返回第一个*/
    return $this->serverList[current(array_keys($this->serverList))];
}

/*hash函数*/
function mHash($key){
    $md5 = substr(md5($key),0,8);
    $seed = 31;
    $hash = 0;

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

}
?>

 


测试代码:

<?php
$hserver = new FlexiHash();

$hserver -> addServer("127.0.0.1");
$hserver -> addServer("127.0.0.2");
$hserver -> addServer("127.0.0.3");
$hserver -> addServer("127.0.0.4");
$hserver -> addServer("127.0.0.5");

echo "save key1 in server: " . $hserver->lookup("key1")."<br>";
echo "save key2 in server: " . $hserver->lookup("key2")."<br>";

echo "=============================="."<br>";

$hserver->removeServer("127.0.0.1");

echo "save key1 in server: " . $hserver->lookup("key1")."<br>";
echo "save key2 in server: " . $hserver->lookup("key2")."<br>";

echo "=============================="."<br>";

$hserver->addServer("127.0.0.1");

echo "save key1 in server: " . $hserver->lookup("key1")."<br>";
echo "save key2 in server: " . $hserver->lookup("key2")."<br>";

echo "=============================="."<br>";
?>

 


运行结果如下:

 

注:关于哈希算法,读者可以自己编写自己的,也可以运用PHP自带函数或方法。

例如:一个比较简单的

echo sprintf('%u',crc32("test"));

一致性hash分布优化
上述方法的缺点如下:

服务器算出的mhash(),并不均匀,就会出现,数据分配不均的现象。
移除一个服务器后,会将此服务器的数据,全部转移至下一个服务器,并不能将其分担给其余服务器。
解决方法:

 

创建若干的虚拟节点,这样,done掉一台服务器的话,数据会近似均匀的分给其他几台服务器。

 

实现方式:

<?php
class FlexiHash
{
    private $serverList = array();//保存服务器虚拟节点
    private $isSorted = FALSE;//记录服务器列表是否已经排过序
    protected $_mul = 64;//每台服务器分成64个虚节点


    /*添加服务器*/
    function addServer($server){
        for($i=0; $i<$this->_mul; $i++) {
            $node = $server.'-'.$i;//给虚节点起名字
            if(!isset($this->serverList[$this->mHash($node)])){
                $this->serverList[$this->mHash($node)] = $server;
            }
        }
        $this->isSorted = FALSE;
        return TRUE;
    }

    /*移除服务器的所有虚拟节点*/
    function removeServer($server){
        foreach($this->serverList as $key=>$value) {
            if($this->serverList[$key] == $server){
                unset($this->serverList[$key]);
            }
        }
        $this->isSorted = FALSE;
        return TRUE;
    }

    /*根据值查找所在服务器*/
    function lookup($key){
        $hash = $this->mHash($key);
        /*将数组按键由小到大排序*/
        if(!$this->isSorted) {
            ksort($this->serverList);
            $this->isSorted = TRUE;
        }
        /*由于数组是按键由小到大排列的,如果$hash小于等于数组的键,则返回该键的value,即服务器IP*/
        foreach($this->serverList as $pos => $server) { 
            if($hash <= $pos) {
                return $server;
            }
        }
        /*如果上述遍历没有找到合适的值,则返回第一个*/
        return $this->serverList[current(array_keys($this->serverList))];
    }

    /*hash函数*/
    function mHash($key){
        $md5 = substr(md5($key),0,8);
        $seed = 31;
        $hash = 0;

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

    function getAllServers(){
        return $this->serverList;
    }

}
?>

 


测试:

<?php
$hserver = new FlexiHash();

$hserver -> addServer("127.0.0.1");
$hserver -> addServer("127.0.0.2");
$hserver -> addServer("127.0.0.3");
$hserver -> addServer("127.0.0.4");
$hserver -> addServer("127.0.0.5");

echo "save key1 in server: " . $hserver->lookup("key1")."<br>";
echo "save key2 in server: " . $hserver->lookup("key2")."<br>";

echo "=============================="."<br>";

$hserver->removeServer("127.0.0.1");

echo "save key1 in server: " . $hserver->lookup("key1")."<br>";
echo "save key2 in server: " . $hserver->lookup("key2")."<br>";

echo "=============================="."<br>";

$hserver->addServer("127.0.0.1");

echo "save key1 in server: " . $hserver->lookup("key1")."<br>";
echo "save key2 in server: " . $hserver->lookup("key2")."<br>";

echo "=============================="."<br>";


//var_dump($hserver->getAllServers());
?>

 


运行结果:

 再看服务器的分布情况:

 

标签:127.0,hash,--,server,Memcache,hserver,服务器,Hash,echo
From: https://www.cnblogs.com/shanhubei/p/18121262

相关文章

  • 面试常问问题——浏览器访问网址发生了什么?
    总体来说分为以下几个过程:DNS解析TCP连接发送HTTP请求服务器处理请求并返回HTTP报文浏览器解析渲染页面连接结束 1.域名解析2.发起TCP的3次握手3.建立TCP连接后,发起http请求4.服务器响应http请求,浏览器得到html代码5、浏览器解析html代码,并请求html代码中的资源(......
  • 有关软件质量一级属性科技论文(4)
    一、软件质量属性软件质量属性,也称软件评估属性,是系统架构设计师必须掌握的核心知识点之一,这些质量属性的具体含义是:(1)性能(Performance)效率指标,是指系统的响应能力,处理任务所需时间或单位时间内的处理量。(2)可靠性(Reliability)是指软件系统在应用或错误面前,在意外或错误使用的......
  • 接口--接口服务
    importjsonfromUSSyunwei.binimport*importrequestsfromUSSapi.bascidataimport*#接口服务defApi_server(port_name,Goal_hierarchy="content",assert_data="",passError=False,**kwargs):"""port_name:接口名称,heade......
  • 有关软件质量一级属性科技论文(5)
    开发高质量的软件是一件极具挑战的工作。其中一个重要的原因就是对于“质量”的定义各不相同,变化莫测。而软件架构的设计主要就是围绕满足功能要求和非功能要求,其中的非功能要求就是软件的各种质量属性。杰拉尔德温伯格在他的四部曲巨作《质量软件管理》的第一卷第一章中就谈到了......
  • 易宝分账状态查询
    fromUSSyunwei.binimport*defyeestatus(order_no):#order_no="W23042211480020"ledger_remark={"完结分账":"十分到家","服务商分账":"服务商","工程师分账":"工程师"}statu_list=[]foriinledger_remark:......
  • SpringBoot拦截器注入stringredistemplate出现Consider defining a bean of type 'org
    问题自定义拦截器需要注入StringRedisTemplate来通过token获取redis中的数据自定义拦截器代码@ComponentpublicclassLoginInterceptorimplementsHandlerInterceptor{@AutowiredprivateStringRedisTemplatestringRedisTemplate;@Overridepublicb......
  • Oracle 在谈 connect by level
     在开发的过程中遇到需要把一行数据显示成N行,当时马上就想到了connectbylevel 这个实在太好用了显示一行selectlevelrnfromdualconnectbylevel<2;显示二行selectlevelrnfromdualconnectbylevel<3; 实例:目前显示一行selectpha.segment1,......
  • 数据库笔记
    数据库1.操作数据库CREATEDATABASEAAA--创建DROPDATABASEAAA--删除USEschool--使用2.创建表CREATETABLEifNOTEXISTS`tb_usear`(`id`INTNOTNULLAUTO_INCREMENTCOMMENT'序号',`age`INT(2)NOTNULLCOMMENT'年龄',`sex`VARCHAR(2)NOT......
  • 鸡乐盒网页版
     前端时间鸡乐盒比较火,当时跟着做了一款鸡乐盒,同时拥有聊天以及音乐播放器功能链接:鸡乐盒https://www.jaron.top/app/xiana/pages/musicBox/musicBox ......
  • MySQL 底层数据结构 聚簇索引以及二级索引 Explain的使用
    数据结构我们知道MySQL的存储引擎Innodb默认底层是使用B+树的变种来存储数据的下面我们来复习一下B树存储+B树存储 +哈希存储的区别哈希存储,只能使用等值查询B树与B+树存储我们知道B+树实际上就是B树的变种那么为啥使用B+树而不是使用B树呢?我们知道效率的高低......