日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis分布式部署,一致性hash

發布時間:2025/3/14 数据库 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis分布式部署,一致性hash 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一致性哈希

由于hash算法結果一般為unsigned int型,因此對于hash函數的結果應該均勻分布在[0,2^32-1]區間,如果我們把一個圓環用2^32 個點來進行均勻切割,首先按照hash(key)函數算出服務器(節點)的哈希值, 并將其分布到0~2^32的圓環上。
用同樣的hash(key)函數求出需要存儲數據的鍵的哈希值,并映射到圓環上。然后從數據映射到的位置開始順時針查找,將數據保存到找到的第一個服務器(節點)上。如圖所示:

?

key1、key2、key3和server1、server2通過hash都能在這個圓環上找到自己的位置,并且通過順時針的方式來將key定位到 server。按上圖來說,key1和key2存儲到server1,而key3存儲到server2。如果新增一臺server,hash后在key1 和key2之間,則只會影響key1(key1將會存儲在新增的server上),其它則不變。

虛擬節點

在上圖中,很容易看出一個問題,沿順時針方向看,server2到server1之間的區間跨度大,而server1到server2的區間跨度小,這就會導致一個問題:數據分布不均勻。大部分數據都分配到server1了,只有小部分數據分布在server2。在服務器數據很少的時候,數據不均勻會表現的非常明顯。

解決這個問題的方法是使用虛擬節點,一個真實服務器對應多個虛擬節點,所有虛擬節點按hash值分布在一致性哈希圓環上。具體實現方法可以這樣做,為真實服務器設置副本數量,然后根據各真實服務器的IP和端口號再加上一個遞增的索引數計算hash值。

?

class RedisCache {public $servers = array(); //真實服務器private $_servers = array(); //虛擬節點const SERVER_REPLICAS = 10000; //服務器副本數量,提高一致性哈希算法的數據分布均勻程度public function __construct( $servers ){$this->servers = $servers;//Redis虛擬節點哈希表foreach ($this->servers as $k => $server) {for ($i = 0; $i < self::SERVER_REPLICAS; $i++) {$hash = crc32($server['host'] . '#' .$server['port'] . '#'. $i);$this->_servers[$hash] = $k;}}ksort($this->_servers);// something else...} }

  

副本數量可以按真實服務器的數量調節,真實服務器多則副本數量可以設置小一點,真實服務器少則副本數量需要設置多一點。在虛擬節點數量很大的時候,出于性能考慮所以不能使用循環的方法查找key對應的虛擬節點,可以使用二分法快速查找。一個優化的算法是不論副本數量設置為10,100,還是10000的時候,對查找所需要的時間基本是沒有影響的。

故障轉移

使用一次性哈希實現Redis分布式部署了,還需要考慮系統的可用性和穩定性。需要做到,在某一臺或者多臺server故障的時候,程序能夠自動檢測到故障,并將數據重新定位到其它server。

我們可以考慮,根據key查找到的虛擬節點所對應的真實服務器故障的時候,我們在一次性哈希圓環上沿順時針方向順移一步,找到下一點虛擬節點對應的真實服務器,將所要存儲的數據存放上去。但也很有可能下一個虛擬節點所對應的真實服務器與前一個虛擬節點相同,還是那臺故障的服務器,而每次嘗試連接故障的redis服務是一個很大的性能開銷。所以在第一次檢測到故障服務器的時候就需要記錄下來,然后在順移到下一個虛擬節點的時候先判斷是不是之前那一臺故障的服務器,如果是那就不要再嘗試進行連接,直接查找下一個虛擬節點,直到找到可用的服務器將數據存儲上去。

完整示例代碼

class RedisCache {public $servers = array(); //真實服務器private $_servers = array(); //虛擬節點private $_serverKeys = array();private $_badServers = array(); // 故障服務器列表private $_count = 0;const SERVER_REPLICAS = 10000; //服務器副本數量,提高一致性哈希算法的數據分布均勻程度public function __construct( $servers ){$this->servers = $servers;$this->_count = count($this-> servers);//Redis虛擬節點哈希表foreach ($this ->servers as $k => $server) {for ($i = 0; $i < self::SERVER_REPLICAS; $i++) {$hash = crc32($server[ 'host'] . '#' .$server['port'] . '#'. $i);$this->_servers [$hash] = $k;}}ksort( $this->_servers );$this->_serverKeys = array_keys($this-> _servers);}/*** 使用一致性哈希分派服務器,附加故障檢測及轉移功能*/ private function getRedis($key){$hash = crc32($key);$slen = $this->_count * self:: SERVER_REPLICAS;// 快速定位虛擬節點$sid = $hash > $this->_serverKeys [$slen-1] ? 0 : $this->quickSearch($this->_serverKeys, $hash, 0, $slen);$conn = false;$i = 0;do {$n = $this->_servers [$this->_serverKeys[$sid]];!in_array($n, $this->_badServers ) && $conn = $this->getRedisConnect($n);$sid = ($sid + 1) % $slen;} while (!$conn && $i++ < $slen);return $conn ? $conn : new Redis();}/*** 二分法快速查找*/private function quickSearch($stack, $find, $start, $length) {if ($length == 1) {return $start;}else if ($length == 2) {return $find <= $stack[$start] ? $start : ($start +1);}$mid = intval($length / 2);if ($find <= $stack[$start + $mid - 1]) {return $this->quickSearch($stack, $find, $start, $mid);}else {return $this->quickSearch($stack, $find, $start+$mid, $length-$mid);}}private function getRedisConnect($n=0){static $REDIS = array();if (!$REDIS[$n]){$REDIS[$n] = new Redis();try{$ret = $REDIS[$n]->pconnect( $this->servers [$n]['host'], $this->servers [$n]['port']);if (!$ret) {unset($REDIS[$n]);$this->_badServers [] = $n;return false;}} catch(Exception $e){unset($REDIS[$n]);$this->_badServers [] = $n;return false;}}return $REDIS[$n];}public function getValue($key){try{$getValue = $this->getRedis($key)->get($key);} catch(Exception $e){$getValue = null;}return $getValue;}public function setValue($key,$value,$expire){if($expire == 0){try{$ret = $this->getRedis($key)->set($key, $value);} catch(Exception $e){$ret = false;}} else{try{$ret = $this->getRedis($key)->setex($key, $expire, $value);} catch(Exception $e){$ret = false;}}return $ret;}public function deleteValue($key){return $this->getRedis($key)->delete($key);}public function flushValues(){//TODOreturn true;} }// Usage: $redis_servers = array(array('host' => '10.0.0.1','port' => 6379,),array('host' => '10.0.0.2','port' => 6379,),array('host' => '10.0.0.3','port' => 6379,),array('host' => '10.0.0.3','port' => 6928,), );$redisCache = new RedisCache($redis_servers); $testKey = 'test_key'; $testValue = 'test_value_object'; $redisCache->setValue($testKey, $testValue, 3600); $value = $redisCache->getValue($testKey);

  

轉載于:https://www.cnblogs.com/gpfeisoft/p/5939473.html

總結

以上是生活随笔為你收集整理的Redis分布式部署,一致性hash的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。