1. 程式人生 > >memcached 取模與雜湊演算法命中率實驗

memcached 取模與雜湊演算法命中率實驗

當5臺memcache伺服器中有一臺宕機時的命中率實驗。

一、php實現程式碼

  1. config.php

    

        $server = array(
		"A" => array("host" => "127.0.0.1", "port" => 11211),
		"B" => array("host" => "127.0.0.1", "port" => 11212),
		"C" => array("host" => "127.0.0.1", "port" => 11213),
		"D" => array("host" => "127.0.0.1", "port" => 11214),
		"E" => array("host" => "127.0.0.1", "port" => 11215),
	);

	$_dis = "Moder";//Consistent    

  2. hash.php 

    

interface hasher {public function _hash($str);}
	interface distribution {public function lookup($key);}

	/**
	* 	取模演算法類
	*/
	class Moder implements hasher,distribution
	{
		
		protected $_nodes = array();
		protected $_cnt = 0;

		public function _hash($str) {
			return sprintf('%u',crc32($str)); // 把字串轉成 32 位符號整數
		}

		public function addNode($node){
			if (in_array($node, $this->_nodes)) {
				return true;
			}
			$this->_nodes[] = $node;
			$this->_cnt += 1;
			return true;
		}

		public function delNode($node) {
			if (!in_array($node, $this->_nodes)) {
				return true;
			}
			$key = array_search($node, $this->_nodes);
			unset($this->_nodes[$key]);
			$this->_cnt -= 1;
			return true;
		}

		public function lookup($key) {
			$key = $this->_hash($key) % $this->_cnt;
			return $this->_nodes[$key];
		}

		public  function printNodes()
		{
			print_r($this->_nodes);
		}
	}

	/*
	$mode = new Moder();
	$mode->addNode('a');
	$mode->addNode('b');
	$mode->addNode('c');

	$key = "sssa";

	$mode->printNodes();

	echo $mode->_hash($key)."<br/>";

	echo $mode->lookup($key);
	*/


	/**
	*	一致性hash演算法類
	*/
	class Consistent implements hasher,distribution{
		protected $_nodes = array(); //伺服器節點
		protected $_postion = array();//虛擬節點
		protected $_mul = 64; //每個節點對應 64 個虛節點
		public function _hash($str) {
			return sprintf('%u',crc32($str)); // 把字串轉成 32 位符號整數
		}
		// 核心功能
		public function lookup($key) {
			$point = $this->_hash($key);
			$node = current($this->_postion); //先取圓環上最小的一個節點,當成結果
			foreach($this->_postion as $k=>$v) {
				if($point <= $k) 
				{
					$node = $v;
					break;
				}
			}
			reset($this->_postion);
			return $node;
		}
		//新增節點
		public function addNode($node) {
			if(isset($this->nodes[$node])) {
				return;
			}
			for($i=0; $i<$this->_mul; $i++) {
				$pos = $this->_hash($node . '-' . $i);
				$this->_postion[$pos] = $node;
				$this->_nodes[$node][] = $pos;
			}
			$this->_sortPos();
		}
		// 迴圈所有的虛節點,誰的值==指定的真實節點 ,就把他刪掉
		public function delNode($node) {
			if(!isset($this->_nodes[$node])) {
				return;
			}
			foreach($this->_nodes[$node] as $k) {
				unset($this->_postion[$k]);
			}
			unset($this->_nodes[$node]);
		}
		//將虛擬節點排序
		protected function _sortPos() {
			ksort($this->_postion,SORT_REGULAR);
		}
	}

	/*
	// 測試
	$con = new Consistent();
	$con->addNode('a');
	$con->addNode('b');
	$con->addNode('c');
	$key = 'www.zixue.it';
	echo '此 key 落在'.$con->lookup($key).'號節點';
	*/

  3.initData.php(初始化資料)

    

        include './config.php';
	include './hash.php';
	set_time_limit(0);
	$mem = new Memcache();
	$diser = new $_dis(); 
	foreach ($server as $key => $value) {
		$diser->addNode($key);
	}
	for ($i=0; $i < 1000; $i++) { 
		//獲取伺服器
		$serv = $server[$diser->lookup("key" . $i)];
		$mem->connect($serv['host'], $serv['port'], 2);
		$mem->add("key".$i, "value".$i, 0, 0);
	}

	echo "full";    

  4.load.php (獲取資料的概率)

    

        include './config.php';
	include './hash.php';
	set_time_limit(0);
	$mem = new Memcache();
	$diser = new $_dis(); 
	foreach ($server as $key => $value) {
		$diser->addNode($key);
	}
	for ($i=0; $i < 1000; $i++) { 
		//獲取伺服器
		$serv = $server[$diser->lookup("key" . $i)];
		$mem->connect($serv['host'], $serv['port'], 2);
		$mem->add("key".$i, "value".$i, 0, 0);
	}

	echo "full";        

  5.exec.php (執行)

    

        //模擬減少一臺伺服器
	include './config.php';
	include './hash.php';

	$mem = new Memcache();
	$diser = new $_dis(); 
	foreach ($server as $key => $value) {
		$diser->addNode($key);
	}

	//刪除一臺伺服器
	$diser->delNode("D");


	for ($i=0; $i < 10000; $i++) { 
		//獲取伺服器
		$serv = $server[$diser->lookup("key" . $i)];
		if ($serv) {
			$mem->connect($serv['host'], $serv['port'], 2);
			if(!$mem->get("key" . $i)){
				$mem->add("key".$i, "value".$i, 0, 0);
			}
		}
		
		usleep(3000);
	}     

二、取模演算法命中率

  如圖:

    1.初始狀態:

        

    2.過程中狀態:

        

   3.結束狀態

      

 

 三、雜湊演算法命中率

   如圖:

    1.初始狀態:

        

    2.過程中:

      

        3.結束狀態:

      

三、總結

  1.取模命中率為20%(1 / N),雜湊命中率為80%左右((N - 1) / N)。

   2.當 memcached 節點越多時,一致性雜湊演算法對快取的命中率比取模演算法對快取的命中率要高很多。