搜尋
首頁後端開發php教程PHP實作一致性Hash演算法步驟詳解

這次帶給大家PHP實作一致性Hash演算法步驟詳解,PHP實作一致性Hash演算法的注意事項有哪些,以下就是實戰案例,一起來看一下。

一致性雜湊演算法是分散式系統中常用的算法,為什麼要用這個演算法?

例如:一個分散式儲存系統,要將資料儲存到具體的節點(伺服器)上, 在伺服器數量不改變的情況下,如果採用普通的hash再對伺服器總數量取模的方法(如key%伺服器總數量),如果期間有伺服器宕機了或需要增加伺服器,問題就出來了。同一個key經過hash之後,再與伺服器總數量取模的結果跟之前的結果會不一樣,這就導致了先前保存資料的遺失。因此,引入了一致性Hash(Consistent Hashing)分佈演算法

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

如果B節點宕機了,則B上的資料就會落到C節點上,如下圖所示

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

為了解決這個問題,引入了「虛擬節點「的概念:即想像空上環上有很多」虛擬節點“,一個真實的伺服器節點對應多個虛擬節點,資料儲存的時候沿著環的順時針方向找到虛擬節點,就找到了對應的真實伺服器節點。如下圖

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

一致性雜湊演算法的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(); //虚拟节点的位置
 public $virtualPosNum = 5;  //每个节点对应5个虚节点
 /**
  * 将字符串转换成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);//先取圆环上最小的一个节点当成结果
  foreach($this->virtualPos as $pos=>$server)
  {
   if($point virtualPos);//重置圆环的指针为第一个
  return $finalServer;
 }
 /**
  * 添加一台服务器到服务器列表中
  * @param $server 服务器IP地址
  * @return bool
  */
 public function addServer($server)
 {
  if(!isset($this->serverList[$server]))
  {
   for($i=0; $ivirtualPosNum; $i++)
   {
    $pos = $this->cHash($server . '-' . $i);
    $this->virtualPos[$pos] = $server;
    $this->serverList[$server][] = $pos;
   }
   ksort($this->virtualPos,SORT_NUMERIC);
  }
  return TRUE;
 }
 /**
  * 移除一台服务器(循环所有的虚节点,删除值为该服务器地址的虚节点)
  * @param $key
  * @return bool
  */
 public function removeServer($key)
 {
  if(isset($this->serverList[$key]))
  {
   //删除对应虚节点
   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 :191668.192662.
儲存key4 到server :192.168.1.8
儲存key5 到server :192.168.1.9
儲存key6 到server :192.168.1.10
已經儲存到#key7 到server :192.168.1.7 儲存到被儲存到#key server :192.168.1.4
儲存key9 到server :192.168.1.7
儲存key10 到server :192.168.1.4
移除一台伺服器192.168.1.2
儲存key1 到server :1922168.192#key1 到server17. ##儲存key3 到server :192.168.1.1
儲存key3 到server :192.168.1.6
儲存key4 到server :192.168.1.8
儲存key5 到server :192.168.169.1.8
儲存key5 到server :192.168.11.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.7
##192.server 儲存:1186:


186:186:##21. #移除一台伺服器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 :1server :192.168.1.7
存檔儲存key9 到server :192.168.1.7
儲存key10 到server :192.168.1.4
移除一台伺服器192.168.1.8
儲存key1 到server :192.168.1.7
key2 到儲存key1 到server :192.168.1.7
key12 到server:68 .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. key7 到server :192.168.1.7
儲存key8 到server :192.168.1.4
儲存key9 到server :192.168.1.7
儲存key10 到server :192.168.168.1.7
儲存key10 到server :192.168.1.4#1686868.1.4#16868.1.4#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.168.1.3
儲存key4 到server :192.168.1.101151511592.168.1.到server :192.168.1.9
保存key6 到server :192.168.1.10
保存key7 到server :192.168.1.7
保存key8 到server :192.168.1.4
key9 到儲存key8 到server :192.168.1.4
19 到儲存key8 到server :192.168.1.4
19 到儲存key8
儲存key10 到server :192.168.1.4
增加一台伺服器192.168.1.11
儲存key1 到server :192.168.1.7
儲存key2 到server :192.168.1.1
key3 儲存到:192.168.1.11
儲存key4 到server :192.168.1.10
儲存key5 到server :192.168.1.9
儲存key6 到server :192.168.1.10
key17 到 168.192.168.1.10

key17 到#1812112168.110
17.1-16811212168.110

17.server1681211212119.1212121.10

17.1-1681121212119.10

17.1-1681121212121.10

17。 #儲存key8 到server :192.168.1.4

儲存key9 到server :192.168.1.7

儲存key10 到server :192.168.1.4

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

相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章! 推薦閱讀:

######thinkPHP框架自動填入原理與用法使用詳解############PHP裝飾器模式使用詳解###### #

以上是PHP實作一致性Hash演算法步驟詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

php如何实现Redis的Hash操作php如何实现Redis的Hash操作May 30, 2023 am 08:58 AM

Hash操作//为hash表中的字段赋值。成功返回1,失败返回0。若hash表不存在会先创建表再赋值,若字段已存在会覆盖旧值。$ret=$redis->hSet(&#39;user&#39;,&#39;realname&#39;,&#39;jetwu&#39;);//获取hash表中指定字段的值。若hash表不存在则返回false。$ret=$redis->hGet(&#39;user&#39;,&#39;rea

php怎么除以100保留两位小数php怎么除以100保留两位小数Apr 22, 2022 pm 06:23 PM

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php怎么根据年月日判断是一年的第几天php怎么根据年月日判断是一年的第几天Apr 22, 2022 pm 05:02 PM

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php怎么判断有没有小数点php怎么判断有没有小数点Apr 20, 2022 pm 08:12 PM

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

php怎么设置implode没有分隔符php怎么设置implode没有分隔符Apr 18, 2022 pm 05:39 PM

在PHP中,可以利用implode()函数的第一个参数来设置没有分隔符,该函数的第一个参数用于规定数组元素之间放置的内容,默认是空字符串,也可将第一个参数设置为空,语法为“implode(数组)”或者“implode("",数组)”。

php怎么查找字符串是第几位php怎么查找字符串是第几位Apr 22, 2022 pm 06:48 PM

查找方法:1、用strpos(),语法“strpos("字符串值","查找子串")+1”;2、用stripos(),语法“strpos("字符串值","查找子串")+1”。因为字符串是从0开始计数的,因此两个函数获取的位置需要进行加1处理。

Laravel开发:如何使用Laravel Hash生成密码散列?Laravel开发:如何使用Laravel Hash生成密码散列?Jun 17, 2023 am 10:59 AM

Laravel是目前最为流行的PHPweb框架之一,为开发人员提供了许多强大的功能和组件,其中LaravelHash也是其中之一。LaravelHash是一个用于密码散列的PHP库,其可以用于保护密码的安全,并使应用程序的用户数据更加安全。在本文中,我们将了解LaravelHash的工作原理以及如何使用它来对密码进行散列和验证。前置知识在学习Lara

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境