欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PHP實現的一致性Hash算法詳解【分布式算法】

 更新時間:2018年03月31日 15:07:50   作者:雪山飛豬  
這篇文章主要介紹了PHP實現的一致性Hash算法,結合實例形式詳細分析了php一致性Hash算法的概念、原理及相關實現與使用技巧,需要的朋友可以參考下

本文實例講述了PHP實現的一致性Hash算法。分享給大家供大家參考,具體如下:

一致性哈希算法是分布式系統(tǒng)中常用的算法,為什么要用這個算法?

比如:一個分布式存儲系統(tǒng),要將數據存儲到具體的節(jié)點(服務器)上, 在服務器數量不發(fā)生改變的情況下,如果采用普通的hash再對服務器總數量取模的方法(如key%服務器總數量),如果期間有服務器宕機了或者需要增加服務器,問題就出來了。 同一個key經過hash之后,再與服務器總數量取模的結果跟之前的結果會不一樣,這就導致了之前保存數據的丟失。因此,引入了一致性Hash(Consistent Hashing)分布算法

把數據用hash函數(如md5,sha1),映射到一個圓環(huán)上,如上圖所示,數據在存儲時,先根據hash算法算出key的hash值,對應到這個環(huán)中的位置,如k1對應圖中所示的位置同,然后沿著順時針方向找到服務器節(jié)點B,然后把k1在存到B這個節(jié)點中。

如果B節(jié)點宕機了,則B上的數據就會落到C節(jié)點上,如下圖所示

這樣,只會影響C節(jié)點,對于其他節(jié)點A、D的數據不會造成影響。但是問題來了,這樣會造成C節(jié)點負載過重的情況,因為C節(jié)點承擔了B節(jié)點的數據,所以C節(jié)點容易宕機,這樣造成了分布不均勻。

為了解決這個問題,引入了“虛擬節(jié)點“的概念:即想象空上環(huán)上有很多”虛擬節(jié)點“,一個真實的服務器節(jié)點對應多個虛擬節(jié)點,數據存儲的時候沿著環(huán)的順時針方向找到虛擬節(jié)點,就找到了對應的真實服務器節(jié)點。如下圖

圖中的A1、A2、B1、B2、C1、C2、D1、D2都是虛擬節(jié)點,機器A負載存儲A1、A2的數據,機器B負載存儲B1、B2的數據,機器C負載存儲C1、C2的數據。由于這些虛擬節(jié)點數量很多,均勻分布,因此不會造成“雪崩”現象。

一致性哈希算法的PHP實現

下面給出一個接口

/**
 * 一致性哈希實現接口
 * Interface ConsistentHash
 */
interface ConsistentHash
{
 //將字符串轉為hash值
 public function cHash($str);
 //添加一臺服務器到服務器列表中
 public function addServer($server);
 //從服務器刪除一臺服務器
 public function removeServer($server);
 //在當前的服務器列表中找到合適的服務器存放數據
 public function lookup($key);
}

這個接口分別定義了4個方法,cHash(將字符串處理為hash值)、addServer(增加一臺服務器)、removeServer(移除一臺服務器)、lookup(找到一臺服務器來存儲數據)

下面給出一個該接口的具體實現

/**
 * 具體一致性哈希實現
 * author chenqionghe
 * Class MyConsistentHash
 */
class MyConsistentHash implements ConsistentHash
{
 public $serverList = array(); //服務器列列表
 public $virtualPos = array(); //虛擬節(jié)點的位置
 public $virtualPosNum = 5;  //每個節(jié)點對應5個虛節(jié)點
 /**
  * 將字符串轉換成32位無符號整數hash值
  * @param $str
  * @return int
  */
 public function cHash($str)
 {
  $str = md5($str);
  return sprintf('%u', crc32($str));
 }
 /**
  * 在當前的服務器列表中找到合適的服務器存放數據
  * @param $key 鍵名
  * @return mixed 返回服務器IP地址
  */
 public function lookup($key)
 {
  $point = $this->cHash($key);//落點的hash值
  $finalServer = current($this->virtualPos);//先取圓環(huán)上最小的一個節(jié)點當成結果
  foreach($this->virtualPos as $pos=>$server)
  {
   if($point <= $pos)
   {
    $finalServer = $server;
    break;
   }
  }
  reset($this->virtualPos);//重置圓環(huán)的指針為第一個
  return $finalServer;
 }
 /**
  * 添加一臺服務器到服務器列表中
  * @param $server 服務器IP地址
  * @return bool
  */
 public function addServer($server)
 {
  if(!isset($this->serverList[$server]))
  {
   for($i=0; $i<$this->virtualPosNum; $i++)
   {
    $pos = $this->cHash($server . '-' . $i);
    $this->virtualPos[$pos] = $server;
    $this->serverList[$server][] = $pos;
   }
   ksort($this->virtualPos,SORT_NUMERIC);
  }
  return TRUE;
 }
 /**
  * 移除一臺服務器(循環(huán)所有的虛節(jié)點,刪除值為該服務器地址的虛節(jié)點)
  * @param $key
  * @return bool
  */
 public function removeServer($key)
 {
  if(isset($this->serverList[$key]))
  {
   //刪除對應虛節(jié)點
   foreach($this->serverList[$key] as $pos)
   {
    unset($this->virtualPos[$pos]);
   }
   //刪除對應服務器
   unset($this->serverList[$key]);
  }
  return TRUE;
 }
}

然后, 我們來測試一下該算法

$hashServer = new MyConsistentHash();
$hashServer->addServer('192.168.1.1');
$hashServer->addServer('192.168.1.2');
$hashServer->addServer('192.168.1.3');
$hashServer->addServer('192.168.1.4');
$hashServer->addServer('192.168.1.5');
$hashServer->addServer('192.168.1.6');
$hashServer->addServer('192.168.1.7');
$hashServer->addServer('192.168.1.8');
$hashServer->addServer('192.168.1.9');
$hashServer->addServer('192.168.1.10');
echo "增加十臺服務器192.168.1.1~192.168.1.10<br />";
echo "保存 key1 到 server :".$hashServer->lookup('key1') . '<br />';
echo "保存 key2 到 server :".$hashServer->lookup('key2') . '<br />';
echo "保存 key3 到 server :".$hashServer->lookup('key3') . '<br />';
echo "保存 key4 到 server :".$hashServer->lookup('key4') . '<br />';
echo "保存 key5 到 server :".$hashServer->lookup('key5') . '<br />';
echo "保存 key6 到 server :".$hashServer->lookup('key6') . '<br />';
echo "保存 key7 到 server :".$hashServer->lookup('key7') . '<br />';
echo "保存 key8 到 server :".$hashServer->lookup('key8') . '<br />';
echo "保存 key9 到 server :".$hashServer->lookup('key9') . '<br />';
echo "保存 key10 到 server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "移除一臺服務器192.168.1.2<br />";
$hashServer->removeServer('192.168.1.2');
echo "保存 key1 到 server :".$hashServer->lookup('key1') . '<br />';
echo "保存 key2 到 server :".$hashServer->lookup('key2') . '<br />';
echo "保存 key3 到 server :".$hashServer->lookup('key3') . '<br />';
echo "保存 key4 到 server :".$hashServer->lookup('key4') . '<br />';
echo "保存 key5 到 server :".$hashServer->lookup('key5') . '<br />';
echo "保存 key6 到 server :".$hashServer->lookup('key6') . '<br />';
echo "保存 key7 到 server :".$hashServer->lookup('key7') . '<br />';
echo "保存 key8 到 server :".$hashServer->lookup('key8') . '<br />';
echo "保存 key9 到 server :".$hashServer->lookup('key9') . '<br />';
echo "保存 key10 到 server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "移除一臺服務器192.168.1.6<br />";
$hashServer->removeServer('192.168.1.6');
echo "保存 key1 到 server :".$hashServer->lookup('key1') . '<br />';
echo "保存 key2 到 server :".$hashServer->lookup('key2') . '<br />';
echo "保存 key3 到 server :".$hashServer->lookup('key3') . '<br />';
echo "保存 key4 到 server :".$hashServer->lookup('key4') . '<br />';
echo "保存 key5 到 server :".$hashServer->lookup('key5') . '<br />';
echo "保存 key6 到 server :".$hashServer->lookup('key6') . '<br />';
echo "保存 key7 到 server :".$hashServer->lookup('key7') . '<br />';
echo "保存 key8 到 server :".$hashServer->lookup('key8') . '<br />';
echo "保存 key9 到 server :".$hashServer->lookup('key9') . '<br />';
echo "保存 key10 到 server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "移除一臺服務器192.168.1.8<br />";
$hashServer->removeServer('192.168.1.8');
echo "保存 key1 到 server :".$hashServer->lookup('key1') . '<br />';
echo "保存 key2 到 server :".$hashServer->lookup('key2') . '<br />';
echo "保存 key3 到 server :".$hashServer->lookup('key3') . '<br />';
echo "保存 key4 到 server :".$hashServer->lookup('key4') . '<br />';
echo "保存 key5 到 server :".$hashServer->lookup('key5') . '<br />';
echo "保存 key6 到 server :".$hashServer->lookup('key6') . '<br />';
echo "保存 key7 到 server :".$hashServer->lookup('key7') . '<br />';
echo "保存 key8 到 server :".$hashServer->lookup('key8') . '<br />';
echo "保存 key9 到 server :".$hashServer->lookup('key9') . '<br />';
echo "保存 key10 到 server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "移除一臺服務器192.168.1.2<br />";
$hashServer->removeServer('192.168.1.2');
echo "保存 key1 到 server :".$hashServer->lookup('key1') . '<br />';
echo "保存 key2 到 server :".$hashServer->lookup('key2') . '<br />';
echo "保存 key3 到 server :".$hashServer->lookup('key3') . '<br />';
echo "保存 key4 到 server :".$hashServer->lookup('key4') . '<br />';
echo "保存 key5 到 server :".$hashServer->lookup('key5') . '<br />';
echo "保存 key6 到 server :".$hashServer->lookup('key6') . '<br />';
echo "保存 key7 到 server :".$hashServer->lookup('key7') . '<br />';
echo "保存 key8 到 server :".$hashServer->lookup('key8') . '<br />';
echo "保存 key9 到 server :".$hashServer->lookup('key9') . '<br />';
echo "保存 key10 到 server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "增加一臺服務器192.168.1.11<br />";
$hashServer->addServer('192.168.1.11');
echo "保存 key1 到 server :".$hashServer->lookup('key1') . '<br />';
echo "保存 key2 到 server :".$hashServer->lookup('key2') . '<br />';
echo "保存 key3 到 server :".$hashServer->lookup('key3') . '<br />';
echo "保存 key4 到 server :".$hashServer->lookup('key4') . '<br />';
echo "保存 key5 到 server :".$hashServer->lookup('key5') . '<br />';
echo "保存 key6 到 server :".$hashServer->lookup('key6') . '<br />';
echo "保存 key7 到 server :".$hashServer->lookup('key7') . '<br />';
echo "保存 key8 到 server :".$hashServer->lookup('key8') . '<br />';
echo "保存 key9 到 server :".$hashServer->lookup('key9') . '<br />';
echo "保存 key10 到 server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';

運行結果如下

增加十臺服務器192.168.1.1~192.168.1.10
保存 key1 到 server :192.168.1.2
保存 key2 到 server :192.168.1.1
保存 key3 到 server :192.168.1.6
保存 key4 到 server :192.168.1.8
保存 key5 到 server :192.168.1.9
保存 key6 到 server :192.168.1.10
保存 key7 到 server :192.168.1.7
保存 key8 到 server :192.168.1.4
保存 key9 到 server :192.168.1.7
保存 key10 到 server :192.168.1.4
移除一臺服務器192.168.1.2
保存 key1 到 server :192.168.1.7
保存 key2 到 server :192.168.1.1
保存 key3 到 server :192.168.1.6
保存 key4 到 server :192.168.1.8
保存 key5 到 server :192.168.1.9
保存 key6 到 server :192.168.1.10
保存 key7 到 server :192.168.1.7
保存 key8 到 server :192.168.1.4
保存 key9 到 server :192.168.1.7
保存 key10 到 server :192.168.1.4
移除一臺服務器192.168.1.6
保存 key1 到 server :192.168.1.7
保存 key2 到 server :192.168.1.1
保存 key3 到 server :192.168.1.3
保存 key4 到 server :192.168.1.8
保存 key5 到 server :192.168.1.9
保存 key6 到 server :192.168.1.10
保存 key7 到 server :192.168.1.7
保存 key8 到 server :192.168.1.4
保存 key9 到 server :192.168.1.7
保存 key10 到 server :192.168.1.4
移除一臺服務器192.168.1.8
保存 key1 到 server :192.168.1.7
保存 key2 到 server :192.168.1.1
保存 key3 到 server :192.168.1.3
保存 key4 到 server :192.168.1.10
保存 key5 到 server :192.168.1.9
保存 key6 到 server :192.168.1.10
保存 key7 到 server :192.168.1.7
保存 key8 到 server :192.168.1.4
保存 key9 到 server :192.168.1.7
保存 key10 到 server :192.168.1.4
移除一臺服務器192.168.1.2
保存 key1 到 server :192.168.1.7
保存 key2 到 server :192.168.1.1
保存 key3 到 server :192.168.1.3
保存 key4 到 server :192.168.1.10
保存 key5 到 server :192.168.1.9
保存 key6 到 server :192.168.1.10
保存 key7 到 server :192.168.1.7
保存 key8 到 server :192.168.1.4
保存 key9 到 server :192.168.1.7
保存 key10 到 server :192.168.1.4
增加一臺服務器192.168.1.11
保存 key1 到 server :192.168.1.7
保存 key2 到 server :192.168.1.1
保存 key3 到 server :192.168.1.11
保存 key4 到 server :192.168.1.10
保存 key5 到 server :192.168.1.9
保存 key6 到 server :192.168.1.10
保存 key7 到 server :192.168.1.7
保存 key8 到 server :192.168.1.4
保存 key9 到 server :192.168.1.7
保存 key10 到 server :192.168.1.4

可以,看到,使用一致性哈希后,無認是增加服務器還是減少服務器都最大程度的保證了數據的完整性、均勻性.

PS:這里再為大家提供2款hash相關在線工具供大家參考使用:

在線散列/哈希算法加密工具:
http://tools.jb51.net/password/hash_encrypt

在線MD5/hash/SHA-1/SHA-2/SHA-256/SHA-512/SHA-3/RIPEMD-160加密工具:
http://tools.jb51.net/password/hash_md5_sha

更多關于PHP相關內容感興趣的讀者可查看本站專題:《php加密方法總結》、《PHP編碼與轉碼操作技巧匯總》、《PHP數學運算技巧總結》、《PHP數組(Array)操作技巧大全》、《php字符串(string)用法總結》、《PHP數據結構與算法教程》、《php程序設計算法總結》及《php正則表達式用法總結

希望本文所述對大家PHP程序設計有所幫助。

相關文章

  • Laravel 5.3 學習筆記之 安裝

    Laravel 5.3 學習筆記之 安裝

    本文是Laravel 5.3 學習筆記系列文章的第一篇,我們來加單講解下Laravel 5.3 的安裝,有需要的小伙伴可以參考下
    2016-08-08
  • 比較discuz和ecshop的截取字符串函數php版

    比較discuz和ecshop的截取字符串函數php版

    網上看到一篇文章 discuz和ecshop截取字符串的兩個函數,比較了一下兩個版本的函數,都各有局限,只能在特定的前提下使用,但是學習一下有利于拓寬思路,了解PHP的擴展功能
    2012-09-09
  • 分享最受歡迎的5款PHP框架

    分享最受歡迎的5款PHP框架

    這篇文章主要為大家分享最受歡迎的5款PHP框架,需要的朋友可以參考下
    2014-11-11
  • php禁用函數設置及查看方法詳解

    php禁用函數設置及查看方法詳解

    這篇文章主要介紹了php禁用函數設置及查看方法,結合實例形式分析了php禁用函數的方法及使用php探針查看禁用函數信息的相關實現技巧,需要的朋友可以參考下
    2016-07-07
  • PHP環(huán)形鏈表實現方法示例

    PHP環(huán)形鏈表實現方法示例

    這篇文章主要介紹了PHP環(huán)形鏈表實現方法,結合具體實例形式分析了PHP環(huán)形鏈表的定義、創(chuàng)建及遍歷等操作技巧與注意事項,需要的朋友可以參考下
    2017-09-09
  • PHP生成月歷代碼

    PHP生成月歷代碼

    PHP生成月歷代碼...
    2007-06-06
  • php生成mysql的數據字典

    php生成mysql的數據字典

    這篇文章主要為大家詳細介紹了php生成mysql的數據字典的相關資料,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 淺談php常用的7大框架的優(yōu)缺點

    淺談php常用的7大框架的優(yōu)缺點

    這篇文章主要介紹了淺談php常用的7大框架的優(yōu)缺點,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • 安裝apache2.2.22配置php5.4(具體操作步驟)

    安裝apache2.2.22配置php5.4(具體操作步驟)

    本篇文章是對安裝apache2.2.22配置php5.4的具體操作步驟進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • PHP中array_slice函數用法實例詳解

    PHP中array_slice函數用法實例詳解

    這篇文章主要介紹了PHP中array_slice函數用法,以實例形式詳細分析了array_slice函數的具體含義及使用技巧,并以分頁方法為例給出了具體的應用實例,具有一定的參考借鑒價值,需要的朋友可以參考下
    2014-11-11

最新評論